Merge mozilla-central to mozilla-inbound
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="fadfafa17f5175203b8b9457bfb95e5816f54f58"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="449d632c69b1a4bd5101d07d18f76799d3fd5f38"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="fadfafa17f5175203b8b9457bfb95e5816f54f58"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="449d632c69b1a4bd5101d07d18f76799d3fd5f38"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="999e945b85c578c503ad445c2285940f16aacdae">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="fadfafa17f5175203b8b9457bfb95e5816f54f58"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="449d632c69b1a4bd5101d07d18f76799d3fd5f38"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="fadfafa17f5175203b8b9457bfb95e5816f54f58"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="449d632c69b1a4bd5101d07d18f76799d3fd5f38"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="fadfafa17f5175203b8b9457bfb95e5816f54f58"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="449d632c69b1a4bd5101d07d18f76799d3fd5f38"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "9863517bfb599a39300f5e8c6f94e16189a4c698",
|
||||
"revision": "d7d92199ea7e8f850ca0c6f0514bf596f178a16f",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="fadfafa17f5175203b8b9457bfb95e5816f54f58"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="449d632c69b1a4bd5101d07d18f76799d3fd5f38"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="fadfafa17f5175203b8b9457bfb95e5816f54f58"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="449d632c69b1a4bd5101d07d18f76799d3fd5f38"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="fadfafa17f5175203b8b9457bfb95e5816f54f58"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="449d632c69b1a4bd5101d07d18f76799d3fd5f38"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="fadfafa17f5175203b8b9457bfb95e5816f54f58"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="449d632c69b1a4bd5101d07d18f76799d3fd5f38"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -1291,6 +1291,7 @@ pref("devtools.toolbox.selectedTool", "webconsole");
|
||||
pref("devtools.toolbox.toolbarSpec", '["splitconsole", "paintflashing toggle","tilt toggle","scratchpad","resize toggle","eyedropper","screenshot --fullpage"]');
|
||||
pref("devtools.toolbox.sideEnabled", true);
|
||||
pref("devtools.toolbox.zoomValue", "1");
|
||||
pref("devtools.toolbox.splitconsoleEnabled", false);
|
||||
|
||||
// Toolbox Button preferences
|
||||
pref("devtools.command-button-pick.enabled", true);
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
var gStateObject;
|
||||
var gTreeData;
|
||||
@ -20,19 +19,7 @@ window.onload = function() {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove unneeded braces (added for compatibility with Firefox 2.0 and 3.0)
|
||||
if (sessionData.value.charAt(0) == '(')
|
||||
sessionData.value = sessionData.value.slice(1, -1);
|
||||
try {
|
||||
gStateObject = JSON.parse(sessionData.value);
|
||||
}
|
||||
catch (exJSON) {
|
||||
var s = new Cu.Sandbox("about:blank", {sandboxName: 'aboutSessionRestore'});
|
||||
gStateObject = Cu.evalInSandbox("(" + sessionData.value + ")", s);
|
||||
// If we couldn't parse the string with JSON.parse originally, make sure
|
||||
// that the value in the textbox will be parsable.
|
||||
sessionData.value = JSON.stringify(gStateObject);
|
||||
}
|
||||
gStateObject = JSON.parse(sessionData.value);
|
||||
|
||||
// make sure the data is tracked to be restored in case of a subsequent crash
|
||||
var event = document.createEvent("UIEvents");
|
||||
|
@ -134,7 +134,6 @@ skip-if = true
|
||||
[browser_528776.js]
|
||||
[browser_579868.js]
|
||||
[browser_579879.js]
|
||||
[browser_581593.js]
|
||||
[browser_581937.js]
|
||||
[browser_586147.js]
|
||||
[browser_586068-apptabs.js]
|
||||
|
@ -1,46 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
let stateBackup = ss.getBrowserState();
|
||||
|
||||
function test() {
|
||||
/** Test for bug 581593 **/
|
||||
waitForExplicitFinish();
|
||||
ignoreAllUncaughtExceptions();
|
||||
|
||||
let oldState = { windows: [{ tabs: [{ entries: [{ url: "example.com" }] }] }]};
|
||||
let pageData = {
|
||||
url: "about:sessionrestore",
|
||||
formdata: { id: { "sessionData": "(" + JSON.stringify(oldState) + ")" } }
|
||||
};
|
||||
let state = { windows: [{ tabs: [{ entries: [pageData] }] }] };
|
||||
|
||||
// The form data will be restored before SSTabRestored, so we want to listen
|
||||
// for that on the currently selected tab (it will be reused)
|
||||
gBrowser.selectedTab.addEventListener("SSTabRestored", onSSTabRestored, true);
|
||||
|
||||
ss.setBrowserState(JSON.stringify(state));
|
||||
}
|
||||
|
||||
function onSSTabRestored(aEvent) {
|
||||
info("SSTabRestored event");
|
||||
gBrowser.selectedTab.removeEventListener("SSTabRestored", onSSTabRestored, true);
|
||||
|
||||
// This is an ok way to check this because we will make sure that the text
|
||||
// field is parsable.
|
||||
let val = gBrowser.selectedBrowser.contentDocument.getElementById("sessionData").value;
|
||||
try {
|
||||
JSON.parse(val);
|
||||
ok(true, "JSON.parse succeeded");
|
||||
}
|
||||
catch (e) {
|
||||
ok(false, "JSON.parse failed");
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
ss.setBrowserState(stateBackup);
|
||||
executeSoon(finish);
|
||||
}
|
@ -33,6 +33,7 @@ function* runTests() {
|
||||
let result = toolbox.once("webconsole-ready", () => {
|
||||
ok(toolbox.splitConsole, "Split console is shown.");
|
||||
is(dbgWin.gThreadClient.state, "paused", "Execution is still paused.");
|
||||
Services.prefs.clearUserPref("devtools.toolbox.splitconsoleEnabled");
|
||||
});
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {}, dbgWin);
|
||||
yield result;
|
||||
|
@ -281,22 +281,12 @@ DevTools.prototype = {
|
||||
this.emit("toolbox-destroyed", target);
|
||||
});
|
||||
|
||||
// If we were asked for a specific tool then we need to wait for the
|
||||
// tool to be ready and selected, otherwise we can just wait for the
|
||||
// toolbox open promise.
|
||||
if (toolId != null) {
|
||||
toolbox.once(toolId + "-selected", (event, panel) => {
|
||||
this.emit("toolbox-ready", toolbox);
|
||||
deferred.resolve(toolbox);
|
||||
});
|
||||
toolbox.open();
|
||||
}
|
||||
else {
|
||||
toolbox.open().then(() => {
|
||||
deferred.resolve(toolbox);
|
||||
this.emit("toolbox-ready", toolbox);
|
||||
});
|
||||
}
|
||||
// If toolId was passed in, it will already be selected before the
|
||||
// open promise resolves.
|
||||
toolbox.open().then(() => {
|
||||
deferred.resolve(toolbox);
|
||||
this.emit("toolbox-ready", toolbox);
|
||||
});
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
const MAX_ORDINAL = 99;
|
||||
const ZOOM_PREF = "devtools.toolbox.zoomValue";
|
||||
const SPLITCONSOLE_ENABLED_PREF = "devtools.toolbox.splitconsoleEnabled";
|
||||
const MIN_ZOOM = 0.5;
|
||||
const MAX_ZOOM = 2;
|
||||
|
||||
@ -247,7 +248,6 @@ Toolbox.prototype = {
|
||||
this._buildDockButtons();
|
||||
this._buildOptions();
|
||||
this._buildTabs();
|
||||
let buttonsPromise = this._buildButtons();
|
||||
this._applyCacheSettings();
|
||||
this._addKeysToWindow();
|
||||
this._addReloadKeys();
|
||||
@ -255,10 +255,20 @@ Toolbox.prototype = {
|
||||
this._addZoomKeys();
|
||||
this._loadInitialZoom();
|
||||
|
||||
let splitConsolePromise = promise.resolve();
|
||||
if (Services.prefs.getBoolPref(SPLITCONSOLE_ENABLED_PREF)) {
|
||||
// Force the split console on if pref is true.
|
||||
splitConsolePromise = this.toggleSplitConsole(true);
|
||||
}
|
||||
let buttonsPromise = this._buildButtons();
|
||||
|
||||
this._telemetry.toolOpened("toolbox");
|
||||
|
||||
this.selectTool(this._defaultToolId).then(panel => {
|
||||
buttonsPromise.then(() => {
|
||||
promise.all([
|
||||
splitConsolePromise,
|
||||
buttonsPromise
|
||||
]).then(() => {
|
||||
this.emit("ready");
|
||||
deferred.resolve();
|
||||
}, deferred.reject);
|
||||
@ -730,7 +740,7 @@ Toolbox.prototype = {
|
||||
radio.appendChild(image);
|
||||
}
|
||||
|
||||
if (toolDefinition.label) {
|
||||
if (toolDefinition.label && !toolDefinition.iconOnly) {
|
||||
let label = this.doc.createElement("label");
|
||||
label.setAttribute("value", toolDefinition.label)
|
||||
label.setAttribute("crop", "end");
|
||||
@ -962,23 +972,35 @@ Toolbox.prototype = {
|
||||
|
||||
/**
|
||||
* Toggles the split state of the webconsole. If the webconsole panel
|
||||
* is already selected, then this command is ignored.
|
||||
* is already selected and no forceToggle is not set, then this command
|
||||
* is ignored.
|
||||
*
|
||||
* @param {bool} forceToggle
|
||||
* Should the console be toggled regardless of the selected panel.
|
||||
*
|
||||
* @returns {Promise} a promise that resolves once the tool has been
|
||||
* loaded and focused.
|
||||
*/
|
||||
toggleSplitConsole: function() {
|
||||
toggleSplitConsole: function(forceToggle = false) {
|
||||
let openedConsolePanel = this.currentToolId === "webconsole";
|
||||
let ret = promise.resolve();
|
||||
|
||||
// Don't allow changes when console is open, since it could be confusing
|
||||
if (!openedConsolePanel) {
|
||||
if (!openedConsolePanel || forceToggle) {
|
||||
this._splitConsole = !this._splitConsole;
|
||||
Services.prefs.setBoolPref(SPLITCONSOLE_ENABLED_PREF, this._splitConsole);
|
||||
|
||||
this._refreshConsoleDisplay();
|
||||
this.emit("split-console");
|
||||
|
||||
if (this._splitConsole) {
|
||||
this.loadTool("webconsole").then(() => {
|
||||
ret = this.loadTool("webconsole").then(() => {
|
||||
this.focusConsoleInput();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -72,7 +72,7 @@ browser.jar:
|
||||
content/browser/devtools/canvasdebugger.xul (canvasdebugger/canvasdebugger.xul)
|
||||
content/browser/devtools/canvasdebugger.js (canvasdebugger/canvasdebugger.js)
|
||||
content/browser/devtools/webaudioeditor.xul (webaudioeditor/webaudioeditor.xul)
|
||||
content/browser/devtools/d3.js (webaudioeditor/lib/d3.js)
|
||||
content/browser/devtools/d3.js (shared/d3.js)
|
||||
content/browser/devtools/dagre-d3.js (webaudioeditor/lib/dagre-d3.js)
|
||||
content/browser/devtools/webaudioeditor-controller.js (webaudioeditor/webaudioeditor-controller.js)
|
||||
content/browser/devtools/webaudioeditor-view.js (webaudioeditor/webaudioeditor-view.js)
|
||||
|
@ -70,6 +70,8 @@ Tools.options = {
|
||||
icon: "chrome://browser/skin/devtools/tool-options.svg",
|
||||
invertIconForLightTheme: true,
|
||||
bgTheme: "theme-body",
|
||||
label: l10n("options.label", toolboxStrings),
|
||||
iconOnly: true,
|
||||
panelLabel: l10n("options.panelLabel", toolboxStrings),
|
||||
tooltip: l10n("optionsButton.tooltip", toolboxStrings),
|
||||
inMenu: false,
|
||||
|
@ -102,6 +102,7 @@ function test() {
|
||||
// Menus are correctly updated?
|
||||
is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"), "false", "menu unchecked");
|
||||
|
||||
Services.prefs.clearUserPref("devtools.toolbox.splitconsoleEnabled");
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ function spawnTest() {
|
||||
yield Promise.all([destroyed, waitForGraphRendered(panelWin, 3, 2)]);
|
||||
|
||||
// Test internal storage
|
||||
ok(panelWin.AudioNodes.length, 3, "All nodes should be GC'd except one gain, osc and dest node.");
|
||||
is(panelWin.AudioNodes.length, 3, "All nodes should be GC'd except one gain, osc and dest node.");
|
||||
|
||||
// Test graph rendering
|
||||
ok(findGraphNode(panelWin, actorIDs[0]), "dest should be in graph");
|
||||
|
@ -17,7 +17,7 @@
|
||||
<script type="application/javascript;version=1.8"
|
||||
src="chrome://browser/content/devtools/theme-switching.js"/>
|
||||
|
||||
<script type="application/javascript" src="d3.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/devtools/d3.js"/>
|
||||
<script type="application/javascript" src="dagre-d3.js"/>
|
||||
<script type="application/javascript" src="webaudioeditor-controller.js"/>
|
||||
<script type="application/javascript" src="webaudioeditor-view.js"/>
|
||||
|
@ -281,6 +281,7 @@ skip-if = buildapp == 'mulet'
|
||||
[browser_webconsole_scratchpad_panel_link.js]
|
||||
[browser_webconsole_split.js]
|
||||
[browser_webconsole_split_escape_key.js]
|
||||
[browser_webconsole_split_persist.js]
|
||||
[browser_webconsole_view_source.js]
|
||||
[browser_webconsole_reflow.js]
|
||||
[browser_webconsole_log_file_filter.js]
|
||||
|
@ -38,6 +38,8 @@ function test()
|
||||
function onConsoleMessage()
|
||||
{
|
||||
let currentPosition = hud.outputNode.parentNode.scrollTop;
|
||||
let bottom = currentPosition;
|
||||
|
||||
EventUtils.synthesizeKey("VK_PAGE_UP", {});
|
||||
isnot(hud.outputNode.parentNode.scrollTop, currentPosition, "scroll position changed after page up");
|
||||
|
||||
@ -45,6 +47,12 @@ function test()
|
||||
EventUtils.synthesizeKey("VK_PAGE_DOWN", {});
|
||||
ok(hud.outputNode.parentNode.scrollTop > currentPosition, "scroll position now at bottom");
|
||||
|
||||
EventUtils.synthesizeKey("VK_HOME", {});
|
||||
is(hud.outputNode.parentNode.scrollTop, 0, "scroll position now at top");
|
||||
|
||||
EventUtils.synthesizeKey("VK_END", {});
|
||||
is(hud.outputNode.parentNode.scrollTop, bottom, "scroll position now at bottom");
|
||||
|
||||
hud.jsterm.once("messages-cleared", onClear);
|
||||
info("try ctrl-l to clear output");
|
||||
EventUtils.synthesizeKey("l", { ctrlKey: true });
|
||||
|
@ -103,6 +103,12 @@ function consoleOpened(aHud) {
|
||||
|
||||
ok(popup.selectedIndex < currentSelectionIndex, "Index is less after Page UP");
|
||||
|
||||
EventUtils.synthesizeKey("VK_END", {});
|
||||
is(popup.selectedIndex, 17, "index is last after End");
|
||||
|
||||
EventUtils.synthesizeKey("VK_HOME", {});
|
||||
is(popup.selectedIndex, 0, "index is first after Home");
|
||||
|
||||
info("press Tab and wait for popup to hide");
|
||||
popup._panel.addEventListener("popuphidden", popupHideAfterTab, false);
|
||||
EventUtils.synthesizeKey("VK_TAB", {});
|
||||
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
function test() {
|
||||
info("Test that the split console state is persisted");
|
||||
|
||||
let toolbox;
|
||||
let TEST_URI = "data:text/html;charset=utf-8,<p>Web Console test for splitting</p>";
|
||||
|
||||
Task.spawn(runner).then(finish);
|
||||
|
||||
function* runner() {
|
||||
info("Opening a tab while there is no user setting on split console pref");
|
||||
let {tab} = yield loadTab(TEST_URI);
|
||||
let target = TargetFactory.forTab(tab);
|
||||
toolbox = yield gDevTools.showToolbox(target, "inspector");
|
||||
|
||||
ok(!toolbox.splitConsole, "Split console is hidden by default.");
|
||||
yield toggleSplitConsoleWithEscape();
|
||||
ok(toolbox.splitConsole, "Split console is now visible.");
|
||||
ok(getPrefValue(), "Pref is true");
|
||||
|
||||
yield toolbox.destroy();
|
||||
|
||||
info("Opening a tab while there is a true user setting on split console pref");
|
||||
let {tab} = yield loadTab(TEST_URI);
|
||||
let target = TargetFactory.forTab(tab);
|
||||
toolbox = yield gDevTools.showToolbox(target, "inspector");
|
||||
|
||||
ok(toolbox.splitConsole, "Split console is visible by default.");
|
||||
yield toggleSplitConsoleWithEscape();
|
||||
ok(!toolbox.splitConsole, "Split console is now hidden.");
|
||||
ok(!getPrefValue(), "Pref is false");
|
||||
|
||||
yield toolbox.destroy();
|
||||
|
||||
info("Opening a tab while there is a false user setting on split console pref");
|
||||
let {tab} = yield loadTab(TEST_URI);
|
||||
let target = TargetFactory.forTab(tab);
|
||||
toolbox = yield gDevTools.showToolbox(target, "inspector");
|
||||
|
||||
ok(!toolbox.splitConsole, "Split console is hidden by default.");
|
||||
ok(!getPrefValue(), "Pref is false");
|
||||
|
||||
yield toolbox.destroy();
|
||||
}
|
||||
|
||||
function getPrefValue() {
|
||||
return Services.prefs.getBoolPref("devtools.toolbox.splitconsoleEnabled");
|
||||
}
|
||||
|
||||
function toggleSplitConsoleWithEscape() {
|
||||
let onceSplitConsole = toolbox.once("split-console");
|
||||
let contentWindow = toolbox.frame.contentWindow;
|
||||
contentWindow.focus();
|
||||
EventUtils.sendKey("ESCAPE", contentWindow);
|
||||
return onceSplitConsole;
|
||||
}
|
||||
|
||||
function finish() {
|
||||
toolbox = TEST_URI = null;
|
||||
Services.prefs.clearUserPref("devtools.toolbox.splitconsoleEnabled");
|
||||
finishTest();
|
||||
}
|
||||
}
|
@ -4021,7 +4021,25 @@ JSTerm.prototype = {
|
||||
break;
|
||||
|
||||
case Ci.nsIDOMKeyEvent.DOM_VK_HOME:
|
||||
if (this.autocompletePopup.isOpen) {
|
||||
this.autocompletePopup.selectedIndex = 0;
|
||||
aEvent.preventDefault();
|
||||
} else if (this.inputNode.value.length <= 0) {
|
||||
this.hud.outputNode.parentNode.scrollTop = 0;
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
break;
|
||||
|
||||
case Ci.nsIDOMKeyEvent.DOM_VK_END:
|
||||
if (this.autocompletePopup.isOpen) {
|
||||
this.autocompletePopup.selectedIndex = this.autocompletePopup.itemCount - 1;
|
||||
aEvent.preventDefault();
|
||||
} else if (this.inputNode.value.length <= 0) {
|
||||
this.hud.outputNode.parentNode.scrollTop = this.hud.outputNode.parentNode.scrollHeight;
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
break;
|
||||
|
||||
case Ci.nsIDOMKeyEvent.DOM_VK_LEFT:
|
||||
if (this.autocompletePopup.isOpen || this.lastCompletion.value) {
|
||||
this.clearCompletion();
|
||||
|
@ -18,6 +18,8 @@ webide.jar:
|
||||
content/runtimedetails.xhtml (runtimedetails.xhtml)
|
||||
content/prefs.js (prefs.js)
|
||||
content/prefs.xhtml (prefs.xhtml)
|
||||
content/monitor.xhtml (monitor.xhtml)
|
||||
content/monitor.js (monitor.js)
|
||||
|
||||
# Temporarily include locales in content, until we're ready
|
||||
# to localize webide
|
||||
|
676
browser/devtools/webide/content/monitor.js
Normal file
@ -0,0 +1,676 @@
|
||||
/* 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 Cu = Components.utils;
|
||||
Cu.import('resource:///modules/devtools/gDevTools.jsm');
|
||||
const {require} = Cu.import('resource://gre/modules/devtools/Loader.jsm', {}).devtools;
|
||||
const {Services} = Cu.import('resource://gre/modules/Services.jsm');
|
||||
const {AppManager} = require('devtools/webide/app-manager');
|
||||
const {AppActorFront} = require('devtools/app-actor-front');
|
||||
const {Connection} = require('devtools/client/connection-manager');
|
||||
const EventEmitter = require('devtools/toolkit/event-emitter');
|
||||
|
||||
window.addEventListener('load', function onLoad() {
|
||||
window.removeEventListener('load', onLoad);
|
||||
window.addEventListener('resize', Monitor.resize);
|
||||
window.addEventListener('unload', Monitor.unload);
|
||||
|
||||
document.querySelector('#close').onclick = () => {
|
||||
window.parent.UI.openProject();
|
||||
};
|
||||
|
||||
Monitor.load();
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* The Monitor is a WebIDE tool used to display any kind of time-based data in
|
||||
* the form of graphs.
|
||||
*
|
||||
* The data can come from a Firefox OS device, simulator, or from a WebSockets
|
||||
* server running locally.
|
||||
*
|
||||
* The format of a data update is typically an object like:
|
||||
*
|
||||
* { graph: 'mygraph', curve: 'mycurve', value: 42, time: 1234 }
|
||||
*
|
||||
* or an array of such objects. For more details on the data format, see the
|
||||
* `Graph.update(data)` method.
|
||||
*/
|
||||
let Monitor = {
|
||||
|
||||
apps: new Map(),
|
||||
graphs: new Map(),
|
||||
front: null,
|
||||
socket: null,
|
||||
wstimeout: null,
|
||||
loaded: false,
|
||||
|
||||
/**
|
||||
* Add new data to the graphs, create a new graph if necessary.
|
||||
*/
|
||||
update: function(data, fallback) {
|
||||
if (Array.isArray(data)) {
|
||||
data.forEach(d => Monitor.update(d, fallback));
|
||||
return;
|
||||
}
|
||||
|
||||
if (fallback) {
|
||||
for (let key in fallback) {
|
||||
if (!data[key]) {
|
||||
data[key] = fallback[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let graph = Monitor.graphs.get(data.graph);
|
||||
if (!graph) {
|
||||
let element = document.createElement('div');
|
||||
element.classList.add('graph');
|
||||
document.body.appendChild(element);
|
||||
|
||||
graph = new Graph(data.graph, element);
|
||||
Monitor.resize(); // a scrollbar might have dis/reappeared
|
||||
Monitor.graphs.set(data.graph, graph);
|
||||
}
|
||||
graph.update(data);
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize the Monitor.
|
||||
*/
|
||||
load: function() {
|
||||
AppManager.on('app-manager-update', Monitor.onAppManagerUpdate);
|
||||
Monitor.connectToRuntime();
|
||||
Monitor.connectToWebSocket();
|
||||
Monitor.loaded = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clean up the Monitor.
|
||||
*/
|
||||
unload: function() {
|
||||
AppManager.off('app-manager-update', Monitor.onAppManagerUpdate);
|
||||
Monitor.disconnectFromRuntime();
|
||||
Monitor.disconnectFromWebSocket();
|
||||
},
|
||||
|
||||
/**
|
||||
* Resize all the graphs.
|
||||
*/
|
||||
resize: function() {
|
||||
for (let graph of Monitor.graphs.values()) {
|
||||
graph.resize();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* When WebIDE connects to a new runtime, start its data forwarders.
|
||||
*/
|
||||
onAppManagerUpdate: function(event, what, details) {
|
||||
switch (what) {
|
||||
case 'list-tabs-response':
|
||||
Monitor.connectToRuntime();
|
||||
break;
|
||||
case 'connection':
|
||||
if (AppManager.connection.status == Connection.Status.DISCONNECTED) {
|
||||
Monitor.disconnectFromRuntime();
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Use an AppActorFront on a runtime to watch track its apps.
|
||||
*/
|
||||
connectToRuntime: function() {
|
||||
let client = AppManager.connection && AppManager.connection.client;
|
||||
let resp = AppManager._listTabsResponse;
|
||||
if (client && resp && !Monitor.front) {
|
||||
Monitor.front = new AppActorFront(client, resp);
|
||||
Monitor.front.watchApps(Monitor.onRuntimeAppEvent);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroy our AppActorFront.
|
||||
*/
|
||||
disconnectFromRuntime: function() {
|
||||
if (Monitor.front) {
|
||||
Monitor.front.unwatchApps(Monitor.onRuntimeAppEvent);
|
||||
Monitor.front = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Try connecting to a local websockets server and accept updates from it.
|
||||
*/
|
||||
connectToWebSocket: function() {
|
||||
let webSocketURL = Services.prefs.getCharPref('devtools.webide.monitorWebSocketURL');
|
||||
try {
|
||||
Monitor.socket = new WebSocket(webSocketURL);
|
||||
Monitor.socket.onmessage = function(event) {
|
||||
Monitor.update(JSON.parse(event.data));
|
||||
};
|
||||
Monitor.socket.onclose = function() {
|
||||
Monitor.wstimeout = setTimeout(Monitor.connectToWebsocket, 1000);
|
||||
};
|
||||
} catch(e) {
|
||||
Monitor.wstimeout = setTimeout(Monitor.connectToWebsocket, 1000);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Used when cleaning up.
|
||||
*/
|
||||
disconnectFromWebSocket: function() {
|
||||
clearTimeout(Monitor.wstimeout);
|
||||
if (Monitor.socket) {
|
||||
Monitor.socket.onclose = () => {};
|
||||
Monitor.socket.close();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* When an app starts on the runtime, start a monitor actor for its process.
|
||||
*/
|
||||
onRuntimeAppEvent: function(type, app) {
|
||||
if (type !== 'appOpen' && type !== 'appClose') {
|
||||
return;
|
||||
}
|
||||
|
||||
let client = AppManager.connection.client;
|
||||
app.getForm().then(form => {
|
||||
if (type === 'appOpen') {
|
||||
app.monitorClient = new MonitorClient(client, form);
|
||||
app.monitorClient.start();
|
||||
app.monitorClient.on('update', Monitor.onRuntimeUpdate);
|
||||
Monitor.apps.set(form.monitorActor, app);
|
||||
} else {
|
||||
let app = Monitor.apps.get(form.monitorActor)
|
||||
if (app) {
|
||||
app.monitorClient.stop(() => app.monitorClient.destroy());
|
||||
Monitor.apps.delete(form.monitorActor);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Accept data updates from the monitor actors of a runtime.
|
||||
*/
|
||||
onRuntimeUpdate: function(type, packet) {
|
||||
let fallback = {}, app = Monitor.apps.get(packet.from);
|
||||
if (app) {
|
||||
fallback.curve = app.manifest.name
|
||||
}
|
||||
Monitor.update(packet.data, fallback);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A MonitorClient is used as an actor client of a runtime's monitor actors,
|
||||
* receiving its updates.
|
||||
*/
|
||||
function MonitorClient(client, form) {
|
||||
this.client = client;
|
||||
this.actor = form.monitorActor;
|
||||
this.events = ['update'];
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
this.client.registerClient(this);
|
||||
}
|
||||
MonitorClient.prototype.destroy = function () {
|
||||
this.client.unregisterClient(this);
|
||||
}
|
||||
MonitorClient.prototype.detach = function () {}
|
||||
MonitorClient.prototype.start = function () {
|
||||
this.client.request({
|
||||
to: this.actor,
|
||||
type: 'start'
|
||||
});
|
||||
}
|
||||
MonitorClient.prototype.stop = function (callback) {
|
||||
this.client.request({
|
||||
to: this.actor,
|
||||
type: 'stop'
|
||||
}, callback);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A Graph populates a container DOM element with an SVG graph and a legend.
|
||||
*/
|
||||
function Graph(name, element) {
|
||||
this.name = name;
|
||||
this.element = element;
|
||||
this.curves = new Map();
|
||||
this.events = new Map();
|
||||
this.ignored = new Set();
|
||||
this.enabled = true;
|
||||
this.request = null;
|
||||
|
||||
this.x = d3.time.scale();
|
||||
this.y = d3.scale.linear();
|
||||
|
||||
this.xaxis = d3.svg.axis().scale(this.x).orient('bottom');
|
||||
this.yaxis = d3.svg.axis().scale(this.y).orient('left');
|
||||
|
||||
this.xformat = d3.time.format('%I:%M:%S');
|
||||
this.yformat = this.formatter(1);
|
||||
this.yaxis.tickFormat(this.formatter(0));
|
||||
|
||||
this.line = d3.svg.line().interpolate('linear')
|
||||
.x(function(d) { return this.x(d.time); })
|
||||
.y(function(d) { return this.y(d.value); });
|
||||
|
||||
this.color = d3.scale.category10();
|
||||
|
||||
this.svg = d3.select(element).append('svg').append('g')
|
||||
.attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');
|
||||
|
||||
this.xelement = this.svg.append('g').attr('class', 'x axis').call(this.xaxis);
|
||||
this.yelement = this.svg.append('g').attr('class', 'y axis').call(this.yaxis);
|
||||
|
||||
// RULERS on axes
|
||||
let xruler = this.xruler = this.svg.select('.x.axis').append('g').attr('class', 'x ruler');
|
||||
xruler.append('line').attr('y2', 6);
|
||||
xruler.append('line').attr('stroke-dasharray', '1,1');
|
||||
xruler.append('text').attr('y', 9).attr('dy', '.71em');
|
||||
|
||||
let yruler = this.yruler = this.svg.select('.y.axis').append('g').attr('class', 'y ruler');
|
||||
yruler.append('line').attr('x2', -6);
|
||||
yruler.append('line').attr('stroke-dasharray', '1,1');
|
||||
yruler.append('text').attr('x', -9).attr('dy', '.32em');
|
||||
|
||||
let self = this;
|
||||
|
||||
d3.select(element).select('svg')
|
||||
.on('mousemove', function() {
|
||||
let mouse = d3.mouse(this);
|
||||
self.mousex = mouse[0] - self.margin.left,
|
||||
self.mousey = mouse[1] - self.margin.top;
|
||||
|
||||
xruler.attr('transform', 'translate(' + self.mousex + ',0)');
|
||||
yruler.attr('transform', 'translate(0,' + self.mousey + ')');
|
||||
});
|
||||
/*.on('mouseout', function() {
|
||||
self.xruler.attr('transform', 'translate(-500,0)');
|
||||
self.yruler.attr('transform', 'translate(0,-500)');
|
||||
});*/
|
||||
this.mousex = this.mousey = -500;
|
||||
|
||||
let sidebar = d3.select(this.element).append('div').attr('class', 'sidebar');
|
||||
let title = sidebar.append('label').attr('class', 'graph-title');
|
||||
|
||||
title.append('input')
|
||||
.attr('type', 'checkbox')
|
||||
.attr('checked', 'true')
|
||||
.on('click', function() { self.toggle(); });
|
||||
title.append('span').text(this.name);
|
||||
|
||||
this.legend = sidebar.append('div').attr('class', 'legend');
|
||||
|
||||
this.resize = this.resize.bind(this);
|
||||
this.render = this.render.bind(this);
|
||||
this.averages = this.averages.bind(this);
|
||||
|
||||
setInterval(this.averages, 1000);
|
||||
|
||||
this.resize();
|
||||
}
|
||||
|
||||
Graph.prototype = {
|
||||
|
||||
/**
|
||||
* These margin are used to properly position the SVG graph items inside the
|
||||
* container element.
|
||||
*/
|
||||
margin: {
|
||||
top: 10,
|
||||
right: 150,
|
||||
bottom: 20,
|
||||
left: 50
|
||||
},
|
||||
|
||||
/**
|
||||
* A Graph can be collapsed by the user.
|
||||
*/
|
||||
toggle: function() {
|
||||
if (this.enabled) {
|
||||
this.element.classList.add('disabled');
|
||||
this.enabled = false;
|
||||
} else {
|
||||
this.element.classList.remove('disabled');
|
||||
this.enabled = true;
|
||||
}
|
||||
Monitor.resize();
|
||||
},
|
||||
|
||||
/**
|
||||
* If the container element is resized (e.g. because the window was resized or
|
||||
* a scrollbar dis/appeared), the graph needs to be resized as well.
|
||||
*/
|
||||
resize: function() {
|
||||
let style = getComputedStyle(this.element),
|
||||
height = parseFloat(style.height) - this.margin.top - this.margin.bottom,
|
||||
width = parseFloat(style.width) - this.margin.left - this.margin.right;
|
||||
|
||||
d3.select(this.element).select('svg')
|
||||
.attr('width', width + this.margin.left)
|
||||
.attr('height', height + this.margin.top + this.margin.bottom);
|
||||
|
||||
this.x.range([0, width]);
|
||||
this.y.range([height, 0]);
|
||||
|
||||
this.xelement.attr('transform', 'translate(0,' + height + ')')
|
||||
this.xruler.select('line[stroke-dasharray]').attr('y2', -height);
|
||||
this.yruler.select('line[stroke-dasharray]').attr('x2', width);
|
||||
},
|
||||
|
||||
/**
|
||||
* If the domain of the Graph's data changes (on the time axis and/or on the
|
||||
* value axis), the axes' domains need to be updated and the graph items need
|
||||
* to be rescaled in order to represent all the data.
|
||||
*/
|
||||
rescale: function() {
|
||||
let gettime = v => { return v.time; },
|
||||
getvalue = v => { return v.value; },
|
||||
ignored = c => { return this.ignored.has(c.id); };
|
||||
|
||||
let xmin = null, xmax = null, ymin = null, ymax = null;
|
||||
for (let curve of this.curves.values()) {
|
||||
if (ignored(curve)) {
|
||||
continue;
|
||||
}
|
||||
if (xmax == null || curve.xmax > xmax) {
|
||||
xmax = curve.xmax;
|
||||
}
|
||||
if (xmin == null || curve.xmin < xmin) {
|
||||
xmin = curve.xmin;
|
||||
}
|
||||
if (ymax == null || curve.ymax > ymax) {
|
||||
ymax = curve.ymax;
|
||||
}
|
||||
if (ymin == null || curve.ymin < ymin) {
|
||||
ymin = curve.ymin;
|
||||
}
|
||||
}
|
||||
for (let event of this.events.values()) {
|
||||
if (ignored(event)) {
|
||||
continue;
|
||||
}
|
||||
if (xmax == null || event.xmax > xmax) {
|
||||
xmax = event.xmax;
|
||||
}
|
||||
if (xmin == null || event.xmin < xmin) {
|
||||
xmin = event.xmin;
|
||||
}
|
||||
}
|
||||
|
||||
let oldxdomain = this.x.domain();
|
||||
if (xmin != null && xmax != null) {
|
||||
this.x.domain([xmin, xmax]);
|
||||
let newxdomain = this.x.domain();
|
||||
if (newxdomain[0] !== oldxdomain[0] || newxdomain[1] !== oldxdomain[1]) {
|
||||
this.xelement.call(this.xaxis);
|
||||
}
|
||||
}
|
||||
|
||||
let oldydomain = this.y.domain();
|
||||
if (ymin != null && ymax != null) {
|
||||
this.y.domain([ymin, ymax]).nice();
|
||||
let newydomain = this.y.domain();
|
||||
if (newydomain[0] !== oldydomain[0] || newydomain[1] !== oldydomain[1]) {
|
||||
this.yelement.call(this.yaxis);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add new values to the graph.
|
||||
*/
|
||||
update: function(data) {
|
||||
delete data.graph;
|
||||
|
||||
let time = data.time || Date.now();
|
||||
delete data.time;
|
||||
|
||||
let curve = data.curve;
|
||||
delete data.curve;
|
||||
|
||||
// Single curve value, e.g. { curve: 'memory', value: 42, time: 1234 }.
|
||||
if ('value' in data) {
|
||||
this.push(this.curves, curve, [{time: time, value: data.value}]);
|
||||
delete data.value;
|
||||
}
|
||||
|
||||
// Several curve values, e.g. { curve: 'memory', values: [{value: 42, time: 1234}] }.
|
||||
if ('values' in data) {
|
||||
this.push(this.curves, curve, data.values);
|
||||
delete data.values;
|
||||
}
|
||||
|
||||
// Punctual event, e.g. { event: 'gc', time: 1234 },
|
||||
// event with duration, e.g. { event: 'jank', duration: 425, time: 1234 }.
|
||||
if ('event' in data) {
|
||||
this.push(this.events, data.event, [{time: time, value: data.duration}]);
|
||||
delete data.event;
|
||||
delete data.duration;
|
||||
}
|
||||
|
||||
// Remaining keys are curves, e.g. { time: 1234, memory: 42, battery: 13, temperature: 45 }.
|
||||
for (let key in data) {
|
||||
this.push(this.curves, key, [{time: time, value: data[key]}]);
|
||||
}
|
||||
|
||||
// If no render is currently pending, request one.
|
||||
if (this.enabled && !this.request) {
|
||||
this.request = requestAnimationFrame(this.render);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Insert new data into the graph's data structures.
|
||||
*/
|
||||
push: function(collection, id, values) {
|
||||
|
||||
// Note: collection is either `this.curves` or `this.events`.
|
||||
let item = collection.get(id);
|
||||
if (!item) {
|
||||
item = { id: id, values: [], xmin: null, xmax: null, ymin: 0, ymax: null, average: 0 };
|
||||
collection.set(id, item);
|
||||
}
|
||||
|
||||
for (let v of values) {
|
||||
let time = new Date(v.time), value = +v.value;
|
||||
// Update the curve/event's domain values.
|
||||
if (item.xmax == null || time > item.xmax) {
|
||||
item.xmax = time;
|
||||
}
|
||||
if (item.xmin == null || time < item.xmin) {
|
||||
item.xmin = time;
|
||||
}
|
||||
if (item.ymax == null || value > item.ymax) {
|
||||
item.ymax = value;
|
||||
}
|
||||
if (item.ymin == null || value < item.ymin) {
|
||||
item.ymin = value;
|
||||
}
|
||||
// Note: A curve's average is not computed here. Call `graph.averages()`.
|
||||
item.values.push({ time: time, value: value });
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Render the SVG graph with curves, events, crosshair and legend.
|
||||
*/
|
||||
render: function() {
|
||||
this.request = null;
|
||||
this.rescale();
|
||||
|
||||
|
||||
// DATA
|
||||
|
||||
let self = this,
|
||||
getid = d => { return d.id; },
|
||||
gettime = d => { return d.time.getTime(); },
|
||||
getline = d => { return self.line(d.values); },
|
||||
getcolor = d => { return self.color(d.id); },
|
||||
getvalues = d => { return d.values; },
|
||||
ignored = d => { return self.ignored.has(d.id); };
|
||||
|
||||
// Convert our maps to arrays for d3.
|
||||
let curvedata = [...this.curves.values()],
|
||||
eventdata = [...this.events.values()],
|
||||
data = curvedata.concat(eventdata);
|
||||
|
||||
|
||||
// CURVES
|
||||
|
||||
// Map curve data to curve elements.
|
||||
let curves = this.svg.selectAll('.curve').data(curvedata, getid);
|
||||
|
||||
// Create new curves (no element corresponding to the data).
|
||||
curves.enter().append('g').attr('class', 'curve').append('path')
|
||||
.style('stroke', getcolor);
|
||||
|
||||
// Delete old curves (elements corresponding to data not present anymore).
|
||||
curves.exit().remove();
|
||||
|
||||
// Update all curves from data.
|
||||
this.svg.selectAll('.curve').select('path')
|
||||
.attr('d', d => { return ignored(d) ? '' : getline(d); });
|
||||
|
||||
let height = parseFloat(getComputedStyle(this.element).height) - this.margin.top - this.margin.bottom;
|
||||
|
||||
|
||||
// EVENTS
|
||||
|
||||
// Map event data to event elements.
|
||||
let events = this.svg.selectAll('.event-slot').data(eventdata, getid);
|
||||
|
||||
// Create new events.
|
||||
events.enter().append('g').attr('class', 'event-slot');
|
||||
|
||||
// Remove old events.
|
||||
events.exit().remove();
|
||||
|
||||
// Get all occurences of an event, and map its data to them.
|
||||
let lines = this.svg.selectAll('.event-slot')
|
||||
.style('stroke', d => { return ignored(d) ? 'none' : getcolor(d); })
|
||||
.selectAll('.event')
|
||||
.data(getvalues, gettime);
|
||||
|
||||
// Create new event occurrence.
|
||||
lines.enter().append('line').attr('class', 'event').attr('y2', height);
|
||||
|
||||
// Delete old event occurrence.
|
||||
lines.exit().remove();
|
||||
|
||||
// Update all event occurrences from data.
|
||||
this.svg.selectAll('.event')
|
||||
.attr('transform', d => { return 'translate(' + self.x(d.time) + ',0)'; });
|
||||
|
||||
|
||||
// CROSSHAIR
|
||||
|
||||
// TODO select curves and events, intersect with curves and show values/hovers
|
||||
// e.g. look like http://code.shutterstock.com/rickshaw/examples/lines.html
|
||||
|
||||
// Update crosshair labels on each axis.
|
||||
this.xruler.select('text').text(self.xformat(self.x.invert(self.mousex)));
|
||||
this.yruler.select('text').text(self.yformat(self.y.invert(self.mousey)));
|
||||
|
||||
|
||||
// LEGEND
|
||||
|
||||
// Map data to legend elements.
|
||||
let legends = this.legend.selectAll('label').data(data, getid);
|
||||
|
||||
// Update averages.
|
||||
legends.attr('title', c => { return 'Average: ' + self.yformat(c.average); });
|
||||
|
||||
// Create new legends.
|
||||
let newlegend = legends.enter().append('label');
|
||||
newlegend.append('input').attr('type', 'checkbox').attr('checked', 'true').on('click', function(c) {
|
||||
if (ignored(c)) {
|
||||
this.parentElement.classList.remove('disabled');
|
||||
self.ignored.delete(c.id);
|
||||
} else {
|
||||
this.parentElement.classList.add('disabled');
|
||||
self.ignored.add(c.id);
|
||||
}
|
||||
self.update({}); // if no re-render is pending, request one.
|
||||
});
|
||||
newlegend.append('span').attr('class', 'legend-color').style('background-color', getcolor);
|
||||
newlegend.append('span').attr('class', 'legend-id').text(getid);
|
||||
|
||||
// Delete old legends.
|
||||
legends.exit().remove();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a SI value formatter with a given precision.
|
||||
*/
|
||||
formatter: function(decimals) {
|
||||
return value => {
|
||||
// Don't use sub-unit SI prefixes (milli, micro, etc.).
|
||||
if (Math.abs(value) < 1) return value.toFixed(decimals);
|
||||
// SI prefix, e.g. 1234567 will give '1.2M' at precision 1.
|
||||
let prefix = d3.formatPrefix(value);
|
||||
return prefix.scale(value).toFixed(decimals) + prefix.symbol;
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Compute the average of each time series.
|
||||
*/
|
||||
averages: function() {
|
||||
for (let c of this.curves.values()) {
|
||||
let length = c.values.length;
|
||||
if (length > 0) {
|
||||
let total = 0;
|
||||
c.values.forEach(v => total += v.value);
|
||||
c.average = (total / length);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Bisect a time serie to find the data point immediately left of `time`.
|
||||
*/
|
||||
bisectTime: d3.bisector(d => d.time).left,
|
||||
|
||||
/**
|
||||
* Get all curve values at a given time.
|
||||
*/
|
||||
valuesAt: function(time) {
|
||||
let values = { time: time };
|
||||
|
||||
for (let id of this.curves.keys()) {
|
||||
let curve = this.curves.get(id);
|
||||
|
||||
// Find the closest value just before `time`.
|
||||
let i = this.bisectTime(curve.values, time);
|
||||
if (i < 0) {
|
||||
// Curve starts after `time`, use first value.
|
||||
values[id] = curve.values[0].value;
|
||||
} else if (i > curve.values.length-2) {
|
||||
// Curve ends before `time`, use last value.
|
||||
values[id] = curve.values[curve.values.length-1].value;
|
||||
} else {
|
||||
// Curve has two values around `time`, interpolate.
|
||||
let v1 = curve.values[i],
|
||||
v2 = curve.values[i+1],
|
||||
delta = (time - v1.time) / (v2.time - v1.time);
|
||||
values[id] = v1.value + (v2.value - v1.time) * delta;
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
};
|
31
browser/devtools/webide/content/monitor.xhtml
Normal file
@ -0,0 +1,31 @@
|
||||
<?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 % webideDTD SYSTEM "chrome://webide/content/webide.dtd" >
|
||||
%webideDTD;
|
||||
]>
|
||||
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf8"/>
|
||||
<link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://webide/skin/monitor.css" type="text/css"/>
|
||||
<script src="chrome://browser/content/devtools/d3.js"></script>
|
||||
<script type="application/javascript;version=1.8" src="monitor.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="controls">
|
||||
<a href="https://developer.mozilla.org/docs/Tools/WebIDE/Monitor" target="_blank">&monitor_help;</a>
|
||||
<a id="close">&deck_close;</a>
|
||||
</div>
|
||||
|
||||
<h1>&monitor_title;</h1>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -488,6 +488,11 @@ let UI = {
|
||||
this.resetFocus();
|
||||
let deck = document.querySelector("#deck");
|
||||
let panel = deck.querySelector("#deck-panel-" + id);
|
||||
let lazysrc = panel.getAttribute("lazysrc");
|
||||
if (lazysrc) {
|
||||
panel.removeAttribute("lazysrc");
|
||||
panel.setAttribute("src", lazysrc);
|
||||
}
|
||||
deck.selectedPanel = panel;
|
||||
this.updateProjectEditorMenusVisibility();
|
||||
},
|
||||
@ -881,6 +886,10 @@ let Cmds = {
|
||||
UI.selectDeckPanel("runtimedetails");
|
||||
},
|
||||
|
||||
showMonitor: function() {
|
||||
UI.selectDeckPanel("monitor");
|
||||
},
|
||||
|
||||
play: function() {
|
||||
switch(AppManager.selectedProject.type) {
|
||||
case "packaged":
|
||||
|
@ -39,6 +39,7 @@
|
||||
<command id="cmd_showProjectPanel" oncommand="Cmds.showProjectPanel()"/>
|
||||
<command id="cmd_showRuntimePanel" oncommand="Cmds.showRuntimePanel()"/>
|
||||
<command id="cmd_disconnectRuntime" oncommand="Cmds.disconnectRuntime()" label="&runtimeMenu_disconnect_label;"/>
|
||||
<command id="cmd_showMonitor" oncommand="Cmds.showMonitor()" label="&runtimeMenu_showMonitor_label;"/>
|
||||
<command id="cmd_showPermissionsTable" oncommand="Cmds.showPermissionsTable()" label="&runtimeMenu_showPermissionTable_label;"/>
|
||||
<command id="cmd_showRuntimeDetails" oncommand="Cmds.showRuntimeDetails()" label="&runtimeMenu_showDetails_label;"/>
|
||||
<command id="cmd_takeScreenshot" oncommand="Cmds.takeScreenshot()" label="&runtimeMenu_takeScreenshot_label;"/>
|
||||
@ -72,6 +73,7 @@
|
||||
|
||||
<menu id="menu-runtime" label="&runtimeMenu_label;" accesskey="&runtimeMenu_accesskey;">
|
||||
<menupopup id="menu-runtime-popup">
|
||||
<menuitem command="cmd_showMonitor" accesskey="&runtimeMenu_showMonitor_accesskey;"/>
|
||||
<menuitem command="cmd_takeScreenshot" accesskey="&runtimeMenu_takeScreenshot_accesskey;"/>
|
||||
<menuitem command="cmd_showPermissionsTable" accesskey="&runtimeMenu_showPermissionTable_accesskey;"/>
|
||||
<menuitem command="cmd_showRuntimeDetails" accesskey="&runtimeMenu_showDetails_accesskey;"/>
|
||||
@ -177,6 +179,7 @@
|
||||
<iframe id="deck-panel-prefs" flex="1" src="prefs.xhtml"/>
|
||||
<iframe id="deck-panel-permissionstable" flex="1" src="permissionstable.xhtml"/>
|
||||
<iframe id="deck-panel-runtimedetails" flex="1" src="runtimedetails.xhtml"/>
|
||||
<iframe id="deck-panel-monitor" flex="1" lazysrc="monitor.xhtml"/>
|
||||
</deck>
|
||||
</notificationbox>
|
||||
|
||||
|
@ -35,6 +35,8 @@
|
||||
<!ENTITY runtimeMenu_takeScreenshot_accesskey "S">
|
||||
<!ENTITY runtimeMenu_showDetails_label "Runtime Info">
|
||||
<!ENTITY runtimeMenu_showDetails_accesskey "E">
|
||||
<!ENTITY runtimeMenu_showMonitor_label "Monitor">
|
||||
<!ENTITY runtimeMenu_showMonitor_accesskey "M">
|
||||
|
||||
<!ENTITY viewMenu_label "View">
|
||||
<!ENTITY viewMenu_accesskey "V">
|
||||
@ -128,3 +130,7 @@
|
||||
<!ENTITY runtimedetails_restrictedPrivileges "DevTools restricted privileges: ">
|
||||
<!ENTITY runtimedetails_requestPrivileges "request higher privileges">
|
||||
<!ENTITY runtimedetails_privilegesWarning "(Will reboot device. Requires root access.)">
|
||||
|
||||
<!-- Monitor -->
|
||||
<!ENTITY monitor_title "Monitor">
|
||||
<!ENTITY monitor_help "Help">
|
||||
|
@ -14,3 +14,4 @@ webide.jar:
|
||||
skin/prefs.css (prefs.css)
|
||||
skin/runtimedetails.css (runtimedetails.css)
|
||||
skin/permissionstable.css (permissionstable.css)
|
||||
skin/monitor.css (monitor.css)
|
||||
|
86
browser/devtools/webide/themes/monitor.css
Normal file
@ -0,0 +1,86 @@
|
||||
/* 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/. */
|
||||
|
||||
/* Graph */
|
||||
.graph {
|
||||
height: 500px;
|
||||
width: 100%;
|
||||
padding-top: 20px;
|
||||
padding-bottom: 20px;
|
||||
margin-bottom: 30px;
|
||||
background-color: white;
|
||||
}
|
||||
.graph > svg, .sidebar {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
.disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.graph.disabled {
|
||||
height: 30px;
|
||||
}
|
||||
.graph.disabled > svg {
|
||||
visibility: hidden;
|
||||
}
|
||||
.curve path, .event-slot line {
|
||||
fill: none;
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
.axis line {
|
||||
fill: none;
|
||||
stroke: #000;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
.axis path {
|
||||
fill: none;
|
||||
stroke: black;
|
||||
stroke-width: 1px;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
.tick text, .x.ruler text, .y.ruler text {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.x.ruler text {
|
||||
text-anchor: middle;
|
||||
}
|
||||
.y.ruler text {
|
||||
text-anchor: end;
|
||||
}
|
||||
|
||||
/* Sidebar */
|
||||
.sidebar {
|
||||
width: 150px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.sidebar label {
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
}
|
||||
.sidebar span:not(.color) {
|
||||
vertical-align: 13%;
|
||||
}
|
||||
.sidebar input {
|
||||
visibility: hidden;
|
||||
}
|
||||
.sidebar input:hover {
|
||||
visibility: visible;
|
||||
}
|
||||
.graph-title {
|
||||
margin-top: 5px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
.legend-color {
|
||||
display: inline-block;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
margin-left: 1px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
.legend-id {
|
||||
font-size: .9em;
|
||||
}
|
||||
.graph.disabled > .sidebar > .legend {
|
||||
display: none;
|
||||
}
|
@ -14,3 +14,4 @@ pref("devtools.webide.simulatorAddonsURL", "https://ftp.mozilla.org/pub/mozilla.
|
||||
pref("devtools.webide.simulatorAddonID", "fxos_#SLASHED_VERSION#_simulator@mozilla.org");
|
||||
pref("devtools.webide.adbAddonURL", "https://ftp.mozilla.org/pub/mozilla.org/labs/fxos-simulator/adb-helper/#OS#/adbhelper-#OS#-latest.xpi");
|
||||
pref("devtools.webide.adbAddonID", "adbhelper@mozilla.org");
|
||||
pref("devtools.webide.monitorWebSocketURL", "ws://localhost:9000");
|
||||
|
@ -1,4 +1,4 @@
|
||||
This is the pdf.js project output, https://github.com/mozilla/pdf.js
|
||||
|
||||
Current extension version is: 1.0.370
|
||||
Current extension version is: 1.0.473
|
||||
|
||||
|
@ -44,10 +44,22 @@ this.PdfJsTelemetry = {
|
||||
let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_DOCUMENT_GENERATOR");
|
||||
histogram.add(generatorId);
|
||||
},
|
||||
onEmbed: function (isObject) {
|
||||
let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_EMBED");
|
||||
histogram.add(isObject);
|
||||
},
|
||||
onFontType: function (fontTypeId) {
|
||||
let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_FONT_TYPES");
|
||||
histogram.add(fontTypeId);
|
||||
},
|
||||
onForm: function (isAcroform) {
|
||||
let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_FORM");
|
||||
histogram.add(isAcroform);
|
||||
},
|
||||
onPrint: function () {
|
||||
let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_PRINT");
|
||||
histogram.add(true);
|
||||
},
|
||||
onStreamType: function (streamTypeId) {
|
||||
let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_STREAM_TYPES");
|
||||
histogram.add(streamTypeId);
|
||||
|
@ -232,6 +232,7 @@ function ChromeActions(domWindow, contentDispositionFilename) {
|
||||
documentInfo: false,
|
||||
firstPageInfo: false,
|
||||
streamTypesUsed: [],
|
||||
fontTypesUsed: [],
|
||||
startAt: Date.now()
|
||||
};
|
||||
}
|
||||
@ -373,18 +374,39 @@ ChromeActions.prototype = {
|
||||
this.telemetryState.firstPageInfo = true;
|
||||
}
|
||||
break;
|
||||
case 'streamInfo':
|
||||
if (!Array.isArray(probeInfo.streamTypes)) {
|
||||
case 'documentStats':
|
||||
// documentStats can be called several times for one documents.
|
||||
// if stream/font types are reported, trying not to submit the same
|
||||
// enumeration value multiple times.
|
||||
var documentStats = probeInfo.stats;
|
||||
if (!documentStats || typeof documentStats !== 'object') {
|
||||
break;
|
||||
}
|
||||
for (var i = 0; i < probeInfo.streamTypes.length; i++) {
|
||||
var streamTypeId = probeInfo.streamTypes[i] | 0;
|
||||
if (streamTypeId >= 0 && streamTypeId < 10 &&
|
||||
!this.telemetryState.streamTypesUsed[streamTypeId]) {
|
||||
PdfJsTelemetry.onStreamType(streamTypeId);
|
||||
this.telemetryState.streamTypesUsed[streamTypeId] = true;
|
||||
var streamTypes = documentStats.streamTypes;
|
||||
if (Array.isArray(streamTypes)) {
|
||||
var STREAM_TYPE_ID_LIMIT = 20;
|
||||
for (var i = 0; i < STREAM_TYPE_ID_LIMIT; i++) {
|
||||
if (streamTypes[i] &&
|
||||
!this.telemetryState.streamTypesUsed[i]) {
|
||||
PdfJsTelemetry.onStreamType(i);
|
||||
this.telemetryState.streamTypesUsed[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
var fontTypes = documentStats.fontTypes;
|
||||
if (Array.isArray(fontTypes)) {
|
||||
var FONT_TYPE_ID_LIMIT = 20;
|
||||
for (var i = 0; i < FONT_TYPE_ID_LIMIT; i++) {
|
||||
if (fontTypes[i] &&
|
||||
!this.telemetryState.fontTypesUsed[i]) {
|
||||
PdfJsTelemetry.onFontType(i);
|
||||
this.telemetryState.fontTypesUsed[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'print':
|
||||
PdfJsTelemetry.onPrint();
|
||||
break;
|
||||
}
|
||||
},
|
||||
@ -942,6 +964,12 @@ PdfStreamConverter.prototype = {
|
||||
findEventManager.bind();
|
||||
}
|
||||
listener.onStopRequest(aRequest, context, statusCode);
|
||||
|
||||
if (domWindow.frameElement) {
|
||||
var isObjectEmbed = domWindow.frameElement.tagName !== 'IFRAME' ||
|
||||
domWindow.frameElement.className === 'previewPluginContentFrame';
|
||||
PdfJsTelemetry.onEmbed(isObjectEmbed);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
2146
browser/extensions/pdfjs/content/build/pdf.worker.js
vendored
@ -71,72 +71,72 @@ http://sourceforge.net/adobe/cmap/wiki/License/
|
||||
<div id="mainContainer">
|
||||
<div class="findbar hidden doorHanger hiddenSmallView" id="findbar">
|
||||
<label for="findInput" class="toolbarLabel" data-l10n-id="find_label">Find:</label>
|
||||
<input id="findInput" class="toolbarField" tabindex="41">
|
||||
<input id="findInput" class="toolbarField" tabindex="91">
|
||||
<div class="splitToolbarButton">
|
||||
<button class="toolbarButton findPrevious" title="" id="findPrevious" tabindex="42" data-l10n-id="find_previous">
|
||||
<button class="toolbarButton findPrevious" title="" id="findPrevious" tabindex="92" data-l10n-id="find_previous">
|
||||
<span data-l10n-id="find_previous_label">Previous</span>
|
||||
</button>
|
||||
<div class="splitToolbarButtonSeparator"></div>
|
||||
<button class="toolbarButton findNext" title="" id="findNext" tabindex="43" data-l10n-id="find_next">
|
||||
<button class="toolbarButton findNext" title="" id="findNext" tabindex="93" data-l10n-id="find_next">
|
||||
<span data-l10n-id="find_next_label">Next</span>
|
||||
</button>
|
||||
</div>
|
||||
<input type="checkbox" id="findHighlightAll" class="toolbarField">
|
||||
<label for="findHighlightAll" class="toolbarLabel" tabindex="44" data-l10n-id="find_highlight">Highlight all</label>
|
||||
<label for="findHighlightAll" class="toolbarLabel" tabindex="94" data-l10n-id="find_highlight">Highlight all</label>
|
||||
<input type="checkbox" id="findMatchCase" class="toolbarField">
|
||||
<label for="findMatchCase" class="toolbarLabel" tabindex="45" data-l10n-id="find_match_case_label">Match case</label>
|
||||
<label for="findMatchCase" class="toolbarLabel" tabindex="95" data-l10n-id="find_match_case_label">Match case</label>
|
||||
<span id="findMsg" class="toolbarLabel"></span>
|
||||
</div> <!-- findbar -->
|
||||
|
||||
<div id="secondaryToolbar" class="secondaryToolbar hidden doorHangerRight">
|
||||
<div id="secondaryToolbarButtonContainer">
|
||||
<button id="secondaryPresentationMode" class="secondaryToolbarButton presentationMode visibleLargeView" title="Switch to Presentation Mode" tabindex="19" data-l10n-id="presentation_mode">
|
||||
<button id="secondaryPresentationMode" class="secondaryToolbarButton presentationMode visibleLargeView" title="Switch to Presentation Mode" tabindex="51" data-l10n-id="presentation_mode">
|
||||
<span data-l10n-id="presentation_mode_label">Presentation Mode</span>
|
||||
</button>
|
||||
|
||||
<button id="secondaryOpenFile" class="secondaryToolbarButton openFile visibleLargeView" title="Open File" tabindex="20" data-l10n-id="open_file">
|
||||
<button id="secondaryOpenFile" class="secondaryToolbarButton openFile visibleLargeView" title="Open File" tabindex="52" data-l10n-id="open_file">
|
||||
<span data-l10n-id="open_file_label">Open</span>
|
||||
</button>
|
||||
|
||||
<button id="secondaryPrint" class="secondaryToolbarButton print visibleMediumView" title="Print" tabindex="21" data-l10n-id="print">
|
||||
<button id="secondaryPrint" class="secondaryToolbarButton print visibleMediumView" title="Print" tabindex="53" data-l10n-id="print">
|
||||
<span data-l10n-id="print_label">Print</span>
|
||||
</button>
|
||||
|
||||
<button id="secondaryDownload" class="secondaryToolbarButton download visibleMediumView" title="Download" tabindex="22" data-l10n-id="download">
|
||||
<button id="secondaryDownload" class="secondaryToolbarButton download visibleMediumView" title="Download" tabindex="54" data-l10n-id="download">
|
||||
<span data-l10n-id="download_label">Download</span>
|
||||
</button>
|
||||
|
||||
<a href="#" id="secondaryViewBookmark" class="secondaryToolbarButton bookmark visibleSmallView" title="Current view (copy or open in new window)" tabindex="23" data-l10n-id="bookmark">
|
||||
<a href="#" id="secondaryViewBookmark" class="secondaryToolbarButton bookmark visibleSmallView" title="Current view (copy or open in new window)" tabindex="55" data-l10n-id="bookmark">
|
||||
<span data-l10n-id="bookmark_label">Current View</span>
|
||||
</a>
|
||||
|
||||
<div class="horizontalToolbarSeparator visibleLargeView"></div>
|
||||
|
||||
<button id="firstPage" class="secondaryToolbarButton firstPage" title="Go to First Page" tabindex="24" data-l10n-id="first_page">
|
||||
<button id="firstPage" class="secondaryToolbarButton firstPage" title="Go to First Page" tabindex="56" data-l10n-id="first_page">
|
||||
<span data-l10n-id="first_page_label">Go to First Page</span>
|
||||
</button>
|
||||
<button id="lastPage" class="secondaryToolbarButton lastPage" title="Go to Last Page" tabindex="25" data-l10n-id="last_page">
|
||||
<button id="lastPage" class="secondaryToolbarButton lastPage" title="Go to Last Page" tabindex="57" data-l10n-id="last_page">
|
||||
<span data-l10n-id="last_page_label">Go to Last Page</span>
|
||||
</button>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<button id="pageRotateCw" class="secondaryToolbarButton rotateCw" title="Rotate Clockwise" tabindex="26" data-l10n-id="page_rotate_cw">
|
||||
<button id="pageRotateCw" class="secondaryToolbarButton rotateCw" title="Rotate Clockwise" tabindex="58" data-l10n-id="page_rotate_cw">
|
||||
<span data-l10n-id="page_rotate_cw_label">Rotate Clockwise</span>
|
||||
</button>
|
||||
<button id="pageRotateCcw" class="secondaryToolbarButton rotateCcw" title="Rotate Counterclockwise" tabindex="27" data-l10n-id="page_rotate_ccw">
|
||||
<button id="pageRotateCcw" class="secondaryToolbarButton rotateCcw" title="Rotate Counterclockwise" tabindex="59" data-l10n-id="page_rotate_ccw">
|
||||
<span data-l10n-id="page_rotate_ccw_label">Rotate Counterclockwise</span>
|
||||
</button>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<button id="toggleHandTool" class="secondaryToolbarButton handTool" title="Enable hand tool" tabindex="28" data-l10n-id="hand_tool_enable">
|
||||
<button id="toggleHandTool" class="secondaryToolbarButton handTool" title="Enable hand tool" tabindex="60" data-l10n-id="hand_tool_enable">
|
||||
<span data-l10n-id="hand_tool_enable_label">Enable hand tool</span>
|
||||
</button>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<button id="documentProperties" class="secondaryToolbarButton documentProperties" title="Document Properties…" tabindex="29" data-l10n-id="document_properties">
|
||||
<button id="documentProperties" class="secondaryToolbarButton documentProperties" title="Document Properties…" tabindex="61" data-l10n-id="document_properties">
|
||||
<span data-l10n-id="document_properties_label">Document Properties…</span>
|
||||
</button>
|
||||
</div>
|
||||
@ -146,66 +146,66 @@ http://sourceforge.net/adobe/cmap/wiki/License/
|
||||
<div id="toolbarContainer">
|
||||
<div id="toolbarViewer">
|
||||
<div id="toolbarViewerLeft">
|
||||
<button id="sidebarToggle" class="toolbarButton" title="Toggle Sidebar" tabindex="5" data-l10n-id="toggle_sidebar">
|
||||
<button id="sidebarToggle" class="toolbarButton" title="Toggle Sidebar" tabindex="11" data-l10n-id="toggle_sidebar">
|
||||
<span data-l10n-id="toggle_sidebar_label">Toggle Sidebar</span>
|
||||
</button>
|
||||
<div class="toolbarButtonSpacer"></div>
|
||||
<button id="viewFind" class="toolbarButton group hiddenSmallView" title="Find in Document" tabindex="6" data-l10n-id="findbar">
|
||||
<button id="viewFind" class="toolbarButton group hiddenSmallView" title="Find in Document" tabindex="12" data-l10n-id="findbar">
|
||||
<span data-l10n-id="findbar_label">Find</span>
|
||||
</button>
|
||||
<div class="splitToolbarButton">
|
||||
<button class="toolbarButton pageUp" title="Previous Page" id="previous" tabindex="7" data-l10n-id="previous">
|
||||
<button class="toolbarButton pageUp" title="Previous Page" id="previous" tabindex="13" data-l10n-id="previous">
|
||||
<span data-l10n-id="previous_label">Previous</span>
|
||||
</button>
|
||||
<div class="splitToolbarButtonSeparator"></div>
|
||||
<button class="toolbarButton pageDown" title="Next Page" id="next" tabindex="8" data-l10n-id="next">
|
||||
<button class="toolbarButton pageDown" title="Next Page" id="next" tabindex="14" data-l10n-id="next">
|
||||
<span data-l10n-id="next_label">Next</span>
|
||||
</button>
|
||||
</div>
|
||||
<label id="pageNumberLabel" class="toolbarLabel" for="pageNumber" data-l10n-id="page_label">Page: </label>
|
||||
<input type="number" id="pageNumber" class="toolbarField pageNumber" value="1" size="4" min="1" tabindex="9">
|
||||
<input type="number" id="pageNumber" class="toolbarField pageNumber" value="1" size="4" min="1" tabindex="15">
|
||||
<span id="numPages" class="toolbarLabel"></span>
|
||||
</div>
|
||||
<div id="toolbarViewerRight">
|
||||
<button id="presentationMode" class="toolbarButton presentationMode hiddenLargeView" title="Switch to Presentation Mode" tabindex="13" data-l10n-id="presentation_mode">
|
||||
<button id="presentationMode" class="toolbarButton presentationMode hiddenLargeView" title="Switch to Presentation Mode" tabindex="31" data-l10n-id="presentation_mode">
|
||||
<span data-l10n-id="presentation_mode_label">Presentation Mode</span>
|
||||
</button>
|
||||
|
||||
<button id="openFile" class="toolbarButton openFile hiddenLargeView" title="Open File" tabindex="14" data-l10n-id="open_file">
|
||||
<button id="openFile" class="toolbarButton openFile hiddenLargeView" title="Open File" tabindex="32" data-l10n-id="open_file">
|
||||
<span data-l10n-id="open_file_label">Open</span>
|
||||
</button>
|
||||
|
||||
<button id="print" class="toolbarButton print hiddenMediumView" title="Print" tabindex="15" data-l10n-id="print">
|
||||
<button id="print" class="toolbarButton print hiddenMediumView" title="Print" tabindex="33" data-l10n-id="print">
|
||||
<span data-l10n-id="print_label">Print</span>
|
||||
</button>
|
||||
|
||||
<button id="download" class="toolbarButton download hiddenMediumView" title="Download" tabindex="16" data-l10n-id="download">
|
||||
<button id="download" class="toolbarButton download hiddenMediumView" title="Download" tabindex="34" data-l10n-id="download">
|
||||
<span data-l10n-id="download_label">Download</span>
|
||||
</button>
|
||||
<!-- <div class="toolbarButtonSpacer"></div> -->
|
||||
<a href="#" id="viewBookmark" class="toolbarButton bookmark hiddenSmallView" title="Current view (copy or open in new window)" tabindex="17" data-l10n-id="bookmark">
|
||||
<a href="#" id="viewBookmark" class="toolbarButton bookmark hiddenSmallView" title="Current view (copy or open in new window)" tabindex="35" data-l10n-id="bookmark">
|
||||
<span data-l10n-id="bookmark_label">Current View</span>
|
||||
</a>
|
||||
|
||||
<div class="verticalToolbarSeparator hiddenSmallView"></div>
|
||||
|
||||
<button id="secondaryToolbarToggle" class="toolbarButton" title="Tools" tabindex="18" data-l10n-id="tools">
|
||||
<button id="secondaryToolbarToggle" class="toolbarButton" title="Tools" tabindex="36" data-l10n-id="tools">
|
||||
<span data-l10n-id="tools_label">Tools</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="outerCenter">
|
||||
<div class="innerCenter" id="toolbarViewerMiddle">
|
||||
<div class="splitToolbarButton">
|
||||
<button id="zoomOut" class="toolbarButton zoomOut" title="Zoom Out" tabindex="10" data-l10n-id="zoom_out">
|
||||
<button id="zoomOut" class="toolbarButton zoomOut" title="Zoom Out" tabindex="21" data-l10n-id="zoom_out">
|
||||
<span data-l10n-id="zoom_out_label">Zoom Out</span>
|
||||
</button>
|
||||
<div class="splitToolbarButtonSeparator"></div>
|
||||
<button id="zoomIn" class="toolbarButton zoomIn" title="Zoom In" tabindex="11" data-l10n-id="zoom_in">
|
||||
<button id="zoomIn" class="toolbarButton zoomIn" title="Zoom In" tabindex="22" data-l10n-id="zoom_in">
|
||||
<span data-l10n-id="zoom_in_label">Zoom In</span>
|
||||
</button>
|
||||
</div>
|
||||
<span id="scaleSelectContainer" class="dropdownToolbarButton">
|
||||
<select id="scaleSelect" title="Zoom" tabindex="12" data-l10n-id="zoom">
|
||||
<select id="scaleSelect" title="Zoom" tabindex="23" data-l10n-id="zoom">
|
||||
<option id="pageAutoOption" title="" value="auto" selected="selected" data-l10n-id="page_scale_auto">Automatic Zoom</option>
|
||||
<option id="pageActualOption" title="" value="page-actual" data-l10n-id="page_scale_actual">Actual Size</option>
|
||||
<option id="pageFitOption" title="" value="page-fit" data-l10n-id="page_scale_fit">Fit Page</option>
|
||||
|
@ -28,7 +28,7 @@ var DEFAULT_URL = 'compressed.tracemonkey-pldi-09.pdf';
|
||||
var DEFAULT_SCALE = 'auto';
|
||||
var DEFAULT_SCALE_DELTA = 1.1;
|
||||
var UNKNOWN_SCALE = 0;
|
||||
var CACHE_SIZE = 10;
|
||||
var DEFAULT_CACHE_SIZE = 10;
|
||||
var CSS_UNITS = 96.0 / 72.0;
|
||||
var SCROLLBAR_PADDING = 40;
|
||||
var VERTICAL_PADDING = 5;
|
||||
@ -301,6 +301,12 @@ var Cache = function cacheCache(size) {
|
||||
data.shift().destroy();
|
||||
}
|
||||
};
|
||||
this.resize = function (newSize) {
|
||||
size = newSize;
|
||||
while (data.length > size) {
|
||||
data.shift().destroy();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -585,7 +591,7 @@ Preferences._readFromStorage = function (prefObj) {
|
||||
|
||||
|
||||
|
||||
var cache = new Cache(CACHE_SIZE);
|
||||
var cache = new Cache(DEFAULT_CACHE_SIZE);
|
||||
var currentPageNumber = 1;
|
||||
|
||||
|
||||
@ -844,45 +850,41 @@ var PDFFindBar = {
|
||||
|
||||
var PDFFindController = {
|
||||
startedTextExtraction: false,
|
||||
|
||||
extractTextPromises: [],
|
||||
|
||||
pendingFindMatches: {},
|
||||
|
||||
// If active, find results will be highlighted.
|
||||
active: false,
|
||||
|
||||
// Stores the text for each page.
|
||||
pageContents: [],
|
||||
|
||||
active: false, // If active, find results will be highlighted.
|
||||
pageContents: [], // Stores the text for each page.
|
||||
pageMatches: [],
|
||||
|
||||
// Currently selected match.
|
||||
selected: {
|
||||
selected: { // Currently selected match.
|
||||
pageIdx: -1,
|
||||
matchIdx: -1
|
||||
},
|
||||
|
||||
// Where find algorithm currently is in the document.
|
||||
offset: {
|
||||
offset: { // Where the find algorithm currently is in the document.
|
||||
pageIdx: null,
|
||||
matchIdx: null
|
||||
},
|
||||
|
||||
resumePageIdx: null,
|
||||
|
||||
state: null,
|
||||
|
||||
dirtyMatch: false,
|
||||
|
||||
findTimeout: null,
|
||||
|
||||
pdfPageSource: null,
|
||||
|
||||
integratedFind: false,
|
||||
charactersToNormalize: {
|
||||
'\u2018': '\'', // Left single quotation mark
|
||||
'\u2019': '\'', // Right single quotation mark
|
||||
'\u201A': '\'', // Single low-9 quotation mark
|
||||
'\u201B': '\'', // Single high-reversed-9 quotation mark
|
||||
'\u201C': '"', // Left double quotation mark
|
||||
'\u201D': '"', // Right double quotation mark
|
||||
'\u201E': '"', // Double low-9 quotation mark
|
||||
'\u201F': '"', // Double high-reversed-9 quotation mark
|
||||
'\u00BC': '1/4', // Vulgar fraction one quarter
|
||||
'\u00BD': '1/2', // Vulgar fraction one half
|
||||
'\u00BE': '3/4' // Vulgar fraction three quarters
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
if(typeof PDFFindBar === 'undefined' || PDFFindBar === null) {
|
||||
if (typeof PDFFindBar === 'undefined' || PDFFindBar === null) {
|
||||
throw 'PDFFindController cannot be initialized ' +
|
||||
'without a PDFFindBar instance';
|
||||
}
|
||||
@ -890,6 +892,10 @@ var PDFFindController = {
|
||||
this.pdfPageSource = options.pdfPageSource;
|
||||
this.integratedFind = options.integratedFind;
|
||||
|
||||
// Compile the regular expression for text normalization once
|
||||
var replace = Object.keys(this.charactersToNormalize).join('');
|
||||
this.normalizationRegex = new RegExp('[' + replace + ']', 'g');
|
||||
|
||||
var events = [
|
||||
'find',
|
||||
'findagain',
|
||||
@ -902,7 +908,7 @@ var PDFFindController = {
|
||||
}.bind(this));
|
||||
this.handleEvent = this.handleEvent.bind(this);
|
||||
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
for (var i = 0, len = events.length; i < len; i++) {
|
||||
window.addEventListener(events[i], this.handleEvent);
|
||||
}
|
||||
},
|
||||
@ -913,14 +919,20 @@ var PDFFindController = {
|
||||
this.active = false;
|
||||
},
|
||||
|
||||
normalize: function pdfFindControllerNormalize(text) {
|
||||
return text.replace(this.normalizationRegex, function (ch) {
|
||||
return PDFFindController.charactersToNormalize[ch];
|
||||
});
|
||||
},
|
||||
|
||||
calcFindMatch: function(pageIndex) {
|
||||
var pageContent = this.pageContents[pageIndex];
|
||||
var query = this.state.query;
|
||||
var pageContent = this.normalize(this.pageContents[pageIndex]);
|
||||
var query = this.normalize(this.state.query);
|
||||
var caseSensitive = this.state.caseSensitive;
|
||||
var queryLen = query.length;
|
||||
|
||||
if (queryLen === 0) {
|
||||
// Do nothing the matches should be wiped out already.
|
||||
// Do nothing: the matches should be wiped out already.
|
||||
return;
|
||||
}
|
||||
|
||||
@ -930,14 +942,12 @@ var PDFFindController = {
|
||||
}
|
||||
|
||||
var matches = [];
|
||||
|
||||
var matchIdx = -queryLen;
|
||||
while (true) {
|
||||
matchIdx = pageContent.indexOf(query, matchIdx + queryLen);
|
||||
if (matchIdx === -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
matches.push(matchIdx);
|
||||
}
|
||||
this.pageMatches[pageIndex] = matches;
|
||||
@ -956,7 +966,8 @@ var PDFFindController = {
|
||||
|
||||
this.pageContents = [];
|
||||
var extractTextPromisesResolves = [];
|
||||
for (var i = 0, ii = this.pdfPageSource.pdfDocument.numPages; i < ii; i++) {
|
||||
var numPages = this.pdfPageSource.pdfDocument.numPages;
|
||||
for (var i = 0; i < numPages; i++) {
|
||||
this.extractTextPromises.push(new Promise(function (resolve) {
|
||||
extractTextPromisesResolves.push(resolve);
|
||||
}));
|
||||
@ -967,14 +978,14 @@ var PDFFindController = {
|
||||
self.pdfPageSource.pages[pageIndex].getTextContent().then(
|
||||
function textContentResolved(textContent) {
|
||||
var textItems = textContent.items;
|
||||
var str = '';
|
||||
var str = [];
|
||||
|
||||
for (var i = 0; i < textItems.length; i++) {
|
||||
str += textItems[i].str;
|
||||
for (var i = 0, len = textItems.length; i < len; i++) {
|
||||
str.push(textItems[i].str);
|
||||
}
|
||||
|
||||
// Store the pageContent as a string.
|
||||
self.pageContents.push(str);
|
||||
self.pageContents.push(str.join(''));
|
||||
|
||||
extractTextPromisesResolves[pageIndex](pageIndex);
|
||||
if ((pageIndex + 1) < self.pdfPageSource.pages.length) {
|
||||
@ -1072,15 +1083,16 @@ var PDFFindController = {
|
||||
var numPageMatches = this.pageMatches[offset.pageIdx].length;
|
||||
if ((!previous && offset.matchIdx + 1 < numPageMatches) ||
|
||||
(previous && offset.matchIdx > 0)) {
|
||||
// The simple case, we just have advance the matchIdx to select the next
|
||||
// match on the page.
|
||||
// The simple case; we just have advance the matchIdx to select
|
||||
// the next match on the page.
|
||||
this.hadMatch = true;
|
||||
offset.matchIdx = previous ? offset.matchIdx - 1 : offset.matchIdx + 1;
|
||||
offset.matchIdx = (previous ? offset.matchIdx - 1 :
|
||||
offset.matchIdx + 1);
|
||||
this.updateMatch(true);
|
||||
return;
|
||||
}
|
||||
// We went beyond the current page's matches, so we advance to the next
|
||||
// page.
|
||||
// We went beyond the current page's matches, so we advance to
|
||||
// the next page.
|
||||
this.advanceOffsetPage(previous);
|
||||
}
|
||||
// Start searching through the page.
|
||||
@ -1094,24 +1106,23 @@ var PDFFindController = {
|
||||
if (numMatches) {
|
||||
// There were matches for the page, so initialize the matchIdx.
|
||||
this.hadMatch = true;
|
||||
offset.matchIdx = previous ? numMatches - 1 : 0;
|
||||
offset.matchIdx = (previous ? numMatches - 1 : 0);
|
||||
this.updateMatch(true);
|
||||
// matches were found
|
||||
return true;
|
||||
} else {
|
||||
// No matches attempt to search the next page.
|
||||
// No matches, so attempt to search the next page.
|
||||
this.advanceOffsetPage(previous);
|
||||
if (offset.wrapped) {
|
||||
offset.matchIdx = null;
|
||||
if (!this.hadMatch) {
|
||||
// No point in wrapping there were no matches.
|
||||
// No point in wrapping, there were no matches.
|
||||
this.updateMatch(false);
|
||||
// while matches were not found, searching for a page
|
||||
// with matches should nevertheless halt.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// matches were not found (and searching is not done)
|
||||
// Matches were not found (and searching is not done).
|
||||
return false;
|
||||
}
|
||||
},
|
||||
@ -1135,10 +1146,10 @@ var PDFFindController = {
|
||||
advanceOffsetPage: function(previous) {
|
||||
var offset = this.offset;
|
||||
var numPages = this.extractTextPromises.length;
|
||||
offset.pageIdx = previous ? offset.pageIdx - 1 : offset.pageIdx + 1;
|
||||
offset.pageIdx = (previous ? offset.pageIdx - 1 : offset.pageIdx + 1);
|
||||
offset.matchIdx = null;
|
||||
if (offset.pageIdx >= numPages || offset.pageIdx < 0) {
|
||||
offset.pageIdx = previous ? numPages - 1 : 0;
|
||||
offset.pageIdx = (previous ? numPages - 1 : 0);
|
||||
offset.wrapped = true;
|
||||
return;
|
||||
}
|
||||
@ -1152,7 +1163,7 @@ var PDFFindController = {
|
||||
var previousPage = this.selected.pageIdx;
|
||||
this.selected.pageIdx = this.offset.pageIdx;
|
||||
this.selected.matchIdx = this.offset.matchIdx;
|
||||
state = wrapped ? FindStates.FIND_WRAPPED : FindStates.FIND_FOUND;
|
||||
state = (wrapped ? FindStates.FIND_WRAPPED : FindStates.FIND_FOUND);
|
||||
// Update the currently selected page to wipe out any selected matches.
|
||||
if (previousPage !== -1 && previousPage !== this.selected.pageIdx) {
|
||||
this.updatePage(previousPage);
|
||||
@ -1167,7 +1178,7 @@ var PDFFindController = {
|
||||
updateUIState: function(state, previous) {
|
||||
if (this.integratedFind) {
|
||||
FirefoxCom.request('updateFindControlState',
|
||||
{result: state, findPrevious: previous});
|
||||
{ result: state, findPrevious: previous });
|
||||
return;
|
||||
}
|
||||
PDFFindBar.updateUIState(state, previous);
|
||||
@ -2532,6 +2543,7 @@ var PDFView = {
|
||||
fellback: false,
|
||||
pdfDocument: null,
|
||||
sidebarOpen: false,
|
||||
printing: false,
|
||||
pageViewScroll: null,
|
||||
thumbnailViewScroll: null,
|
||||
pageRotation: 0,
|
||||
@ -3599,6 +3611,11 @@ var PDFView = {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.printing) {
|
||||
// If printing is currently ongoing do not reschedule cleanup.
|
||||
return;
|
||||
}
|
||||
|
||||
PDFView.idleTimeout = setTimeout(function () {
|
||||
PDFView.cleanup();
|
||||
}, CLEANUP_TIMEOUT);
|
||||
@ -3908,11 +3925,18 @@ var PDFView = {
|
||||
return;
|
||||
}
|
||||
|
||||
this.printing = true;
|
||||
this.renderHighestPriority();
|
||||
|
||||
var body = document.querySelector('body');
|
||||
body.setAttribute('data-mozPrintCallback', true);
|
||||
for (i = 0, ii = this.pages.length; i < ii; ++i) {
|
||||
this.pages[i].beforePrint();
|
||||
}
|
||||
|
||||
FirefoxCom.request('reportTelemetry', JSON.stringify({
|
||||
type: 'print'
|
||||
}));
|
||||
},
|
||||
|
||||
afterPrint: function pdfViewSetupAfterPrint() {
|
||||
@ -3920,6 +3944,9 @@ var PDFView = {
|
||||
while (div.hasChildNodes()) {
|
||||
div.removeChild(div.lastChild);
|
||||
}
|
||||
|
||||
this.printing = false;
|
||||
this.renderHighestPriority();
|
||||
},
|
||||
|
||||
rotatePages: function pdfViewRotatePages(delta) {
|
||||
@ -4317,16 +4344,15 @@ var PageView = function pageView(container, id, scale,
|
||||
} else {
|
||||
for (i = 0, ii = annotationsData.length; i < ii; i++) {
|
||||
data = annotationsData[i];
|
||||
var annotation = PDFJS.Annotation.fromData(data);
|
||||
if (!annotation || !annotation.hasHtml()) {
|
||||
if (!data || !data.hasHtml) {
|
||||
continue;
|
||||
}
|
||||
|
||||
element = annotation.getHtmlElement(pdfPage.commonObjs);
|
||||
element = PDFJS.AnnotationUtils.getHtmlElement(data,
|
||||
pdfPage.commonObjs);
|
||||
element.setAttribute('data-annotation-id', data.id);
|
||||
mozL10n.translate(element);
|
||||
|
||||
data = annotation.getData();
|
||||
var rect = data.rect;
|
||||
var view = pdfPage.view;
|
||||
rect = PDFJS.Util.normalizeRect([
|
||||
@ -4622,7 +4648,13 @@ var PageView = function pageView(container, id, scale,
|
||||
FirefoxCom.request('reportTelemetry', JSON.stringify({
|
||||
type: 'pageInfo'
|
||||
}));
|
||||
// TODO add stream types report here
|
||||
// It is a good time to report stream and font types
|
||||
PDFView.pdfDocument.getStats().then(function (stats) {
|
||||
FirefoxCom.request('reportTelemetry', JSON.stringify({
|
||||
type: 'documentStats',
|
||||
stats: stats
|
||||
}));
|
||||
});
|
||||
callback();
|
||||
}
|
||||
|
||||
@ -4955,335 +4987,311 @@ ThumbnailView.tempImageCache = null;
|
||||
|
||||
var FIND_SCROLL_OFFSET_TOP = -50;
|
||||
var FIND_SCROLL_OFFSET_LEFT = -400;
|
||||
var MAX_TEXT_DIVS_TO_RENDER = 100000;
|
||||
var RENDER_DELAY = 200; // ms
|
||||
|
||||
/**
|
||||
* TextLayerBuilder provides text-selection
|
||||
* functionality for the PDF. It does this
|
||||
* by creating overlay divs over the PDF
|
||||
* text. This divs contain text that matches
|
||||
* the PDF text they are overlaying. This
|
||||
* object also provides for a way to highlight
|
||||
* text that is being searched for.
|
||||
* TextLayerBuilder provides text-selection functionality for the PDF.
|
||||
* It does this by creating overlay divs over the PDF text. These divs
|
||||
* contain text that matches the PDF text they are overlaying. This object
|
||||
* also provides a way to highlight text that is being searched for.
|
||||
*/
|
||||
var TextLayerBuilder = function textLayerBuilder(options) {
|
||||
var textLayerFrag = document.createDocumentFragment();
|
||||
|
||||
this.textLayerDiv = options.textLayerDiv;
|
||||
this.layoutDone = false;
|
||||
this.divContentDone = false;
|
||||
this.pageIdx = options.pageIndex;
|
||||
this.matches = [];
|
||||
this.lastScrollSource = options.lastScrollSource;
|
||||
this.viewport = options.viewport;
|
||||
this.isViewerInPresentationMode = options.isViewerInPresentationMode;
|
||||
this.textDivs = [];
|
||||
|
||||
if (typeof PDFFindController === 'undefined') {
|
||||
window.PDFFindController = null;
|
||||
var TextLayerBuilder = (function TextLayerBuilderClosure() {
|
||||
function TextLayerBuilder(options) {
|
||||
this.textLayerDiv = options.textLayerDiv;
|
||||
this.layoutDone = false;
|
||||
this.divContentDone = false;
|
||||
this.pageIdx = options.pageIndex;
|
||||
this.matches = [];
|
||||
this.lastScrollSource = options.lastScrollSource || null;
|
||||
this.viewport = options.viewport;
|
||||
this.isViewerInPresentationMode = options.isViewerInPresentationMode;
|
||||
this.textDivs = [];
|
||||
this.findController = window.PDFFindController || null;
|
||||
}
|
||||
|
||||
if (typeof this.lastScrollSource === 'undefined') {
|
||||
this.lastScrollSource = null;
|
||||
}
|
||||
TextLayerBuilder.prototype = {
|
||||
renderLayer: function TextLayerBuilder_renderLayer() {
|
||||
var textLayerFrag = document.createDocumentFragment();
|
||||
var textDivs = this.textDivs;
|
||||
var textDivsLength = textDivs.length;
|
||||
var canvas = document.createElement('canvas');
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
this.renderLayer = function textLayerBuilderRenderLayer() {
|
||||
var textDivs = this.textDivs;
|
||||
var canvas = document.createElement('canvas');
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
// No point in rendering so many divs as it'd make the browser unusable
|
||||
// even after the divs are rendered
|
||||
var MAX_TEXT_DIVS_TO_RENDER = 100000;
|
||||
if (textDivs.length > MAX_TEXT_DIVS_TO_RENDER) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0, ii = textDivs.length; i < ii; i++) {
|
||||
var textDiv = textDivs[i];
|
||||
if ('isWhitespace' in textDiv.dataset) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ctx.font = textDiv.style.fontSize + ' ' + textDiv.style.fontFamily;
|
||||
var width = ctx.measureText(textDiv.textContent).width;
|
||||
|
||||
if (width > 0) {
|
||||
textLayerFrag.appendChild(textDiv);
|
||||
var textScale = textDiv.dataset.canvasWidth / width;
|
||||
var rotation = textDiv.dataset.angle;
|
||||
var transform = 'scale(' + textScale + ', 1)';
|
||||
transform = 'rotate(' + rotation + 'deg) ' + transform;
|
||||
CustomStyle.setProp('transform' , textDiv, transform);
|
||||
CustomStyle.setProp('transformOrigin' , textDiv, '0% 0%');
|
||||
}
|
||||
}
|
||||
|
||||
this.textLayerDiv.appendChild(textLayerFrag);
|
||||
this.renderingDone = true;
|
||||
this.updateMatches();
|
||||
};
|
||||
|
||||
this.setupRenderLayoutTimer = function textLayerSetupRenderLayoutTimer() {
|
||||
// Schedule renderLayout() if user has been scrolling, otherwise
|
||||
// run it right away
|
||||
var RENDER_DELAY = 200; // in ms
|
||||
var self = this;
|
||||
var lastScroll = (this.lastScrollSource === null ?
|
||||
0 : this.lastScrollSource.lastScroll);
|
||||
|
||||
if (Date.now() - lastScroll > RENDER_DELAY) {
|
||||
// Render right away
|
||||
this.renderLayer();
|
||||
} else {
|
||||
// Schedule
|
||||
if (this.renderTimer) {
|
||||
clearTimeout(this.renderTimer);
|
||||
}
|
||||
this.renderTimer = setTimeout(function() {
|
||||
self.setupRenderLayoutTimer();
|
||||
}, RENDER_DELAY);
|
||||
}
|
||||
};
|
||||
|
||||
this.appendText = function textLayerBuilderAppendText(geom, styles) {
|
||||
var style = styles[geom.fontName];
|
||||
var textDiv = document.createElement('div');
|
||||
this.textDivs.push(textDiv);
|
||||
if (!/\S/.test(geom.str)) {
|
||||
textDiv.dataset.isWhitespace = true;
|
||||
return;
|
||||
}
|
||||
var tx = PDFJS.Util.transform(this.viewport.transform, geom.transform);
|
||||
var angle = Math.atan2(tx[1], tx[0]);
|
||||
if (style.vertical) {
|
||||
angle += Math.PI / 2;
|
||||
}
|
||||
var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
|
||||
var fontAscent = (style.ascent ? style.ascent * fontHeight :
|
||||
(style.descent ? (1 + style.descent) * fontHeight : fontHeight));
|
||||
|
||||
textDiv.style.position = 'absolute';
|
||||
textDiv.style.left = (tx[4] + (fontAscent * Math.sin(angle))) + 'px';
|
||||
textDiv.style.top = (tx[5] - (fontAscent * Math.cos(angle))) + 'px';
|
||||
textDiv.style.fontSize = fontHeight + 'px';
|
||||
textDiv.style.fontFamily = style.fontFamily;
|
||||
|
||||
textDiv.textContent = geom.str;
|
||||
textDiv.dataset.fontName = geom.fontName;
|
||||
textDiv.dataset.angle = angle * (180 / Math.PI);
|
||||
if (style.vertical) {
|
||||
textDiv.dataset.canvasWidth = geom.height * this.viewport.scale;
|
||||
} else {
|
||||
textDiv.dataset.canvasWidth = geom.width * this.viewport.scale;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.setTextContent = function textLayerBuilderSetTextContent(textContent) {
|
||||
this.textContent = textContent;
|
||||
|
||||
var textItems = textContent.items;
|
||||
for (var i = 0; i < textItems.length; i++) {
|
||||
this.appendText(textItems[i], textContent.styles);
|
||||
}
|
||||
this.divContentDone = true;
|
||||
|
||||
this.setupRenderLayoutTimer();
|
||||
};
|
||||
|
||||
this.convertMatches = function textLayerBuilderConvertMatches(matches) {
|
||||
var i = 0;
|
||||
var iIndex = 0;
|
||||
var bidiTexts = this.textContent.items;
|
||||
var end = bidiTexts.length - 1;
|
||||
var queryLen = (PDFFindController === null ?
|
||||
0 : PDFFindController.state.query.length);
|
||||
|
||||
var ret = [];
|
||||
|
||||
// Loop over all the matches.
|
||||
for (var m = 0; m < matches.length; m++) {
|
||||
var matchIdx = matches[m];
|
||||
// # Calculate the begin position.
|
||||
|
||||
// Loop over the divIdxs.
|
||||
while (i !== end && matchIdx >= (iIndex + bidiTexts[i].str.length)) {
|
||||
iIndex += bidiTexts[i].str.length;
|
||||
i++;
|
||||
}
|
||||
|
||||
// TODO: Do proper handling here if something goes wrong.
|
||||
if (i == bidiTexts.length) {
|
||||
console.error('Could not find matching mapping');
|
||||
}
|
||||
|
||||
var match = {
|
||||
begin: {
|
||||
divIdx: i,
|
||||
offset: matchIdx - iIndex
|
||||
}
|
||||
};
|
||||
|
||||
// # Calculate the end position.
|
||||
matchIdx += queryLen;
|
||||
|
||||
// Somewhat same array as above, but use a > instead of >= to get the end
|
||||
// position right.
|
||||
while (i !== end && matchIdx > (iIndex + bidiTexts[i].str.length)) {
|
||||
iIndex += bidiTexts[i].str.length;
|
||||
i++;
|
||||
}
|
||||
|
||||
match.end = {
|
||||
divIdx: i,
|
||||
offset: matchIdx - iIndex
|
||||
};
|
||||
ret.push(match);
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
this.renderMatches = function textLayerBuilder_renderMatches(matches) {
|
||||
// Early exit if there is nothing to render.
|
||||
if (matches.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var bidiTexts = this.textContent.items;
|
||||
var textDivs = this.textDivs;
|
||||
var prevEnd = null;
|
||||
var isSelectedPage = (PDFFindController === null ?
|
||||
false : (this.pageIdx === PDFFindController.selected.pageIdx));
|
||||
|
||||
var selectedMatchIdx = (PDFFindController === null ?
|
||||
-1 : PDFFindController.selected.matchIdx);
|
||||
|
||||
var highlightAll = (PDFFindController === null ?
|
||||
false : PDFFindController.state.highlightAll);
|
||||
|
||||
var infty = {
|
||||
divIdx: -1,
|
||||
offset: undefined
|
||||
};
|
||||
|
||||
function beginText(begin, className) {
|
||||
var divIdx = begin.divIdx;
|
||||
var div = textDivs[divIdx];
|
||||
div.textContent = '';
|
||||
appendTextToDiv(divIdx, 0, begin.offset, className);
|
||||
}
|
||||
|
||||
function appendText(from, to, className) {
|
||||
appendTextToDiv(from.divIdx, from.offset, to.offset, className);
|
||||
}
|
||||
|
||||
function appendTextToDiv(divIdx, fromOffset, toOffset, className) {
|
||||
var div = textDivs[divIdx];
|
||||
|
||||
var content = bidiTexts[divIdx].str.substring(fromOffset, toOffset);
|
||||
var node = document.createTextNode(content);
|
||||
if (className) {
|
||||
var span = document.createElement('span');
|
||||
span.className = className;
|
||||
span.appendChild(node);
|
||||
div.appendChild(span);
|
||||
// No point in rendering many divs as it would make the browser
|
||||
// unusable even after the divs are rendered.
|
||||
if (textDivsLength > MAX_TEXT_DIVS_TO_RENDER) {
|
||||
return;
|
||||
}
|
||||
div.appendChild(node);
|
||||
}
|
||||
|
||||
function highlightDiv(divIdx, className) {
|
||||
textDivs[divIdx].className = className;
|
||||
}
|
||||
|
||||
var i0 = selectedMatchIdx, i1 = i0 + 1, i;
|
||||
|
||||
if (highlightAll) {
|
||||
i0 = 0;
|
||||
i1 = matches.length;
|
||||
} else if (!isSelectedPage) {
|
||||
// Not highlighting all and this isn't the selected page, so do nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = i0; i < i1; i++) {
|
||||
var match = matches[i];
|
||||
var begin = match.begin;
|
||||
var end = match.end;
|
||||
|
||||
var isSelected = isSelectedPage && i === selectedMatchIdx;
|
||||
var highlightSuffix = (isSelected ? ' selected' : '');
|
||||
if (isSelected && !this.isViewerInPresentationMode) {
|
||||
scrollIntoView(textDivs[begin.divIdx], { top: FIND_SCROLL_OFFSET_TOP,
|
||||
left: FIND_SCROLL_OFFSET_LEFT });
|
||||
}
|
||||
|
||||
// Match inside new div.
|
||||
if (!prevEnd || begin.divIdx !== prevEnd.divIdx) {
|
||||
// If there was a previous div, then add the text at the end
|
||||
if (prevEnd !== null) {
|
||||
appendText(prevEnd, infty);
|
||||
for (var i = 0; i < textDivsLength; i++) {
|
||||
var textDiv = textDivs[i];
|
||||
if (textDiv.dataset.isWhitespace !== undefined) {
|
||||
continue;
|
||||
}
|
||||
// clears the divs and set the content until the begin point.
|
||||
beginText(begin);
|
||||
} else {
|
||||
appendText(prevEnd, begin);
|
||||
}
|
||||
|
||||
if (begin.divIdx === end.divIdx) {
|
||||
appendText(begin, end, 'highlight' + highlightSuffix);
|
||||
} else {
|
||||
appendText(begin, infty, 'highlight begin' + highlightSuffix);
|
||||
for (var n = begin.divIdx + 1; n < end.divIdx; n++) {
|
||||
highlightDiv(n, 'highlight middle' + highlightSuffix);
|
||||
ctx.font = textDiv.style.fontSize + ' ' + textDiv.style.fontFamily;
|
||||
var width = ctx.measureText(textDiv.textContent).width;
|
||||
if (width > 0) {
|
||||
textLayerFrag.appendChild(textDiv);
|
||||
var textScale = textDiv.dataset.canvasWidth / width;
|
||||
var rotation = textDiv.dataset.angle;
|
||||
var transform = 'scale(' + textScale + ', 1)';
|
||||
transform = 'rotate(' + rotation + 'deg) ' + transform;
|
||||
CustomStyle.setProp('transform' , textDiv, transform);
|
||||
CustomStyle.setProp('transformOrigin' , textDiv, '0% 0%');
|
||||
}
|
||||
beginText(end, 'highlight end' + highlightSuffix);
|
||||
}
|
||||
prevEnd = end;
|
||||
}
|
||||
|
||||
if (prevEnd) {
|
||||
appendText(prevEnd, infty);
|
||||
this.textLayerDiv.appendChild(textLayerFrag);
|
||||
this.renderingDone = true;
|
||||
this.updateMatches();
|
||||
},
|
||||
|
||||
setupRenderLayoutTimer:
|
||||
function TextLayerBuilder_setupRenderLayoutTimer() {
|
||||
// Schedule renderLayout() if the user has been scrolling,
|
||||
// otherwise run it right away.
|
||||
var self = this;
|
||||
var lastScroll = (this.lastScrollSource === null ?
|
||||
0 : this.lastScrollSource.lastScroll);
|
||||
|
||||
if (Date.now() - lastScroll > RENDER_DELAY) { // Render right away
|
||||
this.renderLayer();
|
||||
} else { // Schedule
|
||||
if (this.renderTimer) {
|
||||
clearTimeout(this.renderTimer);
|
||||
}
|
||||
this.renderTimer = setTimeout(function() {
|
||||
self.setupRenderLayoutTimer();
|
||||
}, RENDER_DELAY);
|
||||
}
|
||||
},
|
||||
|
||||
appendText: function TextLayerBuilder_appendText(geom, styles) {
|
||||
var style = styles[geom.fontName];
|
||||
var textDiv = document.createElement('div');
|
||||
this.textDivs.push(textDiv);
|
||||
if (!/\S/.test(geom.str)) {
|
||||
textDiv.dataset.isWhitespace = true;
|
||||
return;
|
||||
}
|
||||
var tx = PDFJS.Util.transform(this.viewport.transform, geom.transform);
|
||||
var angle = Math.atan2(tx[1], tx[0]);
|
||||
if (style.vertical) {
|
||||
angle += Math.PI / 2;
|
||||
}
|
||||
var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
|
||||
var fontAscent = (style.ascent ? style.ascent * fontHeight :
|
||||
(style.descent ? (1 + style.descent) * fontHeight : fontHeight));
|
||||
|
||||
textDiv.style.position = 'absolute';
|
||||
textDiv.style.left = (tx[4] + (fontAscent * Math.sin(angle))) + 'px';
|
||||
textDiv.style.top = (tx[5] - (fontAscent * Math.cos(angle))) + 'px';
|
||||
textDiv.style.fontSize = fontHeight + 'px';
|
||||
textDiv.style.fontFamily = style.fontFamily;
|
||||
|
||||
textDiv.textContent = geom.str;
|
||||
textDiv.dataset.fontName = geom.fontName;
|
||||
textDiv.dataset.angle = angle * (180 / Math.PI);
|
||||
if (style.vertical) {
|
||||
textDiv.dataset.canvasWidth = geom.height * this.viewport.scale;
|
||||
} else {
|
||||
textDiv.dataset.canvasWidth = geom.width * this.viewport.scale;
|
||||
}
|
||||
},
|
||||
|
||||
setTextContent: function TextLayerBuilder_setTextContent(textContent) {
|
||||
this.textContent = textContent;
|
||||
|
||||
var textItems = textContent.items;
|
||||
for (var i = 0, len = textItems.length; i < len; i++) {
|
||||
this.appendText(textItems[i], textContent.styles);
|
||||
}
|
||||
this.divContentDone = true;
|
||||
this.setupRenderLayoutTimer();
|
||||
},
|
||||
|
||||
convertMatches: function TextLayerBuilder_convertMatches(matches) {
|
||||
var i = 0;
|
||||
var iIndex = 0;
|
||||
var bidiTexts = this.textContent.items;
|
||||
var end = bidiTexts.length - 1;
|
||||
var queryLen = (this.findController === null ?
|
||||
0 : this.findController.state.query.length);
|
||||
var ret = [];
|
||||
|
||||
for (var m = 0, len = matches.length; m < len; m++) {
|
||||
// Calculate the start position.
|
||||
var matchIdx = matches[m];
|
||||
|
||||
// Loop over the divIdxs.
|
||||
while (i !== end && matchIdx >= (iIndex + bidiTexts[i].str.length)) {
|
||||
iIndex += bidiTexts[i].str.length;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i === bidiTexts.length) {
|
||||
console.error('Could not find a matching mapping');
|
||||
}
|
||||
|
||||
var match = {
|
||||
begin: {
|
||||
divIdx: i,
|
||||
offset: matchIdx - iIndex
|
||||
}
|
||||
};
|
||||
|
||||
// Calculate the end position.
|
||||
matchIdx += queryLen;
|
||||
|
||||
// Somewhat the same array as above, but use > instead of >= to get
|
||||
// the end position right.
|
||||
while (i !== end && matchIdx > (iIndex + bidiTexts[i].str.length)) {
|
||||
iIndex += bidiTexts[i].str.length;
|
||||
i++;
|
||||
}
|
||||
|
||||
match.end = {
|
||||
divIdx: i,
|
||||
offset: matchIdx - iIndex
|
||||
};
|
||||
ret.push(match);
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
renderMatches: function TextLayerBuilder_renderMatches(matches) {
|
||||
// Early exit if there is nothing to render.
|
||||
if (matches.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var bidiTexts = this.textContent.items;
|
||||
var textDivs = this.textDivs;
|
||||
var prevEnd = null;
|
||||
var isSelectedPage = (this.findController === null ?
|
||||
false : (this.pageIdx === this.findController.selected.pageIdx));
|
||||
var selectedMatchIdx = (this.findController === null ?
|
||||
-1 : this.findController.selected.matchIdx);
|
||||
var highlightAll = (this.findController === null ?
|
||||
false : this.findController.state.highlightAll);
|
||||
var infinity = {
|
||||
divIdx: -1,
|
||||
offset: undefined
|
||||
};
|
||||
|
||||
function beginText(begin, className) {
|
||||
var divIdx = begin.divIdx;
|
||||
textDivs[divIdx].textContent = '';
|
||||
appendTextToDiv(divIdx, 0, begin.offset, className);
|
||||
}
|
||||
|
||||
function appendTextToDiv(divIdx, fromOffset, toOffset, className) {
|
||||
var div = textDivs[divIdx];
|
||||
var content = bidiTexts[divIdx].str.substring(fromOffset, toOffset);
|
||||
var node = document.createTextNode(content);
|
||||
if (className) {
|
||||
var span = document.createElement('span');
|
||||
span.className = className;
|
||||
span.appendChild(node);
|
||||
div.appendChild(span);
|
||||
return;
|
||||
}
|
||||
div.appendChild(node);
|
||||
}
|
||||
|
||||
var i0 = selectedMatchIdx, i1 = i0 + 1;
|
||||
if (highlightAll) {
|
||||
i0 = 0;
|
||||
i1 = matches.length;
|
||||
} else if (!isSelectedPage) {
|
||||
// Not highlighting all and this isn't the selected page, so do nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = i0; i < i1; i++) {
|
||||
var match = matches[i];
|
||||
var begin = match.begin;
|
||||
var end = match.end;
|
||||
var isSelected = (isSelectedPage && i === selectedMatchIdx);
|
||||
var highlightSuffix = (isSelected ? ' selected' : '');
|
||||
|
||||
if (isSelected && !this.isViewerInPresentationMode) {
|
||||
scrollIntoView(textDivs[begin.divIdx],
|
||||
{ top: FIND_SCROLL_OFFSET_TOP,
|
||||
left: FIND_SCROLL_OFFSET_LEFT });
|
||||
}
|
||||
|
||||
// Match inside new div.
|
||||
if (!prevEnd || begin.divIdx !== prevEnd.divIdx) {
|
||||
// If there was a previous div, then add the text at the end.
|
||||
if (prevEnd !== null) {
|
||||
appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
|
||||
}
|
||||
// Clear the divs and set the content until the starting point.
|
||||
beginText(begin);
|
||||
} else {
|
||||
appendTextToDiv(prevEnd.divIdx, prevEnd.offset, begin.offset);
|
||||
}
|
||||
|
||||
if (begin.divIdx === end.divIdx) {
|
||||
appendTextToDiv(begin.divIdx, begin.offset, end.offset,
|
||||
'highlight' + highlightSuffix);
|
||||
} else {
|
||||
appendTextToDiv(begin.divIdx, begin.offset, infinity.offset,
|
||||
'highlight begin' + highlightSuffix);
|
||||
for (var n0 = begin.divIdx + 1, n1 = end.divIdx; n0 < n1; n0++) {
|
||||
textDivs[n0].className = 'highlight middle' + highlightSuffix;
|
||||
}
|
||||
beginText(end, 'highlight end' + highlightSuffix);
|
||||
}
|
||||
prevEnd = end;
|
||||
}
|
||||
|
||||
if (prevEnd) {
|
||||
appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
|
||||
}
|
||||
},
|
||||
|
||||
updateMatches: function TextLayerBuilder_updateMatches() {
|
||||
// Only show matches when all rendering is done.
|
||||
if (!this.renderingDone) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear all matches.
|
||||
var matches = this.matches;
|
||||
var textDivs = this.textDivs;
|
||||
var bidiTexts = this.textContent.items;
|
||||
var clearedUntilDivIdx = -1;
|
||||
|
||||
// Clear all current matches.
|
||||
for (var i = 0, len = matches.length; i < len; i++) {
|
||||
var match = matches[i];
|
||||
var begin = Math.max(clearedUntilDivIdx, match.begin.divIdx);
|
||||
for (var n = begin, end = match.end.divIdx; n <= end; n++) {
|
||||
var div = textDivs[n];
|
||||
div.textContent = bidiTexts[n].str;
|
||||
div.className = '';
|
||||
}
|
||||
clearedUntilDivIdx = match.end.divIdx + 1;
|
||||
}
|
||||
|
||||
if (this.findController === null || !this.findController.active) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the matches on the page controller into the match format
|
||||
// used for the textLayer.
|
||||
this.matches = this.convertMatches(this.findController === null ?
|
||||
[] : (this.findController.pageMatches[this.pageIdx] || []));
|
||||
this.renderMatches(this.matches);
|
||||
}
|
||||
};
|
||||
|
||||
this.updateMatches = function textLayerUpdateMatches() {
|
||||
// Only show matches, once all rendering is done.
|
||||
if (!this.renderingDone) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear out all matches.
|
||||
var matches = this.matches;
|
||||
var textDivs = this.textDivs;
|
||||
var bidiTexts = this.textContent.items;
|
||||
var clearedUntilDivIdx = -1;
|
||||
|
||||
// Clear out all current matches.
|
||||
for (var i = 0; i < matches.length; i++) {
|
||||
var match = matches[i];
|
||||
var begin = Math.max(clearedUntilDivIdx, match.begin.divIdx);
|
||||
for (var n = begin; n <= match.end.divIdx; n++) {
|
||||
var div = textDivs[n];
|
||||
div.textContent = bidiTexts[n].str;
|
||||
div.className = '';
|
||||
}
|
||||
clearedUntilDivIdx = match.end.divIdx + 1;
|
||||
}
|
||||
|
||||
if (PDFFindController === null || !PDFFindController.active) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the matches on the page controller into the match format used
|
||||
// for the textLayer.
|
||||
this.matches = matches = (this.convertMatches(PDFFindController === null ?
|
||||
[] : (PDFFindController.pageMatches[this.pageIdx] || [])));
|
||||
|
||||
this.renderMatches(this.matches);
|
||||
};
|
||||
};
|
||||
return TextLayerBuilder;
|
||||
})();
|
||||
|
||||
|
||||
|
||||
@ -5584,6 +5592,10 @@ function updateViewarea() {
|
||||
return;
|
||||
}
|
||||
|
||||
var suggestedCacheSize = Math.max(DEFAULT_CACHE_SIZE,
|
||||
2 * visiblePages.length + 1);
|
||||
cache.resize(suggestedCacheSize);
|
||||
|
||||
PDFView.renderHighestPriority(visible);
|
||||
|
||||
var currentId = PDFView.page;
|
||||
|
@ -43,6 +43,10 @@ toolbox.label=Developer Tools
|
||||
# for the options panel tab.
|
||||
optionsButton.tooltip=Toolbox Options
|
||||
|
||||
# LOCALIZATION NOTE (options.label): This is used as the label of the tab in
|
||||
# the devtools window.
|
||||
options.label=Options
|
||||
|
||||
# LOCALIZATION NOTE (options.panelLabel): This is used as the label for the
|
||||
# toolbox panel.
|
||||
options.panelLabel=Toolbox Options Panel
|
||||
|
@ -3,95 +3,71 @@
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px" y="0px"
|
||||
viewBox="0 0 16 16"
|
||||
enable-background="new 0 0 16 16"
|
||||
xml:space="preserve">
|
||||
<style>
|
||||
g:not(:target) {
|
||||
use:not(:target) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
path {
|
||||
use {
|
||||
fill: menutext;
|
||||
}
|
||||
|
||||
g.active > path {
|
||||
use[id$="-active"] {
|
||||
fill: -moz-menuhovertext;
|
||||
}
|
||||
|
||||
use[id$="-disabled"] {
|
||||
fill: graytext;
|
||||
}
|
||||
</style>
|
||||
<g id="back">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159
|
||||
<defs style="display:none">
|
||||
<path id="back-shape" fill-rule="evenodd" clip-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159
|
||||
l5.199,5.301c0.607,0.63,1.465,0.764,1.915,0.297l1.02-1.082c0.449-0.467,0.32-1.357-0.288-1.99l-2.116-2.158h5.705
|
||||
c0.671,0,1.215-0.544,1.215-1.215v-2.43c0-0.671-0.544-1.215-1.215-1.215H8.094l2.271-2.309c0.609-0.626,0.737-1.512,0.288-1.974
|
||||
L9.635,0.278C9.184-0.188,8.327-0.055,7.718,0.575L2.479,5.901C2.38,5.946,2.289,6.008,2.21,6.089L1.192,7.171
|
||||
c-0.21,0.219-0.293,0.53-0.26,0.864C0.899,8.367,0.981,8.676,1.192,8.893z"/>
|
||||
</g>
|
||||
<g id="forward">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159
|
||||
<path id="forward-shape" fill-rule="evenodd" clip-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159
|
||||
L8.377,0.576C7.77-0.054,6.912-0.189,6.461,0.278L5.441,1.36c-0.449,0.467-0.32,1.357,0.288,1.99l2.116,2.158H2.14
|
||||
c-0.671,0-1.215,0.544-1.215,1.215v2.43c0,0.671,0.544,1.215,1.215,1.215h5.765l-2.271,2.309c-0.609,0.626-0.737,1.512-0.288,1.974
|
||||
l1.019,1.072c0.451,0.465,1.308,0.332,1.917-0.297l5.238-5.326c0.1-0.045,0.191-0.107,0.269-0.188l1.019-1.082
|
||||
c0.21-0.219,0.293-0.53,0.26-0.864C15.101,7.633,15.019,7.324,14.808,7.107z"/>
|
||||
</g>
|
||||
<g id="reload">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947
|
||||
<path id="reload-shape" fill-rule="evenodd" clip-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947
|
||||
c-2.554,0-4.625,2.071-4.625,4.625S5.446,13.196,8,13.196c1.638,0,3.069-0.857,3.891-2.141l2.576,1.104
|
||||
C13.199,14.439,10.794,16,8,16c-4.103,0-7.429-3.326-7.429-7.429S3.897,1.143,8,1.143c1.762,0,3.366,0.624,4.631,1.654L15.429,0V8z"/>
|
||||
</g>
|
||||
<g id="stop">
|
||||
<polygon fill-rule="evenodd" clip-rule="evenodd" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669
|
||||
<polygon id="stop-shape" fill-rule="evenodd" clip-rule="evenodd" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669
|
||||
5.377,8.059 0.157,13.292 2.819,15.961 8.039,10.728 13.298,16 15.959,13.331 10.701,8.06"/>
|
||||
</g>
|
||||
<g id="bookmark">
|
||||
<path d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967
|
||||
<path id="bookmark-shape" d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967
|
||||
L10.896,13l-1.959-1.039l-0.937-0.497l-0.937,0.497l-1.957,1.038L5.468,10.6l0.146-0.968L4.937,8.924L3.219,7.126l2.351-0.39
|
||||
l1.023-0.17l0.45-0.934L8.008,3.632 M8,0C7.72,0,7.44,0.217,7.228,0.65L5.242,4.766L0.907,5.485c-0.958,0.159-1.195,0.861-0.53,1.56
|
||||
l3.113,3.258l-0.69,4.583c-0.105,0.689,0.172,1.092,0.658,1.092c0.185,0,0.399-0.058,0.635-0.181l3.906-2.072l3.906,2.072
|
||||
c0.236,0.123,0.45,0.181,0.635,0.181c0.486,0,0.762-0.403,0.659-1.092l-0.687-4.583l3.109-3.255c0.666-0.702,0.428-1.404-0.53-1.564
|
||||
l-4.303-0.719L8.772,0.65C8.56,0.217,8.28,0,8,0L8,0z"/>
|
||||
</g>
|
||||
<g id="bookmark-starred">
|
||||
<path d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562
|
||||
<path id="bookmarked-shape" d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562
|
||||
l3.124,3.262l-0.692,4.589C2.679,15.596,2.957,16,3.444,16c0.185,0,0.401-0.058,0.637-0.181L8,13.744l3.919,2.075
|
||||
C12.156,15.942,12.372,16,12.557,16c0.487,0,0.764-0.404,0.661-1.094l-0.69-4.589l3.12-3.259c0.668-0.703,0.43-1.406-0.532-1.566
|
||||
l-4.317-0.72L8.775,0.651C8.562,0.217,8.281,0,8,0L8,0z"/>
|
||||
</g>
|
||||
<g id="back-active" class="active">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159
|
||||
l5.199,5.301c0.607,0.63,1.465,0.764,1.915,0.297l1.02-1.082c0.449-0.467,0.32-1.357-0.288-1.99l-2.116-2.158h5.705
|
||||
c0.671,0,1.215-0.544,1.215-1.215v-2.43c0-0.671-0.544-1.215-1.215-1.215H8.094l2.271-2.309c0.609-0.626,0.737-1.512,0.288-1.974
|
||||
L9.635,0.278C9.184-0.188,8.327-0.055,7.718,0.575L2.479,5.901C2.38,5.946,2.289,6.008,2.21,6.089L1.192,7.171
|
||||
c-0.21,0.219-0.293,0.53-0.26,0.864C0.899,8.367,0.981,8.676,1.192,8.893z"/>
|
||||
</g>
|
||||
<g id="forward-active" class="active">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159
|
||||
L8.377,0.576C7.77-0.054,6.912-0.189,6.461,0.278L5.441,1.36c-0.449,0.467-0.32,1.357,0.288,1.99l2.116,2.158H2.14
|
||||
c-0.671,0-1.215,0.544-1.215,1.215v2.43c0,0.671,0.544,1.215,1.215,1.215h5.765l-2.271,2.309c-0.609,0.626-0.737,1.512-0.288,1.974
|
||||
l1.019,1.072c0.451,0.465,1.308,0.332,1.917-0.297l5.238-5.326c0.1-0.045,0.191-0.107,0.269-0.188l1.019-1.082
|
||||
c0.21-0.219,0.293-0.53,0.26-0.864C15.101,7.633,15.019,7.324,14.808,7.107z"/>
|
||||
</g>
|
||||
<g id="reload-active" class="active">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947
|
||||
c-2.554,0-4.625,2.071-4.625,4.625S5.446,13.196,8,13.196c1.638,0,3.069-0.857,3.891-2.141l2.576,1.104
|
||||
C13.199,14.439,10.794,16,8,16c-4.103,0-7.429-3.326-7.429-7.429S3.897,1.143,8,1.143c1.762,0,3.366,0.624,4.631,1.654L15.429,0V8z"/>
|
||||
</g>
|
||||
<g id="stop-active" class="active">
|
||||
<polygon fill-rule="evenodd" clip-rule="evenodd" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669
|
||||
5.377,8.059 0.157,13.292 2.819,15.961 8.039,10.728 13.298,16 15.959,13.331 10.701,8.06"/>
|
||||
</g>
|
||||
<g id="bookmark-active" class="active">
|
||||
<path d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967
|
||||
L10.896,13l-1.959-1.039l-0.937-0.497l-0.937,0.497l-1.957,1.038L5.468,10.6l0.146-0.968L4.937,8.924L3.219,7.126l2.351-0.39
|
||||
l1.023-0.17l0.45-0.934L8.008,3.632 M8,0C7.72,0,7.44,0.217,7.228,0.65L5.242,4.766L0.907,5.485c-0.958,0.159-1.195,0.861-0.53,1.56
|
||||
l3.113,3.258l-0.69,4.583c-0.105,0.689,0.172,1.092,0.658,1.092c0.185,0,0.399-0.058,0.635-0.181l3.906-2.072l3.906,2.072
|
||||
c0.236,0.123,0.45,0.181,0.635,0.181c0.486,0,0.762-0.403,0.659-1.092l-0.687-4.583l3.109-3.255c0.666-0.702,0.428-1.404-0.53-1.564
|
||||
l-4.303-0.719L8.772,0.65C8.56,0.217,8.28,0,8,0L8,0z"/>
|
||||
</g>
|
||||
<g id="bookmark-starred-active" class="active">
|
||||
<path d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562
|
||||
l3.124,3.262l-0.692,4.589C2.679,15.596,2.957,16,3.444,16c0.185,0,0.401-0.058,0.637-0.181L8,13.744l3.919,2.075
|
||||
C12.156,15.942,12.372,16,12.557,16c0.487,0,0.764-0.404,0.661-1.094l-0.69-4.589l3.12-3.259c0.668-0.703,0.43-1.406-0.532-1.566
|
||||
l-4.317-0.72L8.775,0.651C8.562,0.217,8.281,0,8,0L8,0z"/>
|
||||
</g>
|
||||
</defs>
|
||||
<use id="back" xlink:href="#back-shape"/>
|
||||
<use id="back-active" xlink:href="#back-shape"/>
|
||||
<use id="back-disabled" xlink:href="#back-shape"/>
|
||||
<use id="forward" xlink:href="#forward-shape"/>
|
||||
<use id="forward-active" xlink:href="#forward-shape"/>
|
||||
<use id="forward-disabled" xlink:href="#forward-shape"/>
|
||||
<use id="reload" xlink:href="#reload-shape"/>
|
||||
<use id="reload-active" xlink:href="#reload-shape"/>
|
||||
<use id="reload-disabled" xlink:href="#reload-shape"/>
|
||||
<use id="stop" xlink:href="#stop-shape"/>
|
||||
<use id="stop-active" xlink:href="#stop-shape"/>
|
||||
<use id="stop-disabled" xlink:href="#stop-shape"/>
|
||||
<use id="bookmark" xlink:href="#bookmark-shape"/>
|
||||
<use id="bookmark-active" xlink:href="#bookmark-shape"/>
|
||||
<use id="bookmark-disabled" xlink:href="#bookmark-shape"/>
|
||||
<use id="bookmarked" xlink:href="#bookmarked-shape"/>
|
||||
<use id="bookmarked-active" xlink:href="#bookmarked-shape"/>
|
||||
<use id="bookmarked-disabled" xlink:href="#bookmarked-shape"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 4.5 KiB |
@ -3,95 +3,71 @@
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px" y="0px"
|
||||
viewBox="0 0 16 16"
|
||||
enable-background="new 0 0 16 16"
|
||||
xml:space="preserve">
|
||||
<style>
|
||||
g:not(:target) {
|
||||
use:not(:target) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
path {
|
||||
use {
|
||||
fill: menutext;
|
||||
}
|
||||
|
||||
g.active > path {
|
||||
use[id$="-active"] {
|
||||
fill: -moz-mac-menutextselect;
|
||||
}
|
||||
|
||||
use[id$="-disabled"] {
|
||||
fill: -moz-mac-menutextdisable;
|
||||
}
|
||||
</style>
|
||||
<g id="back">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159
|
||||
<defs style="display:none">
|
||||
<path id="back-shape" fill-rule="evenodd" clip-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159
|
||||
l5.199,5.301c0.607,0.63,1.465,0.764,1.915,0.297l1.02-1.082c0.449-0.467,0.32-1.357-0.288-1.99l-2.116-2.158h5.705
|
||||
c0.671,0,1.215-0.544,1.215-1.215v-2.43c0-0.671-0.544-1.215-1.215-1.215H8.094l2.271-2.309c0.609-0.626,0.737-1.512,0.288-1.974
|
||||
L9.635,0.278C9.184-0.188,8.327-0.055,7.718,0.575L2.479,5.901C2.38,5.946,2.289,6.008,2.21,6.089L1.192,7.171
|
||||
c-0.21,0.219-0.293,0.53-0.26,0.864C0.899,8.367,0.981,8.676,1.192,8.893z"/>
|
||||
</g>
|
||||
<g id="forward">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159
|
||||
<path id="forward-shape" fill-rule="evenodd" clip-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159
|
||||
L8.377,0.576C7.77-0.054,6.912-0.189,6.461,0.278L5.441,1.36c-0.449,0.467-0.32,1.357,0.288,1.99l2.116,2.158H2.14
|
||||
c-0.671,0-1.215,0.544-1.215,1.215v2.43c0,0.671,0.544,1.215,1.215,1.215h5.765l-2.271,2.309c-0.609,0.626-0.737,1.512-0.288,1.974
|
||||
l1.019,1.072c0.451,0.465,1.308,0.332,1.917-0.297l5.238-5.326c0.1-0.045,0.191-0.107,0.269-0.188l1.019-1.082
|
||||
c0.21-0.219,0.293-0.53,0.26-0.864C15.101,7.633,15.019,7.324,14.808,7.107z"/>
|
||||
</g>
|
||||
<g id="reload">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947
|
||||
<path id="reload-shape" fill-rule="evenodd" clip-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947
|
||||
c-2.554,0-4.625,2.071-4.625,4.625S5.446,13.196,8,13.196c1.638,0,3.069-0.857,3.891-2.141l2.576,1.104
|
||||
C13.199,14.439,10.794,16,8,16c-4.103,0-7.429-3.326-7.429-7.429S3.897,1.143,8,1.143c1.762,0,3.366,0.624,4.631,1.654L15.429,0V8z"/>
|
||||
</g>
|
||||
<g id="stop">
|
||||
<polygon fill-rule="evenodd" clip-rule="evenodd" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669
|
||||
<polygon id="stop-shape" fill-rule="evenodd" clip-rule="evenodd" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669
|
||||
5.377,8.059 0.157,13.292 2.819,15.961 8.039,10.728 13.298,16 15.959,13.331 10.701,8.06"/>
|
||||
</g>
|
||||
<g id="bookmark">
|
||||
<path d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967
|
||||
<path id="bookmark-shape" d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967
|
||||
L10.896,13l-1.959-1.039l-0.937-0.497l-0.937,0.497l-1.957,1.038L5.468,10.6l0.146-0.968L4.937,8.924L3.219,7.126l2.351-0.39
|
||||
l1.023-0.17l0.45-0.934L8.008,3.632 M8,0C7.72,0,7.44,0.217,7.228,0.65L5.242,4.766L0.907,5.485c-0.958,0.159-1.195,0.861-0.53,1.56
|
||||
l3.113,3.258l-0.69,4.583c-0.105,0.689,0.172,1.092,0.658,1.092c0.185,0,0.399-0.058,0.635-0.181l3.906-2.072l3.906,2.072
|
||||
c0.236,0.123,0.45,0.181,0.635,0.181c0.486,0,0.762-0.403,0.659-1.092l-0.687-4.583l3.109-3.255c0.666-0.702,0.428-1.404-0.53-1.564
|
||||
l-4.303-0.719L8.772,0.65C8.56,0.217,8.28,0,8,0L8,0z"/>
|
||||
</g>
|
||||
<g id="bookmark-starred">
|
||||
<path d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562
|
||||
<path id="bookmarked-shape" d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562
|
||||
l3.124,3.262l-0.692,4.589C2.679,15.596,2.957,16,3.444,16c0.185,0,0.401-0.058,0.637-0.181L8,13.744l3.919,2.075
|
||||
C12.156,15.942,12.372,16,12.557,16c0.487,0,0.764-0.404,0.661-1.094l-0.69-4.589l3.12-3.259c0.668-0.703,0.43-1.406-0.532-1.566
|
||||
l-4.317-0.72L8.775,0.651C8.562,0.217,8.281,0,8,0L8,0z"/>
|
||||
</g>
|
||||
<g id="back-active" class="active">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159
|
||||
l5.199,5.301c0.607,0.63,1.465,0.764,1.915,0.297l1.02-1.082c0.449-0.467,0.32-1.357-0.288-1.99l-2.116-2.158h5.705
|
||||
c0.671,0,1.215-0.544,1.215-1.215v-2.43c0-0.671-0.544-1.215-1.215-1.215H8.094l2.271-2.309c0.609-0.626,0.737-1.512,0.288-1.974
|
||||
L9.635,0.278C9.184-0.188,8.327-0.055,7.718,0.575L2.479,5.901C2.38,5.946,2.289,6.008,2.21,6.089L1.192,7.171
|
||||
c-0.21,0.219-0.293,0.53-0.26,0.864C0.899,8.367,0.981,8.676,1.192,8.893z"/>
|
||||
</g>
|
||||
<g id="forward-active" class="active">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159
|
||||
L8.377,0.576C7.77-0.054,6.912-0.189,6.461,0.278L5.441,1.36c-0.449,0.467-0.32,1.357,0.288,1.99l2.116,2.158H2.14
|
||||
c-0.671,0-1.215,0.544-1.215,1.215v2.43c0,0.671,0.544,1.215,1.215,1.215h5.765l-2.271,2.309c-0.609,0.626-0.737,1.512-0.288,1.974
|
||||
l1.019,1.072c0.451,0.465,1.308,0.332,1.917-0.297l5.238-5.326c0.1-0.045,0.191-0.107,0.269-0.188l1.019-1.082
|
||||
c0.21-0.219,0.293-0.53,0.26-0.864C15.101,7.633,15.019,7.324,14.808,7.107z"/>
|
||||
</g>
|
||||
<g id="reload-active" class="active">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947
|
||||
c-2.554,0-4.625,2.071-4.625,4.625S5.446,13.196,8,13.196c1.638,0,3.069-0.857,3.891-2.141l2.576,1.104
|
||||
C13.199,14.439,10.794,16,8,16c-4.103,0-7.429-3.326-7.429-7.429S3.897,1.143,8,1.143c1.762,0,3.366,0.624,4.631,1.654L15.429,0V8z"/>
|
||||
</g>
|
||||
<g id="stop-active" class="active">
|
||||
<polygon fill-rule="evenodd" clip-rule="evenodd" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669
|
||||
5.377,8.059 0.157,13.292 2.819,15.961 8.039,10.728 13.298,16 15.959,13.331 10.701,8.06"/>
|
||||
</g>
|
||||
<g id="bookmark-active" class="active">
|
||||
<path d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967
|
||||
L10.896,13l-1.959-1.039l-0.937-0.497l-0.937,0.497l-1.957,1.038L5.468,10.6l0.146-0.968L4.937,8.924L3.219,7.126l2.351-0.39
|
||||
l1.023-0.17l0.45-0.934L8.008,3.632 M8,0C7.72,0,7.44,0.217,7.228,0.65L5.242,4.766L0.907,5.485c-0.958,0.159-1.195,0.861-0.53,1.56
|
||||
l3.113,3.258l-0.69,4.583c-0.105,0.689,0.172,1.092,0.658,1.092c0.185,0,0.399-0.058,0.635-0.181l3.906-2.072l3.906,2.072
|
||||
c0.236,0.123,0.45,0.181,0.635,0.181c0.486,0,0.762-0.403,0.659-1.092l-0.687-4.583l3.109-3.255c0.666-0.702,0.428-1.404-0.53-1.564
|
||||
l-4.303-0.719L8.772,0.65C8.56,0.217,8.28,0,8,0L8,0z"/>
|
||||
</g>
|
||||
<g id="bookmark-starred-active" class="active">
|
||||
<path d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562
|
||||
l3.124,3.262l-0.692,4.589C2.679,15.596,2.957,16,3.444,16c0.185,0,0.401-0.058,0.637-0.181L8,13.744l3.919,2.075
|
||||
C12.156,15.942,12.372,16,12.557,16c0.487,0,0.764-0.404,0.661-1.094l-0.69-4.589l3.12-3.259c0.668-0.703,0.43-1.406-0.532-1.566
|
||||
l-4.317-0.72L8.775,0.651C8.562,0.217,8.281,0,8,0L8,0z"/>
|
||||
</g>
|
||||
</defs>
|
||||
<use id="back" xlink:href="#back-shape"/>
|
||||
<use id="back-active" xlink:href="#back-shape"/>
|
||||
<use id="back-disabled" xlink:href="#back-shape"/>
|
||||
<use id="forward" xlink:href="#forward-shape"/>
|
||||
<use id="forward-active" xlink:href="#forward-shape"/>
|
||||
<use id="forward-disabled" xlink:href="#forward-shape"/>
|
||||
<use id="reload" xlink:href="#reload-shape"/>
|
||||
<use id="reload-active" xlink:href="#reload-shape"/>
|
||||
<use id="reload-disabled" xlink:href="#reload-shape"/>
|
||||
<use id="stop" xlink:href="#stop-shape"/>
|
||||
<use id="stop-active" xlink:href="#stop-shape"/>
|
||||
<use id="stop-disabled" xlink:href="#stop-shape"/>
|
||||
<use id="bookmark" xlink:href="#bookmark-shape"/>
|
||||
<use id="bookmark-active" xlink:href="#bookmark-shape"/>
|
||||
<use id="bookmark-disabled" xlink:href="#bookmark-shape"/>
|
||||
<use id="bookmarked" xlink:href="#bookmarked-shape"/>
|
||||
<use id="bookmarked-active" xlink:href="#bookmarked-shape"/>
|
||||
<use id="bookmarked-disabled" xlink:href="#bookmarked-shape"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 4.5 KiB |
@ -1,8 +1,3 @@
|
||||
|
||||
menugroup > .menuitem-iconic[disabled="true"] > .menu-iconic-left {
|
||||
opacity: .3;
|
||||
}
|
||||
|
||||
#context-navigation > .menuitem-iconic {
|
||||
-moz-box-flex: 1;
|
||||
-moz-box-pack: center;
|
||||
@ -13,46 +8,66 @@ menugroup > .menuitem-iconic[disabled="true"] > .menu-iconic-left {
|
||||
-moz-appearance: none;
|
||||
}
|
||||
|
||||
#context-back > .menu-iconic-left {
|
||||
#context-back {
|
||||
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#back");
|
||||
}
|
||||
|
||||
#context-back[_moz-menuactive=true]:not([disabled]) > .menu-iconic-left {
|
||||
#context-back[_moz-menuactive=true] {
|
||||
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#back-active");
|
||||
}
|
||||
|
||||
#context-forward > .menu-iconic-left {
|
||||
#context-back[disabled=true] {
|
||||
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#back-disabled");
|
||||
}
|
||||
|
||||
#context-forward {
|
||||
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#forward");
|
||||
}
|
||||
|
||||
#context-forward[_moz-menuactive=true]:not([disabled]) > .menu-iconic-left {
|
||||
#context-forward[_moz-menuactive=true] {
|
||||
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#forward-active");
|
||||
}
|
||||
|
||||
#context-reload > .menu-iconic-left {
|
||||
#context-forward[disabled=true] {
|
||||
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#forward-disabled");
|
||||
}
|
||||
|
||||
#context-reload {
|
||||
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#reload");
|
||||
}
|
||||
|
||||
#context-reload[_moz-menuactive=true]:not([disabled]) > .menu-iconic-left {
|
||||
#context-reload[_moz-menuactive=true] {
|
||||
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#reload-active");
|
||||
}
|
||||
|
||||
#context-stop > .menu-iconic-left {
|
||||
#context-reload[disabled=true] {
|
||||
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#reload-disabled");
|
||||
}
|
||||
|
||||
#context-stop {
|
||||
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#stop");
|
||||
}
|
||||
|
||||
#context-stop[_moz-menuactive=true]:not([disabled]) > .menu-iconic-left {
|
||||
#context-stop[_moz-menuactive=true] {
|
||||
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#stop-active");
|
||||
}
|
||||
|
||||
#context-bookmarkpage > .menu-iconic-left {
|
||||
#context-stop[disabled=true] {
|
||||
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#stop-disabled");
|
||||
}
|
||||
|
||||
#context-bookmarkpage {
|
||||
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#bookmark");
|
||||
}
|
||||
|
||||
#context-bookmarkpage[_moz-menuactive=true]:not([disabled]) > .menu-iconic-left {
|
||||
#context-bookmarkpage[_moz-menuactive=true] {
|
||||
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#bookmark-active");
|
||||
}
|
||||
|
||||
#context-bookmarkpage[disabled=true] {
|
||||
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#bookmark-disabled");
|
||||
}
|
||||
|
||||
#context-back:-moz-locale-dir(rtl),
|
||||
#context-forward:-moz-locale-dir(rtl),
|
||||
#context-reload:-moz-locale-dir(rtl) {
|
||||
|
@ -13,6 +13,7 @@
|
||||
#banners-and-logs {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
#logs {
|
||||
|
@ -3,95 +3,71 @@
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px" y="0px"
|
||||
viewBox="0 0 16 16"
|
||||
enable-background="new 0 0 16 16"
|
||||
xml:space="preserve">
|
||||
<style>
|
||||
g:not(:target) {
|
||||
use:not(:target) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
path {
|
||||
use {
|
||||
fill: menutext;
|
||||
}
|
||||
|
||||
g.active > path {
|
||||
use[id$="-active"] {
|
||||
fill: -moz-menuhovertext;
|
||||
}
|
||||
|
||||
use[id$="-disabled"] {
|
||||
fill: graytext;
|
||||
}
|
||||
</style>
|
||||
<g id="back">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159
|
||||
<defs style="display:none">
|
||||
<path id="back-shape" fill-rule="evenodd" clip-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159
|
||||
l5.199,5.301c0.607,0.63,1.465,0.764,1.915,0.297l1.02-1.082c0.449-0.467,0.32-1.357-0.288-1.99l-2.116-2.158h5.705
|
||||
c0.671,0,1.215-0.544,1.215-1.215v-2.43c0-0.671-0.544-1.215-1.215-1.215H8.094l2.271-2.309c0.609-0.626,0.737-1.512,0.288-1.974
|
||||
L9.635,0.278C9.184-0.188,8.327-0.055,7.718,0.575L2.479,5.901C2.38,5.946,2.289,6.008,2.21,6.089L1.192,7.171
|
||||
c-0.21,0.219-0.293,0.53-0.26,0.864C0.899,8.367,0.981,8.676,1.192,8.893z"/>
|
||||
</g>
|
||||
<g id="forward">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159
|
||||
<path id="forward-shape" fill-rule="evenodd" clip-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159
|
||||
L8.377,0.576C7.77-0.054,6.912-0.189,6.461,0.278L5.441,1.36c-0.449,0.467-0.32,1.357,0.288,1.99l2.116,2.158H2.14
|
||||
c-0.671,0-1.215,0.544-1.215,1.215v2.43c0,0.671,0.544,1.215,1.215,1.215h5.765l-2.271,2.309c-0.609,0.626-0.737,1.512-0.288,1.974
|
||||
l1.019,1.072c0.451,0.465,1.308,0.332,1.917-0.297l5.238-5.326c0.1-0.045,0.191-0.107,0.269-0.188l1.019-1.082
|
||||
c0.21-0.219,0.293-0.53,0.26-0.864C15.101,7.633,15.019,7.324,14.808,7.107z"/>
|
||||
</g>
|
||||
<g id="reload">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947
|
||||
<path id="reload-shape" fill-rule="evenodd" clip-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947
|
||||
c-2.554,0-4.625,2.071-4.625,4.625S5.446,13.196,8,13.196c1.638,0,3.069-0.857,3.891-2.141l2.576,1.104
|
||||
C13.199,14.439,10.794,16,8,16c-4.103,0-7.429-3.326-7.429-7.429S3.897,1.143,8,1.143c1.762,0,3.366,0.624,4.631,1.654L15.429,0V8z"/>
|
||||
</g>
|
||||
<g id="stop">
|
||||
<polygon fill-rule="evenodd" clip-rule="evenodd" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669
|
||||
<polygon id="stop-shape" fill-rule="evenodd" clip-rule="evenodd" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669
|
||||
5.377,8.059 0.157,13.292 2.819,15.961 8.039,10.728 13.298,16 15.959,13.331 10.701,8.06"/>
|
||||
</g>
|
||||
<g id="bookmark">
|
||||
<path d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967
|
||||
<path id="bookmark-shape" d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967
|
||||
L10.896,13l-1.959-1.039l-0.937-0.497l-0.937,0.497l-1.957,1.038L5.468,10.6l0.146-0.968L4.937,8.924L3.219,7.126l2.351-0.39
|
||||
l1.023-0.17l0.45-0.934L8.008,3.632 M8,0C7.72,0,7.44,0.217,7.228,0.65L5.242,4.766L0.907,5.485c-0.958,0.159-1.195,0.861-0.53,1.56
|
||||
l3.113,3.258l-0.69,4.583c-0.105,0.689,0.172,1.092,0.658,1.092c0.185,0,0.399-0.058,0.635-0.181l3.906-2.072l3.906,2.072
|
||||
c0.236,0.123,0.45,0.181,0.635,0.181c0.486,0,0.762-0.403,0.659-1.092l-0.687-4.583l3.109-3.255c0.666-0.702,0.428-1.404-0.53-1.564
|
||||
l-4.303-0.719L8.772,0.65C8.56,0.217,8.28,0,8,0L8,0z"/>
|
||||
</g>
|
||||
<g id="bookmark-starred">
|
||||
<path d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562
|
||||
<path id="bookmarked-shape" d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562
|
||||
l3.124,3.262l-0.692,4.589C2.679,15.596,2.957,16,3.444,16c0.185,0,0.401-0.058,0.637-0.181L8,13.744l3.919,2.075
|
||||
C12.156,15.942,12.372,16,12.557,16c0.487,0,0.764-0.404,0.661-1.094l-0.69-4.589l3.12-3.259c0.668-0.703,0.43-1.406-0.532-1.566
|
||||
l-4.317-0.72L8.775,0.651C8.562,0.217,8.281,0,8,0L8,0z"/>
|
||||
</g>
|
||||
<g id="back-active" class="active">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159
|
||||
l5.199,5.301c0.607,0.63,1.465,0.764,1.915,0.297l1.02-1.082c0.449-0.467,0.32-1.357-0.288-1.99l-2.116-2.158h5.705
|
||||
c0.671,0,1.215-0.544,1.215-1.215v-2.43c0-0.671-0.544-1.215-1.215-1.215H8.094l2.271-2.309c0.609-0.626,0.737-1.512,0.288-1.974
|
||||
L9.635,0.278C9.184-0.188,8.327-0.055,7.718,0.575L2.479,5.901C2.38,5.946,2.289,6.008,2.21,6.089L1.192,7.171
|
||||
c-0.21,0.219-0.293,0.53-0.26,0.864C0.899,8.367,0.981,8.676,1.192,8.893z"/>
|
||||
</g>
|
||||
<g id="forward-active" class="active">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159
|
||||
L8.377,0.576C7.77-0.054,6.912-0.189,6.461,0.278L5.441,1.36c-0.449,0.467-0.32,1.357,0.288,1.99l2.116,2.158H2.14
|
||||
c-0.671,0-1.215,0.544-1.215,1.215v2.43c0,0.671,0.544,1.215,1.215,1.215h5.765l-2.271,2.309c-0.609,0.626-0.737,1.512-0.288,1.974
|
||||
l1.019,1.072c0.451,0.465,1.308,0.332,1.917-0.297l5.238-5.326c0.1-0.045,0.191-0.107,0.269-0.188l1.019-1.082
|
||||
c0.21-0.219,0.293-0.53,0.26-0.864C15.101,7.633,15.019,7.324,14.808,7.107z"/>
|
||||
</g>
|
||||
<g id="reload-active" class="active">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947
|
||||
c-2.554,0-4.625,2.071-4.625,4.625S5.446,13.196,8,13.196c1.638,0,3.069-0.857,3.891-2.141l2.576,1.104
|
||||
C13.199,14.439,10.794,16,8,16c-4.103,0-7.429-3.326-7.429-7.429S3.897,1.143,8,1.143c1.762,0,3.366,0.624,4.631,1.654L15.429,0V8z"/>
|
||||
</g>
|
||||
<g id="stop-active" class="active">
|
||||
<polygon fill-rule="evenodd" clip-rule="evenodd" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669
|
||||
5.377,8.059 0.157,13.292 2.819,15.961 8.039,10.728 13.298,16 15.959,13.331 10.701,8.06"/>
|
||||
</g>
|
||||
<g id="bookmark-active" class="active">
|
||||
<path d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967
|
||||
L10.896,13l-1.959-1.039l-0.937-0.497l-0.937,0.497l-1.957,1.038L5.468,10.6l0.146-0.968L4.937,8.924L3.219,7.126l2.351-0.39
|
||||
l1.023-0.17l0.45-0.934L8.008,3.632 M8,0C7.72,0,7.44,0.217,7.228,0.65L5.242,4.766L0.907,5.485c-0.958,0.159-1.195,0.861-0.53,1.56
|
||||
l3.113,3.258l-0.69,4.583c-0.105,0.689,0.172,1.092,0.658,1.092c0.185,0,0.399-0.058,0.635-0.181l3.906-2.072l3.906,2.072
|
||||
c0.236,0.123,0.45,0.181,0.635,0.181c0.486,0,0.762-0.403,0.659-1.092l-0.687-4.583l3.109-3.255c0.666-0.702,0.428-1.404-0.53-1.564
|
||||
l-4.303-0.719L8.772,0.65C8.56,0.217,8.28,0,8,0L8,0z"/>
|
||||
</g>
|
||||
<g id="bookmark-starred-active" class="active">
|
||||
<path d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562
|
||||
l3.124,3.262l-0.692,4.589C2.679,15.596,2.957,16,3.444,16c0.185,0,0.401-0.058,0.637-0.181L8,13.744l3.919,2.075
|
||||
C12.156,15.942,12.372,16,12.557,16c0.487,0,0.764-0.404,0.661-1.094l-0.69-4.589l3.12-3.259c0.668-0.703,0.43-1.406-0.532-1.566
|
||||
l-4.317-0.72L8.775,0.651C8.562,0.217,8.281,0,8,0L8,0z"/>
|
||||
</g>
|
||||
</defs>
|
||||
<use id="back" xlink:href="#back-shape"/>
|
||||
<use id="back-active" xlink:href="#back-shape"/>
|
||||
<use id="back-disabled" xlink:href="#back-shape"/>
|
||||
<use id="forward" xlink:href="#forward-shape"/>
|
||||
<use id="forward-active" xlink:href="#forward-shape"/>
|
||||
<use id="forward-disabled" xlink:href="#forward-shape"/>
|
||||
<use id="reload" xlink:href="#reload-shape"/>
|
||||
<use id="reload-active" xlink:href="#reload-shape"/>
|
||||
<use id="reload-disabled" xlink:href="#reload-shape"/>
|
||||
<use id="stop" xlink:href="#stop-shape"/>
|
||||
<use id="stop-active" xlink:href="#stop-shape"/>
|
||||
<use id="stop-disabled" xlink:href="#stop-shape"/>
|
||||
<use id="bookmark" xlink:href="#bookmark-shape"/>
|
||||
<use id="bookmark-active" xlink:href="#bookmark-shape"/>
|
||||
<use id="bookmark-disabled" xlink:href="#bookmark-shape"/>
|
||||
<use id="bookmarked" xlink:href="#bookmarked-shape"/>
|
||||
<use id="bookmarked-active" xlink:href="#bookmarked-shape"/>
|
||||
<use id="bookmarked-disabled" xlink:href="#bookmarked-shape"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 4.5 KiB |
@ -116,10 +116,6 @@ public:
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
extern nsIntRect gScreenBounds;
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
@ -205,12 +201,6 @@ CreateSurfaceForWindow(nsIWidget* widget, const EGLConfig& config) {
|
||||
#else
|
||||
MOZ_ASSERT(widget != nullptr);
|
||||
newSurface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config, GET_NATIVE_WINDOW(widget), 0);
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
gScreenBounds.x = 0;
|
||||
gScreenBounds.y = 0;
|
||||
sEGLLibrary.fQuerySurface(EGL_DISPLAY(), newSurface, LOCAL_EGL_WIDTH, &gScreenBounds.width);
|
||||
sEGLLibrary.fQuerySurface(EGL_DISPLAY(), newSurface, LOCAL_EGL_HEIGHT, &gScreenBounds.height);
|
||||
#endif
|
||||
#endif
|
||||
return newSurface;
|
||||
}
|
||||
|
@ -2545,10 +2545,12 @@ public class BrowserApp extends GeckoApp
|
||||
tab = Tabs.getInstance().getSelectedTab();
|
||||
if (tab != null) {
|
||||
if (item.isChecked()) {
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.UNSAVE, TelemetryContract.Method.MENU, "bookmark");
|
||||
tab.removeBookmark();
|
||||
Toast.makeText(this, R.string.bookmark_removed, Toast.LENGTH_SHORT).show();
|
||||
item.setIcon(R.drawable.ic_menu_bookmark_add);
|
||||
} else {
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.SAVE, TelemetryContract.Method.MENU, "bookmark");
|
||||
tab.addBookmark();
|
||||
getButtonToast().show(false,
|
||||
getResources().getString(R.string.bookmark_added),
|
||||
|
@ -62,7 +62,6 @@ public interface TelemetryContract {
|
||||
SANITIZE("sanitize.1"),
|
||||
|
||||
// Saving a resource (reader, bookmark, etc) for viewing later.
|
||||
// Note: Only used in JavaScript for now, but here for completeness.
|
||||
SAVE("save.1"),
|
||||
|
||||
// Sharing content.
|
||||
@ -76,7 +75,6 @@ public interface TelemetryContract {
|
||||
UNPIN("unpin.1"),
|
||||
|
||||
// Stop holding a resource (reader, bookmark, etc) for viewing later.
|
||||
// Note: Only used in JavaScript for now, but here for completeness.
|
||||
UNSAVE("unsave.1"),
|
||||
|
||||
// VALUES BELOW THIS LINE ARE EXCLUSIVE TO TESTING.
|
||||
|
@ -61,6 +61,8 @@ let AboutReader = function(doc, win) {
|
||||
win.addEventListener("popstate", this, false);
|
||||
win.addEventListener("resize", this, false);
|
||||
|
||||
doc.addEventListener("visibilitychange", this, false);
|
||||
|
||||
this._setupAllDropdowns();
|
||||
this._setupButton("toggle-button", this._onReaderToggle.bind(this));
|
||||
this._setupButton("share-button", this._onShare.bind(this));
|
||||
@ -271,6 +273,10 @@ AboutReader.prototype = {
|
||||
this._handleDeviceLight(aEvent.value);
|
||||
break;
|
||||
|
||||
case "visibilitychange":
|
||||
this._handleVisibilityChange();
|
||||
break;
|
||||
|
||||
case "unload":
|
||||
Services.obs.removeObserver(this, "Reader:Add");
|
||||
Services.obs.removeObserver(this, "Reader:Remove");
|
||||
@ -399,6 +405,29 @@ AboutReader.prototype = {
|
||||
this._totalLux -= oldLux;
|
||||
},
|
||||
|
||||
_handleVisibilityChange: function Reader_handleVisibilityChange() {
|
||||
let colorScheme = Services.prefs.getCharPref("reader.color_scheme");
|
||||
if (colorScheme != "auto") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Turn off the ambient light sensor if the page is hidden
|
||||
this._enableAmbientLighting(!this._doc.hidden);
|
||||
},
|
||||
|
||||
// Setup or teardown the ambient light tracking system.
|
||||
_enableAmbientLighting: function Reader_enableAmbientLighting(enable) {
|
||||
if (enable) {
|
||||
this._win.addEventListener("devicelight", this, false);
|
||||
this._luxValues = [];
|
||||
this._totalLux = 0;
|
||||
} else {
|
||||
this._win.removeEventListener("devicelight", this, false);
|
||||
delete this._luxValues;
|
||||
delete this._totalLux;
|
||||
}
|
||||
},
|
||||
|
||||
_updateColorScheme: function Reader_updateColorScheme(luxValue) {
|
||||
// Upper bound value for "dark" color scheme beyond which it changes to "light".
|
||||
let upperBoundDark = 50;
|
||||
@ -419,7 +448,8 @@ AboutReader.prototype = {
|
||||
},
|
||||
|
||||
_setColorScheme: function Reader_setColorScheme(newColorScheme) {
|
||||
if (this._colorScheme === newColorScheme)
|
||||
// "auto" is not a real color scheme
|
||||
if (this._colorScheme === newColorScheme || newColorScheme === "auto")
|
||||
return;
|
||||
|
||||
let bodyClasses = this._doc.body.classList;
|
||||
@ -434,16 +464,8 @@ AboutReader.prototype = {
|
||||
// Pref values include "dark", "light", and "auto", which automatically switches
|
||||
// between light and dark color schemes based on the ambient light level.
|
||||
_setColorSchemePref: function Reader_setColorSchemePref(colorSchemePref) {
|
||||
if (colorSchemePref === "auto") {
|
||||
this._win.addEventListener("devicelight", this, false);
|
||||
this._luxValues = [];
|
||||
this._totalLux = 0;
|
||||
} else {
|
||||
this._win.removeEventListener("devicelight", this, false);
|
||||
this._setColorScheme(colorSchemePref);
|
||||
delete this._luxValues;
|
||||
delete this._totalLux;
|
||||
}
|
||||
this._enableAmbientLighting(colorSchemePref === "auto");
|
||||
this._setColorScheme(colorSchemePref);
|
||||
|
||||
Services.prefs.setCharPref("reader.color_scheme", colorSchemePref);
|
||||
},
|
||||
|
@ -1653,7 +1653,7 @@ var BrowserApp = {
|
||||
case "Passwords:Init": {
|
||||
let storage = Cc["@mozilla.org/login-manager/storage/mozStorage;1"].
|
||||
getService(Ci.nsILoginManagerStorage);
|
||||
storage.init();
|
||||
storage.initialize();
|
||||
Services.obs.removeObserver(this, "Passwords:Init");
|
||||
break;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
package org.mozilla.search;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
@ -76,7 +77,10 @@ public class PreSearchFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
|
||||
listView = (ListView) inflater.inflate(R.layout.search_fragment_pre_search, container, false);
|
||||
final View mainView = inflater.inflate(R.layout.search_fragment_pre_search, container, false);
|
||||
|
||||
// Initialize listview.
|
||||
listView = (ListView) mainView.findViewById(R.id.list_view);
|
||||
listView.setAdapter(cursorAdapter);
|
||||
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
@ -91,7 +95,15 @@ public class PreSearchFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
});
|
||||
return listView;
|
||||
|
||||
// Apply click handler to settings button.
|
||||
mainView.findViewById(R.id.settings_button).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
startActivity(new Intent(getActivity(), SearchPreferenceActivity.class));
|
||||
}
|
||||
});
|
||||
return mainView;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,96 @@
|
||||
/* 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/. */
|
||||
|
||||
package org.mozilla.search;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
|
||||
/**
|
||||
* This activity allows users to modify the settings for the search activity.
|
||||
*
|
||||
* A note on implementation: At the moment, we don't have tablet-specific designs.
|
||||
* Therefore, this implementation uses the old-style PreferenceActivity. When
|
||||
* we start optimizing for tablets, we can migrate to Fennec's PreferenceFragment
|
||||
* implementation.
|
||||
*
|
||||
* TODO: Change this to PreferenceFragment when we stop supporting devices older than SDK 11.
|
||||
*/
|
||||
public class SearchPreferenceActivity extends PreferenceActivity {
|
||||
|
||||
private static final String LOGTAG = "SearchPreferenceActivity";
|
||||
|
||||
private static final String CLEAR_SEARCH_HISTORY_BUTTON_KEY = "clear_search_history_button";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
if (getActionBar() != null) {
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
setupPrefsScreen();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void setupPrefsScreen() {
|
||||
addPreferencesFromResource(R.xml.search_preferences);
|
||||
|
||||
final Preference clearHistoryButton = findPreference(CLEAR_SEARCH_HISTORY_BUTTON_KEY);
|
||||
clearHistoryButton.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(SearchPreferenceActivity.this);
|
||||
dialogBuilder.setNegativeButton(android.R.string.cancel, null);
|
||||
dialogBuilder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
clearHistory();
|
||||
}
|
||||
});
|
||||
dialogBuilder.setMessage(R.string.search_pref_clear_history_dialog_message);
|
||||
dialogBuilder.show();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void clearHistory() {
|
||||
final AsyncTask<Void, Void, Boolean> clearHistoryTask = new AsyncTask<Void, Void, Boolean>() {
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
final int numDeleted = getContentResolver().delete(
|
||||
BrowserContract.SearchHistory.CONTENT_URI, null, null);
|
||||
return numDeleted >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean success) {
|
||||
if (success) {
|
||||
getContentResolver().notifyChange(BrowserContract.SearchHistory.CONTENT_URI, null);
|
||||
Toast.makeText(SearchPreferenceActivity.this, SearchPreferenceActivity.this.getResources()
|
||||
.getString(R.string.search_pref_clear_history_confirmation), Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Log.e(LOGTAG, "Error clearing search history.");
|
||||
}
|
||||
}
|
||||
};
|
||||
clearHistoryTask.execute();
|
||||
}
|
||||
}
|
@ -3,10 +3,6 @@
|
||||
android:label="@string/search_app_name"
|
||||
android:theme="@style/AppTheme"
|
||||
android:screenOrientation="portrait">
|
||||
|
||||
<!-- Add this to activity declaration to hide keyboard on launch -->
|
||||
<!-- android:windowSoftInputMode="stateHidden" -->
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
|
||||
@ -18,3 +14,13 @@
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="org.mozilla.search.SearchPreferenceActivity"
|
||||
android:label="@string/search_pref_title"
|
||||
android:parentActivityName="org.mozilla.search.MainActivity"
|
||||
android:theme="@style/SettingsTheme" >
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="org.mozilla.search.MainActivity"/>
|
||||
</activity>
|
||||
|
BIN
mobile/android/search/res/drawable-hdpi/ic_action_overflow.png
Normal file
After Width: | Height: | Size: 225 B |
BIN
mobile/android/search/res/drawable-mdpi/ic_action_overflow.png
Normal file
After Width: | Height: | Size: 197 B |
BIN
mobile/android/search/res/drawable-xhdpi/ic_action_overflow.png
Normal file
After Width: | Height: | Size: 267 B |
@ -2,9 +2,26 @@
|
||||
- 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/. -->
|
||||
|
||||
<ListView
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:divider="@null"
|
||||
android:dividerHeight="0dp"/>
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ListView
|
||||
android:id="@+id/list_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:divider="@null"
|
||||
android:dividerHeight="0dp"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/settings_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/transparent"
|
||||
android:padding="15dp"
|
||||
android:src="@drawable/ic_action_overflow"
|
||||
android:text="@string/search_settings_icon"
|
||||
android:layout_gravity="bottom|right"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
@ -10,4 +10,6 @@
|
||||
<item name="android:colorBackground">@color/global_background_color</item>
|
||||
</style>
|
||||
|
||||
<style name="SettingsTheme" parent="@android:style/Theme.Holo.Light"/>
|
||||
|
||||
</resources>
|
||||
|
@ -10,4 +10,6 @@
|
||||
<item name="android:colorBackground">@color/global_background_color</item>
|
||||
</style>
|
||||
|
||||
<style name="SettingsTheme" parent="@android:style/Theme.Light"/>
|
||||
|
||||
</resources>
|
||||
|
9
mobile/android/search/res/xml/search_preferences.xml
Normal 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/. -->
|
||||
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<Preference
|
||||
android:key="clear_search_history_button"
|
||||
android:title="@string/search_pref_clear_history_title"/>
|
||||
</PreferenceScreen>
|
@ -15,4 +15,5 @@ search_activity_sources = [
|
||||
'java/org/mozilla/search/MainActivity.java',
|
||||
'java/org/mozilla/search/PostSearchFragment.java',
|
||||
'java/org/mozilla/search/PreSearchFragment.java',
|
||||
'java/org/mozilla/search/SearchPreferenceActivity.java',
|
||||
]
|
||||
|
@ -3,6 +3,12 @@
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!ENTITY search_jump_arrow '↖'>
|
||||
<!ENTITY search_settings_icon '⋮'>
|
||||
|
||||
<!ENTITY search_app_name 'Firefox Search'>
|
||||
<!ENTITY search_header_image_content_description 'Firefox Search Header Image'>
|
||||
<!ENTITY search_for_something 'Search for something'>
|
||||
|
||||
<!ENTITY search_pref_title 'Settings'>
|
||||
<!ENTITY search_pref_clear_history_confirmation 'History cleared'>
|
||||
<!ENTITY search_pref_clear_history_dialog_message 'Delete all search history from this device?'>
|
||||
<!ENTITY search_pref_clear_history_title 'Clear search history'>
|
||||
|
@ -1,4 +1,10 @@
|
||||
<string name="search_app_name">&search_app_name;</string>
|
||||
<string name="search_jump_arrow">&search_jump_arrow;</string>
|
||||
<string name="search_header_image_content_description">&search_header_image_content_description;</string>
|
||||
<string name="search_settings_icon">&search_settings_icon;</string>
|
||||
|
||||
<string name="search_app_name">&search_app_name;</string>
|
||||
<string name="search_for_something">&search_for_something;</string>
|
||||
|
||||
<string name="search_pref_title">&search_pref_title;</string>
|
||||
<string name="search_pref_clear_history_confirmation">&search_pref_clear_history_confirmation;</string>
|
||||
<string name="search_pref_clear_history_dialog_message">&search_pref_clear_history_dialog_message;</string>
|
||||
<string name="search_pref_clear_history_title">&search_pref_clear_history_title;</string>
|
||||
|
@ -36,7 +36,9 @@ toolkit.jar:
|
||||
* content/global/customizeToolbar.js (customizeToolbar.js)
|
||||
content/global/customizeToolbar.xul (customizeToolbar.xul)
|
||||
content/global/devicestorage.properties (devicestorage.properties)
|
||||
#ifndef ANDROID
|
||||
content/global/directoryLinks.json (directoryLinks.json)
|
||||
#endif
|
||||
content/global/editMenuOverlay.js (editMenuOverlay.js)
|
||||
*+ content/global/editMenuOverlay.xul (editMenuOverlay.xul)
|
||||
content/global/finddialog.js (finddialog.js)
|
||||
|
@ -29,7 +29,6 @@ this.EXPORTED_SYMBOLS = ["DebuggerTransport",
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
let promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js").Promise;
|
||||
const { defer, resolve, reject } = promise;
|
||||
@ -85,6 +84,8 @@ let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
|
||||
loader.loadSubScript("resource://gre/modules/devtools/transport/transport.js", this);
|
||||
|
||||
/**
|
||||
* TODO: Get rid of this API in favor of EventTarget (bug 1042642)
|
||||
*
|
||||
* Add simple event notification to a prototype object. Any object that has
|
||||
* some use for event notifications or the observer pattern in general can be
|
||||
* augmented with the necessary facilities by passing its prototype to this
|
||||
@ -175,7 +176,7 @@ function eventSource(aProto) {
|
||||
* All arguments will be passed along to the listeners,
|
||||
* including the name argument.
|
||||
*/
|
||||
aProto.notify = function () {
|
||||
aProto.emit = function () {
|
||||
if (!this._listeners) {
|
||||
return;
|
||||
}
|
||||
@ -277,7 +278,7 @@ this.DebuggerClient = function (aTransport)
|
||||
this.mainRoot = null;
|
||||
this.expectReply("root", (aPacket) => {
|
||||
this.mainRoot = new RootClient(this, aPacket);
|
||||
this.notify("connected", aPacket.applicationType, aPacket.traits);
|
||||
this.emit("connected", aPacket.applicationType, aPacket.traits);
|
||||
});
|
||||
}
|
||||
|
||||
@ -453,7 +454,7 @@ DebuggerClient.prototype = {
|
||||
javascriptEnabled: cachedTab.javascriptEnabled,
|
||||
traits: cachedTab.traits,
|
||||
};
|
||||
setTimeout(() => aOnResponse(cachedResponse, cachedTab), 0);
|
||||
DevToolsUtils.executeSoon(() => aOnResponse(cachedResponse, cachedTab));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -543,7 +544,7 @@ DebuggerClient.prototype = {
|
||||
*/
|
||||
attachThread: function (aThreadActor, aOnResponse = noop, aOptions={}) {
|
||||
if (this._clients.has(aThreadActor)) {
|
||||
setTimeout(() => aOnResponse({}, this._clients.get(aThreadActor)), 0);
|
||||
DevToolsUtils.executeSoon(() => aOnResponse({}, this._clients.get(aThreadActor)));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -572,7 +573,7 @@ DebuggerClient.prototype = {
|
||||
*/
|
||||
attachTracer: function (aTraceActor, aOnResponse = noop) {
|
||||
if (this._clients.has(aTraceActor)) {
|
||||
setTimeout(() => aOnResponse({}, this._clients.get(aTraceActor)), 0);
|
||||
DevToolsUtils.executeSoon(() => aOnResponse({}, this._clients.get(aTraceActor)));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -918,7 +919,7 @@ DebuggerClient.prototype = {
|
||||
// Only try to notify listeners on events, not responses to requests
|
||||
// that lack a packet type.
|
||||
if (aPacket.type) {
|
||||
this.notify(aPacket.type, aPacket);
|
||||
this.emit(aPacket.type, aPacket);
|
||||
}
|
||||
|
||||
if (activeRequest) {
|
||||
@ -991,7 +992,7 @@ DebuggerClient.prototype = {
|
||||
* the stream.
|
||||
*/
|
||||
onClosed: function (aStatus) {
|
||||
this.notify("closed");
|
||||
this.emit("closed");
|
||||
},
|
||||
|
||||
registerClient: function (client) {
|
||||
@ -1282,7 +1283,7 @@ TabClient.prototype = {
|
||||
*/
|
||||
attachThread: function(aOptions={}, aOnResponse = noop) {
|
||||
if (this.thread) {
|
||||
setTimeout(() => aOnResponse({}, this.thread), 0);
|
||||
DevToolsUtils.executeSoon(() => aOnResponse({}, this.thread));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1670,7 +1671,7 @@ ThreadClient.prototype = {
|
||||
// the next resumption. Otherwise we have to force a pause in order to send
|
||||
// the array.
|
||||
if (this.paused) {
|
||||
setTimeout(() => onResponse({}), 0);
|
||||
DevToolsUtils.executeSoon(() => onResponse({}));
|
||||
return;
|
||||
}
|
||||
this.interrupt(response => {
|
||||
@ -1853,7 +1854,7 @@ ThreadClient.prototype = {
|
||||
_clearScripts: function () {
|
||||
if (Object.keys(this._scriptCache).length > 0) {
|
||||
this._scriptCache = {}
|
||||
this.notify("scriptscleared");
|
||||
this.emit("scriptscleared");
|
||||
}
|
||||
},
|
||||
|
||||
@ -1923,7 +1924,7 @@ ThreadClient.prototype = {
|
||||
|
||||
// If we got as many frames as we asked for, there might be more
|
||||
// frames available.
|
||||
this.notify("framesadded");
|
||||
this.emit("framesadded");
|
||||
|
||||
aCallback(aResponse);
|
||||
});
|
||||
@ -1938,7 +1939,7 @@ ThreadClient.prototype = {
|
||||
_clearFrames: function () {
|
||||
if (this._frameCache.length > 0) {
|
||||
this._frameCache = [];
|
||||
this.notify("framescleared");
|
||||
this.emit("framescleared");
|
||||
}
|
||||
},
|
||||
|
||||
@ -2038,7 +2039,7 @@ ThreadClient.prototype = {
|
||||
this._clearFrames();
|
||||
this._clearPauseGrips();
|
||||
aPacket.type === ThreadStateTypes.detached && this._clearThreadGrips();
|
||||
this.client._eventsEnabled && this.notify(aPacket.type, aPacket);
|
||||
this.client._eventsEnabled && this.emit(aPacket.type, aPacket);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -2389,7 +2390,7 @@ SourceClient.prototype = {
|
||||
if (!aResponse.error) {
|
||||
this._isBlackBoxed = true;
|
||||
if (this._activeThread) {
|
||||
this._activeThread.notify("blackboxchange", this);
|
||||
this._activeThread.emit("blackboxchange", this);
|
||||
}
|
||||
}
|
||||
return aResponse;
|
||||
@ -2410,7 +2411,7 @@ SourceClient.prototype = {
|
||||
if (!aResponse.error) {
|
||||
this._isBlackBoxed = false;
|
||||
if (this._activeThread) {
|
||||
this._activeThread.notify("blackboxchange", this);
|
||||
this._activeThread.emit("blackboxchange", this);
|
||||
}
|
||||
}
|
||||
return aResponse;
|
||||
@ -2443,7 +2444,7 @@ SourceClient.prototype = {
|
||||
if (!aResponse.error) {
|
||||
this._isPrettyPrinted = true;
|
||||
this._activeThread._clearFrames();
|
||||
this._activeThread.notify("prettyprintchange", this);
|
||||
this._activeThread.emit("prettyprintchange", this);
|
||||
}
|
||||
this._onSourceResponse(aResponse, aCallback);
|
||||
});
|
||||
@ -2461,7 +2462,7 @@ SourceClient.prototype = {
|
||||
if (!aResponse.error) {
|
||||
this._isPrettyPrinted = false;
|
||||
this._activeThread._clearFrames();
|
||||
this._activeThread.notify("prettyprintchange", this);
|
||||
this._activeThread.emit("prettyprintchange", this);
|
||||
}
|
||||
this._onSourceResponse(aResponse, aCallback);
|
||||
});
|
||||
|
@ -2,57 +2,58 @@
|
||||
* 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 {Ci,Cu} = require("chrome");
|
||||
const {Ci,Cu,Cc} = require("chrome");
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const Services = require("Services");
|
||||
let {setTimeout} = require("sdk/timers");
|
||||
let {setTimeout,clearTimeout} = require("sdk/timers");
|
||||
|
||||
function MonitorActor(aConnection) {
|
||||
this.conn = aConnection;
|
||||
this._updates = [];
|
||||
this._started = false;
|
||||
}
|
||||
|
||||
MonitorActor.prototype = {
|
||||
actorPrefix: "monitor",
|
||||
|
||||
// Updates
|
||||
// Updates.
|
||||
|
||||
_toSend: [],
|
||||
_timeout: null,
|
||||
_started: false,
|
||||
_scheduleUpdate: function() {
|
||||
if (this._started && !this._timeout) {
|
||||
this._timeout = setTimeout(() => {
|
||||
if (this._toSend.length > 0) {
|
||||
this.conn.sendActorEvent(this.actorID, "update", this._toSend);
|
||||
this._toSend = [];
|
||||
}
|
||||
this._timeout = null;
|
||||
}, 200);
|
||||
_sendUpdate: function() {
|
||||
if (this._started) {
|
||||
this.conn.sendActorEvent(this.actorID, "update", { data: this._updates });
|
||||
this._updates = [];
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Methods available from the front
|
||||
// Methods available from the front.
|
||||
|
||||
start: function() {
|
||||
if (!this._started) {
|
||||
this._started = true;
|
||||
Services.obs.addObserver(this, "devtools-monitor-update", false);
|
||||
Services.obs.notifyObservers(null, "devtools-monitor-start", "");
|
||||
this._agents.forEach(agent => this._startAgent(agent));
|
||||
}
|
||||
return {};
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
if (this._started) {
|
||||
this._agents.forEach(agent => agent.stop());
|
||||
Services.obs.notifyObservers(null, "devtools-monitor-stop", "");
|
||||
Services.obs.removeObserver(this, "devtools-monitor-update");
|
||||
this._started = false;
|
||||
}
|
||||
return {};
|
||||
},
|
||||
|
||||
// nsIObserver
|
||||
disconnect: function() {
|
||||
this.stop();
|
||||
},
|
||||
|
||||
// nsIObserver.
|
||||
|
||||
observe: function (subject, topic, data) {
|
||||
if (topic == "devtools-monitor-update") {
|
||||
@ -64,16 +65,42 @@ MonitorActor.prototype = {
|
||||
return;
|
||||
}
|
||||
if (!Array.isArray(data)) {
|
||||
this._toSend.push(data);
|
||||
this._updates.push(data);
|
||||
} else {
|
||||
this._toSend = this._toSend.concat(data);
|
||||
this._updates = this._updates.concat(data);
|
||||
}
|
||||
this._scheduleUpdate();
|
||||
this._sendUpdate();
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
|
||||
}
|
||||
|
||||
// Update agents (see USSAgent for an example).
|
||||
|
||||
_agents: [],
|
||||
|
||||
_startAgent: function(agent) {
|
||||
try {
|
||||
agent.start();
|
||||
} catch (e) {
|
||||
this._removeAgent(agent);
|
||||
}
|
||||
},
|
||||
|
||||
_addAgent: function(agent) {
|
||||
this._agents.push(agent);
|
||||
if (this._started) {
|
||||
this._startAgent(agent);
|
||||
}
|
||||
},
|
||||
|
||||
_removeAgent: function(agent) {
|
||||
let index = this._agents.indexOf(agent);
|
||||
if (index > -1) {
|
||||
this._agents.splice(index, 1);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
MonitorActor.prototype.requestTypes = {
|
||||
"start": MonitorActor.prototype.start,
|
||||
@ -91,3 +118,40 @@ exports.unregister = function(handle) {
|
||||
handle.removeGlobalActor(MonitorActor, "monitorActor");
|
||||
handle.removeTabActor(MonitorActor, "monitorActor");
|
||||
};
|
||||
|
||||
|
||||
let USSAgent = {
|
||||
_mgr: null,
|
||||
_timeout: null,
|
||||
_packet: {
|
||||
graph: "USS",
|
||||
time: null,
|
||||
value: null
|
||||
},
|
||||
|
||||
start: function() {
|
||||
USSAgent._mgr = Cc["@mozilla.org/memory-reporter-manager;1"].getService(Ci.nsIMemoryReporterManager);
|
||||
if (!USSAgent._mgr.residentUnique) {
|
||||
throw "Couldn't get USS.";
|
||||
}
|
||||
USSAgent.update();
|
||||
},
|
||||
|
||||
update: function() {
|
||||
if (!USSAgent._mgr) {
|
||||
USSAgent.stop();
|
||||
return;
|
||||
}
|
||||
USSAgent._packet.time = Date.now();
|
||||
USSAgent._packet.value = USSAgent._mgr.residentUnique;
|
||||
Services.obs.notifyObservers(null, "devtools-monitor-update", JSON.stringify(USSAgent._packet));
|
||||
USSAgent._timeout = setTimeout(USSAgent.update, 300);
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
clearTimeout(USSAgent._timeout);
|
||||
USSAgent._mgr = null;
|
||||
}
|
||||
};
|
||||
|
||||
MonitorActor.prototype._addAgent(USSAgent);
|
||||
|
@ -1174,7 +1174,7 @@ DebuggerServerConnection.prototype = {
|
||||
this._forwardingPrefixes.delete(aPrefix);
|
||||
},
|
||||
|
||||
sendActorEvent: function (actorID, eventName, event) {
|
||||
sendActorEvent: function (actorID, eventName, event = {}) {
|
||||
event.from = actorID;
|
||||
event.type = eventName;
|
||||
this.send(event);
|
||||
|
@ -28,11 +28,11 @@ function run_test()
|
||||
client.unregisterClient(this);
|
||||
}
|
||||
MonitorClient.prototype.detach = function () {}
|
||||
MonitorClient.prototype.start = function () {
|
||||
MonitorClient.prototype.start = function (callback) {
|
||||
this.client.request({
|
||||
to: this.actor,
|
||||
type: "start"
|
||||
});
|
||||
}, callback);
|
||||
}
|
||||
MonitorClient.prototype.stop = function (callback) {
|
||||
this.client.request({
|
||||
@ -43,34 +43,39 @@ function run_test()
|
||||
|
||||
let monitor;
|
||||
|
||||
// Start tracking event loop lags.
|
||||
// Start the monitor actor.
|
||||
client.connect(function () {
|
||||
client.listTabs(function(resp) {
|
||||
monitor = new MonitorClient(client, resp);
|
||||
monitor.start();
|
||||
monitor.on("update", gotUpdate);
|
||||
do_execute_soon(update);
|
||||
monitor.start(update);
|
||||
});
|
||||
});
|
||||
|
||||
let time = new Date().getTime();
|
||||
let time = Date.now();
|
||||
|
||||
function update() {
|
||||
let event = {
|
||||
graph: "Test",
|
||||
curve: "test",
|
||||
value: 42,
|
||||
time: time,
|
||||
value: 42
|
||||
};
|
||||
Services.obs.notifyObservers(null, "devtools-monitor-update", JSON.stringify(event));
|
||||
}
|
||||
|
||||
function gotUpdate(type, data) {
|
||||
do_check_eq(data.length, 1);
|
||||
let evt = data[0];
|
||||
do_check_eq(evt.value, 42);
|
||||
do_check_eq(evt.time, time);
|
||||
monitor.stop(function (aResponse) {
|
||||
monitor.destroy();
|
||||
finishClient(client);
|
||||
function gotUpdate(type, packet) {
|
||||
packet.data.forEach(function(event) {
|
||||
// Ignore updates that were not sent by this test.
|
||||
if (event.graph === "Test") {
|
||||
do_check_eq(event.curve, "test");
|
||||
do_check_eq(event.value, 42);
|
||||
do_check_eq(event.time, time);
|
||||
monitor.stop(function (aResponse) {
|
||||
monitor.destroy();
|
||||
finishClient(client);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|