|
@ -29,6 +29,7 @@ pref("browser.sessionstore.restore_on_demand", false);
|
|||
pref("browser.sessionstore.resume_from_crash", false);
|
||||
// No e10s on mulet
|
||||
pref("browser.tabs.remote.autostart.1", false);
|
||||
pref("browser.tabs.remote.autostart.2", false);
|
||||
#endif
|
||||
|
||||
// Bug 945235: Prevent all bars to be considered visible:
|
||||
|
@ -1037,6 +1038,7 @@ pref("apz.fling_curve_function_y2", "1.0");
|
|||
pref("apz.fling_curve_threshold_inches_per_ms", "0.01");
|
||||
pref("apz.fling_friction", "0.0019");
|
||||
pref("apz.max_velocity_inches_per_ms", "0.07");
|
||||
pref("apz.touch_start_tolerance", "0.1");
|
||||
|
||||
// Tweak default displayport values to reduce the risk of running out of
|
||||
// memory when zooming in
|
||||
|
|
|
@ -196,19 +196,20 @@ SettingsListener.observe('devtools.overlay', false, (value) => {
|
|||
});
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
|
||||
let LogShake;
|
||||
SettingsListener.observe('devtools.logshake', false, (value) => {
|
||||
(function() {
|
||||
let scope = {};
|
||||
Cu.import('resource://gre/modules/LogShake.jsm', scope);
|
||||
LogShake = scope.LogShake;
|
||||
LogShake.init();
|
||||
})();
|
||||
|
||||
SettingsListener.observe('devtools.logshake', false, value => {
|
||||
if (value) {
|
||||
if (!LogShake) {
|
||||
let scope = {};
|
||||
Cu.import('resource://gre/modules/LogShake.jsm', scope);
|
||||
LogShake = scope.LogShake;
|
||||
}
|
||||
LogShake.init();
|
||||
LogShake.enableDeviceMotionListener();
|
||||
} else {
|
||||
if (LogShake) {
|
||||
LogShake.uninit();
|
||||
}
|
||||
LogShake.disableDeviceMotionListener();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
|
|
@ -56,6 +56,7 @@ function debug(msg) {
|
|||
const EXCITEMENT_THRESHOLD = 500;
|
||||
const DEVICE_MOTION_EVENT = "devicemotion";
|
||||
const SCREEN_CHANGE_EVENT = "screenchange";
|
||||
const CAPTURE_LOGS_CONTENT_EVENT = "requestSystemLogs";
|
||||
const CAPTURE_LOGS_START_EVENT = "capture-logs-start";
|
||||
const CAPTURE_LOGS_ERROR_EVENT = "capture-logs-error";
|
||||
const CAPTURE_LOGS_SUCCESS_EVENT = "capture-logs-success";
|
||||
|
@ -69,6 +70,18 @@ let LogShake = {
|
|||
*/
|
||||
deviceMotionEnabled: false,
|
||||
|
||||
/**
|
||||
* We only listen to motion events when the screen is enabled, keep track
|
||||
* of its state.
|
||||
*/
|
||||
screenEnabled: true,
|
||||
|
||||
/**
|
||||
* Flag monitoring if the preference to enable shake to capture is
|
||||
* enabled in gaia.
|
||||
*/
|
||||
listenToDeviceMotion: true,
|
||||
|
||||
/**
|
||||
* If a capture has been requested and is waiting for reads/parsing. Used for
|
||||
* debouncing.
|
||||
|
@ -109,6 +122,7 @@ let LogShake = {
|
|||
screenEnabled: true
|
||||
}});
|
||||
|
||||
SystemAppProxy.addEventListener(CAPTURE_LOGS_CONTENT_EVENT, this, false);
|
||||
SystemAppProxy.addEventListener(SCREEN_CHANGE_EVENT, this, false);
|
||||
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
|
@ -129,6 +143,10 @@ let LogShake = {
|
|||
case SCREEN_CHANGE_EVENT:
|
||||
this.handleScreenChangeEvent(event);
|
||||
break;
|
||||
|
||||
case CAPTURE_LOGS_CONTENT_EVENT:
|
||||
this.startCapture();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -141,8 +159,20 @@ let LogShake = {
|
|||
}
|
||||
},
|
||||
|
||||
enableDeviceMotionListener: function() {
|
||||
this.listenToDeviceMotion = true;
|
||||
this.startDeviceMotionListener();
|
||||
},
|
||||
|
||||
disableDeviceMotionListener: function() {
|
||||
this.listenToDeviceMotion = false;
|
||||
this.stopDeviceMotionListener();
|
||||
},
|
||||
|
||||
startDeviceMotionListener: function() {
|
||||
if (!this.deviceMotionEnabled) {
|
||||
if (!this.deviceMotionEnabled &&
|
||||
this.listenToDeviceMotion &&
|
||||
this.screenEnabled) {
|
||||
SystemAppProxy.addEventListener(DEVICE_MOTION_EVENT, this, false);
|
||||
this.deviceMotionEnabled = true;
|
||||
}
|
||||
|
@ -169,28 +199,33 @@ let LogShake = {
|
|||
var excitement = acc.x * acc.x + acc.y * acc.y + acc.z * acc.z;
|
||||
|
||||
if (excitement > EXCITEMENT_THRESHOLD) {
|
||||
if (!this.captureRequested) {
|
||||
this.captureRequested = true;
|
||||
SystemAppProxy._sendCustomEvent(CAPTURE_LOGS_START_EVENT, {});
|
||||
this.captureLogs().then(logResults => {
|
||||
// On resolution send the success event to the requester
|
||||
SystemAppProxy._sendCustomEvent(CAPTURE_LOGS_SUCCESS_EVENT, {
|
||||
logFilenames: logResults.logFilenames,
|
||||
logPrefix: logResults.logPrefix
|
||||
});
|
||||
this.captureRequested = false;
|
||||
},
|
||||
error => {
|
||||
// On an error send the error event
|
||||
SystemAppProxy._sendCustomEvent(CAPTURE_LOGS_ERROR_EVENT, {error: error});
|
||||
this.captureRequested = false;
|
||||
});
|
||||
}
|
||||
this.startCapture();
|
||||
}
|
||||
},
|
||||
|
||||
startCapture: function() {
|
||||
if (this.captureRequested) {
|
||||
return;
|
||||
}
|
||||
this.captureRequested = true;
|
||||
SystemAppProxy._sendCustomEvent(CAPTURE_LOGS_START_EVENT, {});
|
||||
this.captureLogs().then(logResults => {
|
||||
// On resolution send the success event to the requester
|
||||
SystemAppProxy._sendCustomEvent(CAPTURE_LOGS_SUCCESS_EVENT, {
|
||||
logFilenames: logResults.logFilenames,
|
||||
logPrefix: logResults.logPrefix
|
||||
});
|
||||
this.captureRequested = false;
|
||||
}, error => {
|
||||
// On an error send the error event
|
||||
SystemAppProxy._sendCustomEvent(CAPTURE_LOGS_ERROR_EVENT, {error: error});
|
||||
this.captureRequested = false;
|
||||
});
|
||||
},
|
||||
|
||||
handleScreenChangeEvent: function(event) {
|
||||
if (event.detail.screenEnabled) {
|
||||
this.screenEnabled = event.detail.screenEnabled;
|
||||
if (this.screenEnabled) {
|
||||
this.startDeviceMotionListener();
|
||||
} else {
|
||||
this.stopDeviceMotionListener();
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ef61ebbe5de8c2c9fc2a8f74a12455044c3b82e9"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="834385f4c834238a4306bf87cc4be41615d91ff0"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -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="ef61ebbe5de8c2c9fc2a8f74a12455044c3b82e9"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="834385f4c834238a4306bf87cc4be41615d91ff0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ef61ebbe5de8c2c9fc2a8f74a12455044c3b82e9"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="834385f4c834238a4306bf87cc4be41615d91ff0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1b1d86462d3150dceacff927536ded9fcc168419"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ef61ebbe5de8c2c9fc2a8f74a12455044c3b82e9"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="834385f4c834238a4306bf87cc4be41615d91ff0"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ef61ebbe5de8c2c9fc2a8f74a12455044c3b82e9"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="834385f4c834238a4306bf87cc4be41615d91ff0"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -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="ef61ebbe5de8c2c9fc2a8f74a12455044c3b82e9"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="834385f4c834238a4306bf87cc4be41615d91ff0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ef61ebbe5de8c2c9fc2a8f74a12455044c3b82e9"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="834385f4c834238a4306bf87cc4be41615d91ff0"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ef61ebbe5de8c2c9fc2a8f74a12455044c3b82e9"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="834385f4c834238a4306bf87cc4be41615d91ff0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1b1d86462d3150dceacff927536ded9fcc168419"/>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"git": {
|
||||
"git_revision": "ef61ebbe5de8c2c9fc2a8f74a12455044c3b82e9",
|
||||
"git_revision": "834385f4c834238a4306bf87cc4be41615d91ff0",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "fceb69a8216d41525d5bec7efe4e97c140cc386d",
|
||||
"revision": "e7a7a8c4f624820b810b33e098a3e7d941de53a1",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ef61ebbe5de8c2c9fc2a8f74a12455044c3b82e9"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="834385f4c834238a4306bf87cc4be41615d91ff0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1b1d86462d3150dceacff927536ded9fcc168419"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ef61ebbe5de8c2c9fc2a8f74a12455044c3b82e9"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="834385f4c834238a4306bf87cc4be41615d91ff0"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -17,3 +17,4 @@ pref("devtools.toolbox.sidebar.width", 800);
|
|||
// nor the system app OOP, but only inner apps
|
||||
pref("browser.tabs.remote.autostart", false);
|
||||
pref("browser.tabs.remote.autostart.1", false);
|
||||
pref("browser.tabs.remote.autostart.2", false);
|
||||
|
|
|
@ -1855,7 +1855,11 @@ pref("privacy.trackingprotection.ui.enabled", false);
|
|||
#endif
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("browser.tabs.remote.autostart.1", true);
|
||||
// At the moment, autostart.2 is used, while autostart.1 is unused.
|
||||
// We leave it here set to false to reset users' defaults and allow
|
||||
// us to change everybody to true in the future, when desired.
|
||||
pref("browser.tabs.remote.autostart.1", false);
|
||||
pref("browser.tabs.remote.autostart.2", true);
|
||||
#endif
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
|
|
|
@ -834,7 +834,7 @@
|
|||
<image id="reader-mode-button"
|
||||
class="urlbar-icon"
|
||||
hidden="true"
|
||||
onclick="ReaderParent.toggleReaderMode(event);"/>
|
||||
onclick="ReaderParent.buttonClick(event);"/>
|
||||
</hbox>
|
||||
<toolbarbutton id="urlbar-go-button"
|
||||
class="chromeclass-toolbar-additional"
|
||||
|
|
|
@ -2772,7 +2772,12 @@ let E10SUINotification = {
|
|||
return;
|
||||
}
|
||||
|
||||
// The user has just voluntarily disabled e10s. Subtract one from displayedE10SNotice
|
||||
// so that the next time e10s is activated (either by the user or forced by us), they
|
||||
// can see the notice again.
|
||||
Services.prefs.setIntPref("browser.displayedE10SNotice", this.CURRENT_NOTICE_COUNT - 1);
|
||||
Services.prefs.clearUserPref("browser.requestE10sFeedback");
|
||||
|
||||
let url = Services.urlFormatter.formatURLPref("app.feedback.baseURL");
|
||||
url += "?utm_source=tab&utm_campaign=e10sfeedback";
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
name="browser.tabs.remote.autostart"
|
||||
type="bool"/>
|
||||
<preference id="e10sTempPref"
|
||||
name="browser.tabs.remote.autostart.1"
|
||||
name="browser.tabs.remote.autostart.2"
|
||||
type="bool"/>
|
||||
#endif
|
||||
|
||||
|
|
|
@ -21,8 +21,13 @@ if test "$OS_ARCH" = "WINNT"; then
|
|||
fi
|
||||
fi
|
||||
fi
|
||||
elif test "$OS_ARCH" = "Darwin"; then
|
||||
MOZ_VERIFY_MAR_SIGNATURE=1
|
||||
fi
|
||||
|
||||
# Enable building ./signmar and running libmar signature tests
|
||||
MOZ_ENABLE_SIGNMAR=1
|
||||
|
||||
MOZ_CHROME_FILE_FORMAT=omni
|
||||
MOZ_DISABLE_EXPORT_JS=1
|
||||
MOZ_SAFE_BROWSING=1
|
||||
|
|
|
@ -125,6 +125,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "DevToolsUtils",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
|
||||
"resource://gre/modules/ShortcutUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
|
||||
"@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
|
||||
|
||||
Object.defineProperty(this, "NetworkHelper", {
|
||||
get: function() {
|
||||
return devtools.require("devtools/toolkit/webconsole/network-helper");
|
||||
|
|
|
@ -40,6 +40,8 @@ function SourcesView() {
|
|||
this._onConditionalPopupShown = this._onConditionalPopupShown.bind(this);
|
||||
this._onConditionalPopupHiding = this._onConditionalPopupHiding.bind(this);
|
||||
this._onConditionalTextboxKeyPress = this._onConditionalTextboxKeyPress.bind(this);
|
||||
this._onCopyUrlCommand = this._onCopyUrlCommand.bind(this);
|
||||
this._onNewTabCommand = this._onNewTabCommand.bind(this);
|
||||
}
|
||||
|
||||
SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
||||
|
@ -50,6 +52,7 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
dumpn("Initializing the SourcesView");
|
||||
|
||||
this.widget = new SideMenuWidget(document.getElementById("sources"), {
|
||||
contextMenu: document.getElementById("debuggerSourcesContextMenu"),
|
||||
showArrows: true
|
||||
});
|
||||
|
||||
|
@ -65,6 +68,8 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
this._stopBlackBoxButton = document.getElementById("black-boxed-message-button");
|
||||
this._prettyPrintButton = document.getElementById("pretty-print");
|
||||
this._toggleBreakpointsButton = document.getElementById("toggle-breakpoints");
|
||||
this._newTabMenuItem = document.getElementById("debugger-sources-context-newtab");
|
||||
this._copyUrlMenuItem = document.getElementById("debugger-sources-context-copyurl");
|
||||
|
||||
if (Prefs.prettyPrintEnabled) {
|
||||
this._prettyPrintButton.removeAttribute("hidden");
|
||||
|
@ -78,7 +83,10 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
this._cbPanel.addEventListener("popupshown", this._onConditionalPopupShown, false);
|
||||
this._cbPanel.addEventListener("popuphiding", this._onConditionalPopupHiding, false);
|
||||
this._cbTextbox.addEventListener("keypress", this._onConditionalTextboxKeyPress, false);
|
||||
this._copyUrlMenuItem.addEventListener("command", this._onCopyUrlCommand, false);
|
||||
this._newTabMenuItem.addEventListener("command", this._onNewTabCommand, false);
|
||||
|
||||
this.allowFocusOnRightClick = true;
|
||||
this.autoFocusOnSelection = false;
|
||||
|
||||
// Sort the contents by the displayed label.
|
||||
|
@ -112,6 +120,8 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
this._cbPanel.removeEventListener("popupshowing", this._onConditionalPopupShown, false);
|
||||
this._cbPanel.removeEventListener("popuphiding", this._onConditionalPopupHiding, false);
|
||||
this._cbTextbox.removeEventListener("keypress", this._onConditionalTextboxKeyPress, false);
|
||||
this._copyUrlMenuItem.removeEventListener("command", this._onCopyUrlCommand, false);
|
||||
this._newTabMenuItem.removeEventListener("command", this._onNewTabCommand, false);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -872,6 +882,26 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy the source url from the currently selected item.
|
||||
*/
|
||||
_onCopyUrlCommand: function() {
|
||||
let selected = this.selectedItem && this.selectedItem.attachment;
|
||||
if (!selected) {
|
||||
return;
|
||||
}
|
||||
clipboardHelper.copyString(selected.source.url, document);
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens selected item source in a new tab.
|
||||
*/
|
||||
_onNewTabCommand: function() {
|
||||
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
let selected = this.selectedItem.attachment;
|
||||
win.openUILinkIn(selected.source.url, "tab", { relatedToCurrent: true });
|
||||
},
|
||||
|
||||
/**
|
||||
* Function called each time a breakpoint item is removed.
|
||||
*
|
||||
|
|
|
@ -156,6 +156,17 @@
|
|||
</menupopup>
|
||||
</popupset>
|
||||
|
||||
<popupset id="debuggerSourcesPopupset">
|
||||
<menupopup id="debuggerSourcesContextMenu">
|
||||
<menuitem id="debugger-sources-context-newtab"
|
||||
label="&debuggerUI.context.newTab;"
|
||||
accesskey="&debuggerUI.context.newTab.accesskey;"/>
|
||||
<menuitem id="debugger-sources-context-copyurl"
|
||||
label="&debuggerUI.context.copyUrl;"
|
||||
accesskey="&debuggerUI.context.copyUrl.accesskey;"/>
|
||||
</menupopup>
|
||||
</popupset>
|
||||
|
||||
<keyset id="debuggerKeys">
|
||||
<key id="nextSourceKey"
|
||||
keycode="VK_DOWN"
|
||||
|
@ -242,6 +253,10 @@
|
|||
key="&debuggerUI.removeAllWatch.key;"
|
||||
modifiers="accel alt"
|
||||
command="removeAllWatchExpressionsCommand"/>
|
||||
<key id="debuggerSourcesCopyUrl"
|
||||
key="&debuggerUI.context.copyUrl.key;"
|
||||
modifiers="accel"
|
||||
oncommand="DebuggerView.Sources._onCopyUrlCommand()"/>
|
||||
</keyset>
|
||||
|
||||
<vbox id="body"
|
||||
|
|
|
@ -389,10 +389,13 @@ skip-if = e10s && debug
|
|||
[browser_dbg_source-maps-04.js]
|
||||
skip-if = e10s # Bug 1093535
|
||||
[browser_dbg_sources-cache.js]
|
||||
[browser_dbg_sources-contextmenu-01.js]
|
||||
[browser_dbg_sources-contextmenu-02.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_sources-eval-01.js]
|
||||
skip-if = true # non-named eval sources turned off for now, bug 1124106
|
||||
[browser_dbg_sources-eval-02.js]
|
||||
[browser_dbg_sources-keybindings.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_sources-labels.js]
|
||||
skip-if = e10s && debug
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests the "Copy URL" functionality of the sources panel context menu
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_function-search.html";
|
||||
const SCRIPT_URI = EXAMPLE_URL + "code_function-search-01.js";
|
||||
|
||||
function test() {
|
||||
let gTab, gPanel, gDebugger, gSources;
|
||||
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gSources = gDebugger.DebuggerView.Sources;
|
||||
|
||||
waitForSourceShown(gPanel, "-01.js")
|
||||
.then(openContextMenu)
|
||||
.then(testCopyMenuItem)
|
||||
.then(() => closeDebuggerAndFinish(gPanel))
|
||||
.then(null, aError => {
|
||||
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
|
||||
});
|
||||
});
|
||||
|
||||
function clickCopyURL() {
|
||||
return new Promise((resolve, reject) => {
|
||||
let copyURLMenuItem = gDebugger.document.getElementById("debugger-sources-context-copyurl");
|
||||
if (!copyURLMenuItem) {
|
||||
reject(new Error("The Copy URL context menu item is not available."));
|
||||
}
|
||||
|
||||
ok(copyURLMenuItem, "The Copy URL context menu item is available.");
|
||||
EventUtils.synthesizeMouseAtCenter(copyURLMenuItem, {}, gDebugger);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function testCopyMenuItem() {
|
||||
return waitForClipboardPromise(clickCopyURL, SCRIPT_URI);
|
||||
}
|
||||
|
||||
function openContextMenu() {
|
||||
let contextMenu = gDebugger.document.getElementById("debuggerSourcesContextMenu");
|
||||
let contextMenuShown = once(contextMenu, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(gSources.selectedItem.prebuiltNode, {type: 'contextmenu'}, gDebugger);
|
||||
return contextMenuShown;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests the "Open in New Tab" functionality of the sources panel context menu
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_function-search.html";
|
||||
const SCRIPT_URI = EXAMPLE_URL + "code_function-search-01.js";
|
||||
|
||||
function test() {
|
||||
let gTab, gPanel, gDebugger;
|
||||
let gSources;
|
||||
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gSources = gDebugger.DebuggerView.Sources;
|
||||
|
||||
waitForSourceShown(gPanel, "-01.js")
|
||||
.then(openContextMenu)
|
||||
.then(testNewTabMenuItem)
|
||||
.then(testNewTabURI)
|
||||
.then(() => closeDebuggerAndFinish(gPanel))
|
||||
.then(null, aError => {
|
||||
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
|
||||
});
|
||||
});
|
||||
|
||||
function testNewTabURI(tabUri) {
|
||||
is(tabUri, SCRIPT_URI, "The tab contains the right script.");
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
|
||||
function waitForTabOpen() {
|
||||
return new Promise(resolve => {
|
||||
gBrowser.tabContainer.addEventListener("TabOpen", function onOpen(e) {
|
||||
gBrowser.tabContainer.removeEventListener("TabOpen", onOpen, false);
|
||||
ok(true, "A new tab loaded");
|
||||
|
||||
gBrowser.addEventListener("DOMContentLoaded", function onTabLoad(e){
|
||||
gBrowser.removeEventListener("DOMContentLoaded", onTabLoad, false);
|
||||
// Pass along the new tab's URI.
|
||||
resolve(gBrowser.currentURI.spec);
|
||||
}, false);
|
||||
}, false);
|
||||
});
|
||||
}
|
||||
|
||||
function testNewTabMenuItem() {
|
||||
return new Promise((resolve, reject) => {
|
||||
let newTabMenuItem = gDebugger.document.getElementById("debugger-sources-context-newtab");
|
||||
if (!newTabMenuItem) {
|
||||
reject(new Error("The Open in New Tab context menu item is not available."));
|
||||
}
|
||||
|
||||
ok(newTabMenuItem, "The Open in New Tab context menu item is available.");
|
||||
waitForTabOpen().then(resolve);
|
||||
EventUtils.synthesizeMouseAtCenter(newTabMenuItem, {}, gDebugger);
|
||||
});
|
||||
}
|
||||
|
||||
function openContextMenu() {
|
||||
let contextMenu = gDebugger.document.getElementById("debuggerSourcesContextMenu");
|
||||
let contextMenuShown = once(contextMenu, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(gSources.selectedItem.prebuiltNode, {type: 'contextmenu'}, gDebugger);
|
||||
return contextMenuShown;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests related to source panel keyboard shortcut bindings
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_function-search.html";
|
||||
const SCRIPT_URI = EXAMPLE_URL + "code_function-search-01.js";
|
||||
|
||||
function test() {
|
||||
let gTab, gPanel, gDebugger, gSources;
|
||||
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gSources = gDebugger.DebuggerView.Sources;
|
||||
|
||||
waitForSourceShown(gPanel, "-01.js")
|
||||
.then(testCopyURLShortcut)
|
||||
.then(() => closeDebuggerAndFinish(gPanel))
|
||||
.then(null, aError => {
|
||||
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
|
||||
});
|
||||
});
|
||||
|
||||
function testCopyURLShortcut() {
|
||||
return waitForClipboardPromise(sendCopyShortcut, SCRIPT_URI);
|
||||
}
|
||||
|
||||
function sendCopyShortcut() {
|
||||
EventUtils.synthesizeKey("C", { accelKey: true }, gDebugger);
|
||||
}
|
||||
}
|
|
@ -441,6 +441,12 @@ function waitForClientEvents(aPanel, aEventName, aEventRepeat = 1) {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
function waitForClipboardPromise(setup, expected) {
|
||||
return new Promise((resolve, reject) => {
|
||||
SimpleTest.waitForClipboard(expected, setup, resolve, reject);
|
||||
});
|
||||
}
|
||||
|
||||
function ensureThreadClientState(aPanel, aState) {
|
||||
let thread = aPanel.panelWin.gThreadClient;
|
||||
let state = thread.state;
|
||||
|
|
|
@ -11,6 +11,7 @@ Cu.import("resource://gre/modules/Services.jsm");
|
|||
let promise = require("resource://gre/modules/Promise.jsm").Promise;
|
||||
let EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
let clipboard = require("sdk/clipboard");
|
||||
let {HostType} = require("devtools/framework/toolbox").Toolbox;
|
||||
|
||||
loader.lazyGetter(this, "MarkupView", () => require("devtools/markupview/markup-view").MarkupView);
|
||||
loader.lazyGetter(this, "HTMLBreadcrumbs", () => require("devtools/inspector/breadcrumbs").HTMLBreadcrumbs);
|
||||
|
@ -144,6 +145,9 @@ InspectorPanel.prototype = {
|
|||
|
||||
this.breadcrumbs = new HTMLBreadcrumbs(this);
|
||||
|
||||
this.onToolboxHostChanged = this.onToolboxHostChanged.bind(this);
|
||||
this._toolbox.on("host-changed", this.onToolboxHostChanged);
|
||||
|
||||
if (this.target.isLocalTab) {
|
||||
this.browser = this.target.tab.linkedBrowser;
|
||||
this.scheduleLayoutChange = this.scheduleLayoutChange.bind(this);
|
||||
|
@ -350,6 +354,19 @@ InspectorPanel.prototype = {
|
|||
}
|
||||
|
||||
this.sidebar.show();
|
||||
|
||||
this.setupSidebarToggle();
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the expand/collapse behavior for the sidebar panel.
|
||||
*/
|
||||
setupSidebarToggle: function() {
|
||||
this._paneToggleButton = this.panelDoc.getElementById("inspector-pane-toggle");
|
||||
this.onPaneToggleButtonClicked = this.onPaneToggleButtonClicked.bind(this);
|
||||
this._paneToggleButton.addEventListener("mousedown",
|
||||
this.onPaneToggleButtonClicked);
|
||||
this.updatePaneToggleButton();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -553,6 +570,7 @@ InspectorPanel.prototype = {
|
|||
this.target.off("thread-paused", this.updateDebuggerPausedWarning);
|
||||
this.target.off("thread-resumed", this.updateDebuggerPausedWarning);
|
||||
this._toolbox.off("select", this.updateDebuggerPausedWarning);
|
||||
this._toolbox.off("host-changed", this.onToolboxHostChanged);
|
||||
|
||||
this.sidebar.off("select", this._setDefaultSidebar);
|
||||
let sidebarDestroyer = this.sidebar.destroy();
|
||||
|
@ -561,6 +579,9 @@ InspectorPanel.prototype = {
|
|||
this.nodemenu.removeEventListener("popupshowing", this._setupNodeMenu, true);
|
||||
this.nodemenu.removeEventListener("popuphiding", this._resetNodeMenu, true);
|
||||
this.breadcrumbs.destroy();
|
||||
this._paneToggleButton.removeEventListener("mousedown",
|
||||
this.onPaneToggleButtonClicked);
|
||||
this._paneToggleButton = null;
|
||||
this.searchSuggestions.destroy();
|
||||
this.searchBox = null;
|
||||
this.selection.off("new-node-front", this.onNewSelection);
|
||||
|
@ -784,6 +805,47 @@ InspectorPanel.prototype = {
|
|||
return destroyPromise;
|
||||
},
|
||||
|
||||
/**
|
||||
* When the type of toolbox host changes.
|
||||
*/
|
||||
onToolboxHostChanged: function() {
|
||||
this.updatePaneToggleButton();
|
||||
},
|
||||
|
||||
/**
|
||||
* When the pane toggle button is clicked, toggle the pane, change the button
|
||||
* state and tooltip.
|
||||
*/
|
||||
onPaneToggleButtonClicked: function(e) {
|
||||
let sidePane = this.panelDoc.querySelector("#inspector-sidebar");
|
||||
let button = this._paneToggleButton;
|
||||
let isVisible = !button.hasAttribute("pane-collapsed");
|
||||
|
||||
ViewHelpers.togglePane({
|
||||
visible: !isVisible,
|
||||
animated: true,
|
||||
delayed: true
|
||||
}, sidePane);
|
||||
|
||||
if (isVisible) {
|
||||
button.setAttribute("pane-collapsed", "");
|
||||
button.setAttribute("tooltiptext",
|
||||
this.strings.GetStringFromName("inspector.expandPane"));
|
||||
} else {
|
||||
button.removeAttribute("pane-collapsed");
|
||||
button.setAttribute("tooltiptext",
|
||||
this.strings.GetStringFromName("inspector.collapsePane"));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the pane toggle button visibility depending on the toolbox host type.
|
||||
*/
|
||||
updatePaneToggleButton: function() {
|
||||
this._paneToggleButton.setAttribute("hidden",
|
||||
this._toolbox.hostType === HostType.SIDE);
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle a pseudo class.
|
||||
*/
|
||||
|
|
|
@ -121,6 +121,9 @@
|
|||
timeout="50"
|
||||
class="devtools-searchinput"
|
||||
placeholder="&inspectorSearchHTML.label2;"/>
|
||||
<toolbarbutton id="inspector-pane-toggle"
|
||||
class="devtools-toolbarbutton"
|
||||
tabindex="0" />
|
||||
</toolbar>
|
||||
<vbox flex="1" id="markup-box">
|
||||
</vbox>
|
||||
|
|
|
@ -76,6 +76,9 @@ skip-if = e10s # GCLI isn't e10s compatible. See bug 1128988.
|
|||
[browser_inspector_menu-03-paste-items.js]
|
||||
[browser_inspector_menu-04-other.js]
|
||||
[browser_inspector_navigation.js]
|
||||
[browser_inspector_pane-toggle-01.js]
|
||||
[browser_inspector_pane-toggle-02.js]
|
||||
[browser_inspector_pane-toggle-03.js]
|
||||
[browser_inspector_picker-stop-on-destroy.js]
|
||||
[browser_inspector_picker-stop-on-tool-change.js]
|
||||
[browser_inspector_pseudoclass-lock.js]
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the inspector panel has a sidebar pane toggle button, and that
|
||||
// this button is hidden when the toolbox is in SIDE mode.
|
||||
|
||||
add_task(function* () {
|
||||
info("Open the inspector in a bottom toolbox host");
|
||||
let {toolbox, inspector} = yield openInspectorForURL("about:blank", "bottom");
|
||||
|
||||
let button = inspector.panelDoc.getElementById("inspector-pane-toggle");
|
||||
ok(button, "The toggle button exists in the DOM");
|
||||
is(button.parentNode.id, "inspector-toolbar", "The toggle button is in the toolbar");
|
||||
ok(!button.hasAttribute("pane-collapsed"), "The button is in expanded state");
|
||||
ok(!!button.getClientRects().length, "The button is visible");
|
||||
|
||||
info("Switch the host to side type");
|
||||
yield toolbox.switchHost("side");
|
||||
|
||||
ok(!button.getClientRects().length, "The button is hidden");
|
||||
});
|
|
@ -0,0 +1,24 @@
|
|||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the inspector panel has its toggle pane button hidden by default
|
||||
// when it is opened in a "side" host, and that the button becomes visible when
|
||||
// the toolbox is switched to a "bottom" host.
|
||||
|
||||
add_task(function* () {
|
||||
info("Open the inspector in a side toolbox host");
|
||||
let {toolbox, inspector} = yield openInspectorForURL("about:blank", "side");
|
||||
|
||||
let button = inspector.panelDoc.getElementById("inspector-pane-toggle");
|
||||
ok(button, "The toggle button exists in the DOM");
|
||||
is(button.parentNode.id, "inspector-toolbar", "The toggle button is in the toolbar");
|
||||
ok(!button.hasAttribute("pane-collapsed"), "The button is in expanded state");
|
||||
ok(!button.getClientRects().length, "The button is hidden");
|
||||
|
||||
info("Switch the host to bottom type");
|
||||
yield toolbox.switchHost("bottom");
|
||||
|
||||
ok(!!button.getClientRects().length, "The button is visible");
|
||||
});
|
|
@ -0,0 +1,37 @@
|
|||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the sidebar panel toggle button actually works.
|
||||
|
||||
add_task(function* () {
|
||||
let {inspector} = yield openInspectorForURL("about:blank");
|
||||
|
||||
let button = inspector.panelDoc.getElementById("inspector-pane-toggle");
|
||||
let panel = inspector.panelDoc.querySelector("#inspector-sidebar");
|
||||
|
||||
ok(!button.hasAttribute("pane-collapsed"), "The button is in expanded state");
|
||||
|
||||
info("Listen to the end of the animation on the sidebar panel");
|
||||
let onTransitionEnd = once(panel, "transitionend");
|
||||
|
||||
info("Click on the toggle button");
|
||||
EventUtils.synthesizeMouseAtCenter(button, {type: "mousedown"},
|
||||
inspector.panelDoc.defaultView);
|
||||
|
||||
yield onTransitionEnd;
|
||||
ok(button.hasAttribute("pane-collapsed"), "The button is in collapsed state");
|
||||
ok(panel.hasAttribute("pane-collapsed"), "The panel is in collapsed state");
|
||||
|
||||
info("Listen again to the end of the animation on the sidebar panel");
|
||||
onTransitionEnd = once(panel, "transitionend");
|
||||
|
||||
info("Click on the toggle button again");
|
||||
EventUtils.synthesizeMouseAtCenter(button, {type: "mousedown"},
|
||||
inspector.panelDoc.defaultView);
|
||||
|
||||
yield onTransitionEnd;
|
||||
ok(!button.hasAttribute("pane-collapsed"), "The button is in expanded state");
|
||||
ok(!panel.hasAttribute("pane-collapsed"), "The panel is in expanded state");
|
||||
});
|
|
@ -149,12 +149,13 @@ let selectNode = Task.async(function*(selector, inspector, reason="test") {
|
|||
/**
|
||||
* Open the inspector in a tab with given URL.
|
||||
* @param {string} url The URL to open.
|
||||
* @param {String} hostType Optional hostType, as defined in Toolbox.HostType
|
||||
* @return A promise that is resolved once the tab and inspector have loaded
|
||||
* with an object: { tab, toolbox, inspector }.
|
||||
*/
|
||||
let openInspectorForURL = Task.async(function* (url) {
|
||||
let openInspectorForURL = Task.async(function*(url, hostType) {
|
||||
let tab = yield addTab(url);
|
||||
let { inspector, toolbox } = yield openInspector();
|
||||
let { inspector, toolbox } = yield openInspector(null, hostType);
|
||||
return { tab, inspector, toolbox };
|
||||
});
|
||||
|
||||
|
@ -162,9 +163,10 @@ let openInspectorForURL = Task.async(function* (url) {
|
|||
* Open the toolbox, with the inspector tool visible.
|
||||
* @param {Function} cb Optional callback, if you don't want to use the returned
|
||||
* promise
|
||||
* @param {String} hostType Optional hostType, as defined in Toolbox.HostType
|
||||
* @return a promise that resolves when the inspector is ready
|
||||
*/
|
||||
let openInspector = Task.async(function*(cb) {
|
||||
let openInspector = Task.async(function*(cb, hostType) {
|
||||
info("Opening the inspector");
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
|
||||
|
@ -190,7 +192,7 @@ let openInspector = Task.async(function*(cb) {
|
|||
}
|
||||
|
||||
info("Opening the toolbox");
|
||||
toolbox = yield gDevTools.showToolbox(target, "inspector");
|
||||
toolbox = yield gDevTools.showToolbox(target, "inspector", hostType);
|
||||
yield waitForToolboxFrameFocus(toolbox);
|
||||
inspector = toolbox.getPanel("inspector");
|
||||
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* This file contains the base line graph that all Performance line graphs use.
|
||||
*/
|
||||
|
||||
const {Cc, Ci, Cu, Cr} = require("chrome");
|
||||
|
||||
Cu.import("resource:///modules/devtools/Graphs.jsm");
|
||||
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
||||
|
||||
const { colorUtils: { setAlpha }} = require("devtools/css-color");
|
||||
const { getColor } = require("devtools/shared/theme");
|
||||
|
||||
loader.lazyRequireGetter(this, "ProfilerGlobal",
|
||||
"devtools/shared/profiler/global");
|
||||
loader.lazyRequireGetter(this, "TimelineGlobal",
|
||||
"devtools/shared/timeline/global");
|
||||
|
||||
const HEIGHT = 35; // px
|
||||
const STROKE_WIDTH = 1; // px
|
||||
const DAMPEN_VALUES = 0.95;
|
||||
const CLIPHEAD_LINE_COLOR = "#666";
|
||||
const SELECTION_LINE_COLOR = "#555";
|
||||
const SELECTION_BACKGROUND_COLOR_NAME = "highlight-blue";
|
||||
const FRAMERATE_GRAPH_COLOR_NAME = "highlight-green";
|
||||
const MEMORY_GRAPH_COLOR_NAME = "highlight-blue";
|
||||
|
||||
/**
|
||||
* A base class for performance graphs to inherit from.
|
||||
*
|
||||
* @param nsIDOMNode parent
|
||||
* The parent node holding the overview.
|
||||
* @param string metric
|
||||
* The unit of measurement for this graph.
|
||||
*/
|
||||
function PerformanceGraph(parent, metric) {
|
||||
LineGraphWidget.call(this, parent, { metric });
|
||||
this.setTheme();
|
||||
}
|
||||
|
||||
PerformanceGraph.prototype = Heritage.extend(LineGraphWidget.prototype, {
|
||||
strokeWidth: STROKE_WIDTH,
|
||||
dampenValuesFactor: DAMPEN_VALUES,
|
||||
fixedHeight: HEIGHT,
|
||||
clipheadLineColor: CLIPHEAD_LINE_COLOR,
|
||||
selectionLineColor: SELECTION_LINE_COLOR,
|
||||
withTooltipArrows: false,
|
||||
withFixedTooltipPositions: true,
|
||||
|
||||
/**
|
||||
* Disables selection and empties this graph.
|
||||
*/
|
||||
clearView: function() {
|
||||
this.selectionEnabled = false;
|
||||
this.dropSelection();
|
||||
this.setData([]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the theme via `theme` to either "light" or "dark",
|
||||
* and updates the internal styling to match. Requires a redraw
|
||||
* to see the effects.
|
||||
*/
|
||||
setTheme: function (theme) {
|
||||
theme = theme || "light";
|
||||
let mainColor = getColor(this.mainColor || "highlight-blue", theme);
|
||||
this.backgroundColor = getColor("body-background", theme);
|
||||
this.strokeColor = mainColor;
|
||||
this.backgroundGradientStart = setAlpha(mainColor, 0.2);
|
||||
this.backgroundGradientEnd = setAlpha(mainColor, 0.2);
|
||||
this.selectionBackgroundColor = setAlpha(getColor(SELECTION_BACKGROUND_COLOR_NAME, theme), 0.25);
|
||||
this.selectionStripesColor = "rgba(255, 255, 255, 0.1)";
|
||||
this.maximumLineColor = setAlpha(mainColor, 0.4);
|
||||
this.averageLineColor = setAlpha(mainColor, 0.7);
|
||||
this.minimumLineColor = setAlpha(mainColor, 0.9);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Constructor for the framerate graph. Inherits from PerformanceGraph.
|
||||
*
|
||||
* @param nsIDOMNode parent
|
||||
* The parent node holding the overview.
|
||||
*/
|
||||
function FramerateGraph(parent) {
|
||||
PerformanceGraph.call(this, parent, ProfilerGlobal.L10N.getStr("graphs.fps"));
|
||||
}
|
||||
|
||||
FramerateGraph.prototype = Heritage.extend(PerformanceGraph.prototype, {
|
||||
mainColor: FRAMERATE_GRAPH_COLOR_NAME
|
||||
});
|
||||
|
||||
exports.FramerateGraph = FramerateGraph;
|
||||
|
||||
/**
|
||||
* Constructor for the memory graph. Inherits from PerformanceGraph.
|
||||
*
|
||||
* @param nsIDOMNode parent
|
||||
* The parent node holding the overview.
|
||||
*/
|
||||
function MemoryGraph(parent) {
|
||||
PerformanceGraph.call(this, parent, TimelineGlobal.L10N.getStr("graphs.memory"));
|
||||
}
|
||||
|
||||
MemoryGraph.prototype = Heritage.extend(PerformanceGraph.prototype, {
|
||||
mainColor: MEMORY_GRAPH_COLOR_NAME
|
||||
});
|
||||
|
||||
exports.MemoryGraph = MemoryGraph;
|
|
@ -7,6 +7,7 @@ EXTRA_JS_MODULES.devtools.performance += [
|
|||
'modules/compatibility.js',
|
||||
'modules/front.js',
|
||||
'modules/io.js',
|
||||
'modules/performance-graphs.js',
|
||||
'modules/recording-model.js',
|
||||
'modules/recording-utils.js',
|
||||
'panel.js'
|
||||
|
|
|
@ -27,10 +27,12 @@ devtools.lazyRequireGetter(this, "RecordingUtils",
|
|||
"devtools/performance/recording-utils", true);
|
||||
devtools.lazyRequireGetter(this, "RecordingModel",
|
||||
"devtools/performance/recording-model", true);
|
||||
devtools.lazyRequireGetter(this, "FramerateGraph",
|
||||
"devtools/performance/performance-graphs", true);
|
||||
devtools.lazyRequireGetter(this, "MemoryGraph",
|
||||
"devtools/performance/performance-graphs", true);
|
||||
devtools.lazyRequireGetter(this, "MarkersOverview",
|
||||
"devtools/shared/timeline/markers-overview", true);
|
||||
devtools.lazyRequireGetter(this, "MemoryOverview",
|
||||
"devtools/shared/timeline/memory-overview", true);
|
||||
devtools.lazyRequireGetter(this, "Waterfall",
|
||||
"devtools/shared/timeline/waterfall", true);
|
||||
devtools.lazyRequireGetter(this, "MarkerDetails",
|
||||
|
@ -48,14 +50,14 @@ devtools.lazyRequireGetter(this, "OptionsView",
|
|||
|
||||
devtools.lazyImporter(this, "CanvasGraphUtils",
|
||||
"resource:///modules/devtools/Graphs.jsm");
|
||||
devtools.lazyImporter(this, "LineGraphWidget",
|
||||
"resource:///modules/devtools/Graphs.jsm");
|
||||
devtools.lazyImporter(this, "FlameGraphUtils",
|
||||
"resource:///modules/devtools/FlameGraph.jsm");
|
||||
devtools.lazyImporter(this, "FlameGraph",
|
||||
"resource:///modules/devtools/FlameGraph.jsm");
|
||||
devtools.lazyImporter(this, "SideMenuWidget",
|
||||
"resource:///modules/devtools/SideMenuWidget.jsm");
|
||||
devtools.lazyImporter(this, "PluralForm",
|
||||
"resource://gre/modules/PluralForm.jsm");
|
||||
|
||||
const BRANCH_NAME = "devtools.performance.ui.";
|
||||
|
||||
|
|
|
@ -99,6 +99,7 @@ support-files =
|
|||
[browser_profiler_tree-model-04.js]
|
||||
[browser_profiler_tree-model-05.js]
|
||||
[browser_profiler_tree-model-06.js]
|
||||
[browser_profiler_tree-model-07.js]
|
||||
[browser_profiler_tree-view-01.js]
|
||||
[browser_profiler_tree-view-02.js]
|
||||
[browser_profiler_tree-view-03.js]
|
||||
|
@ -106,5 +107,6 @@ support-files =
|
|||
[browser_profiler_tree-view-05.js]
|
||||
[browser_profiler_tree-view-06.js]
|
||||
[browser_profiler_tree-view-07.js]
|
||||
[browser_profiler_tree-view-08.js]
|
||||
[browser_timeline_blueprint.js]
|
||||
[browser_timeline_filters.js]
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that when displaying only content nodes, platform nodes are generalized.
|
||||
*/
|
||||
|
||||
let { CATEGORY_MASK } = devtools.require("devtools/shared/profiler/global");
|
||||
|
||||
function test() {
|
||||
let { ThreadNode } = devtools.require("devtools/shared/profiler/tree-model");
|
||||
let url = (n) => `http://content/${n}`;
|
||||
|
||||
// Create a root node from a given samples array.
|
||||
|
||||
let root = new ThreadNode(gSamples, { contentOnly: true });
|
||||
|
||||
/*
|
||||
* should have a tree like:
|
||||
* root
|
||||
* - (JS)
|
||||
* - A
|
||||
* - (GC)
|
||||
* - B
|
||||
* - C
|
||||
* - D
|
||||
* - E
|
||||
* - F
|
||||
* - (JS)
|
||||
*/
|
||||
|
||||
// Test the root node.
|
||||
|
||||
is(Object.keys(root.calls).length, 2, "root has 2 children");
|
||||
ok(root.calls[url("A")], "root has content child");
|
||||
ok(root.calls["64"], "root has platform generalized child");
|
||||
is(Object.keys(root.calls["64"].calls).length, 0, "platform generalized child is a leaf.");
|
||||
|
||||
ok(root.calls[url("A")].calls["128"], "A has platform generalized child of another type");
|
||||
is(Object.keys(root.calls[url("A")].calls["128"].calls).length, 0, "second generalized type is a leaf.");
|
||||
|
||||
ok(root.calls[url("A")].calls[url("E")].calls[url("F")].calls["64"],
|
||||
"a second leaf of the first generalized type exists deep in the tree.");
|
||||
ok(root.calls[url("A")].calls["128"], "A has platform generalized child of another type");
|
||||
|
||||
is(root.calls["64"].category, root.calls[url("A")].calls[url("E")].calls[url("F")].calls["64"].category,
|
||||
"generalized frames of same type are duplicated in top-down view");
|
||||
finish();
|
||||
}
|
||||
|
||||
let gSamples = [{
|
||||
time: 5,
|
||||
frames: [
|
||||
{ location: "(root)" },
|
||||
{ location: "http://content/A" },
|
||||
{ location: "http://content/B" },
|
||||
{ location: "http://content/C" }
|
||||
]
|
||||
}, {
|
||||
time: 5 + 6,
|
||||
frames: [
|
||||
{ location: "(root)" },
|
||||
{ location: "http://content/A" },
|
||||
{ location: "http://content/B" },
|
||||
{ location: "contentY", category: CATEGORY_MASK("css") },
|
||||
{ location: "http://content/D" }
|
||||
]
|
||||
}, {
|
||||
time: 5 + 6 + 7,
|
||||
frames: [
|
||||
{ location: "(root)" },
|
||||
{ location: "http://content/A" },
|
||||
{ location: "contentY", category: CATEGORY_MASK("css") },
|
||||
{ location: "http://content/E" },
|
||||
{ location: "http://content/F" },
|
||||
{ location: "contentY", category: CATEGORY_MASK("js") },
|
||||
]
|
||||
}, {
|
||||
time: 5 + 20,
|
||||
frames: [
|
||||
{ location: "(root)" },
|
||||
{ location: "contentX", category: CATEGORY_MASK("js") },
|
||||
]
|
||||
}, {
|
||||
time: 5 + 25,
|
||||
frames: [
|
||||
{ location: "(root)" },
|
||||
{ location: "http://content/A" },
|
||||
{ location: "contentZ", category: CATEGORY_MASK("gc", 1) },
|
||||
]
|
||||
}];
|
|
@ -0,0 +1,104 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that the profiler's tree view renders generalized platform data
|
||||
* when `contentOnly` is on correctly.
|
||||
*/
|
||||
|
||||
let { CATEGORY_MASK } = devtools.require("devtools/shared/profiler/global");
|
||||
|
||||
function test() {
|
||||
let { ThreadNode } = devtools.require("devtools/shared/profiler/tree-model");
|
||||
let { CallView } = devtools.require("devtools/shared/profiler/tree-view");
|
||||
|
||||
/*
|
||||
* should have a tree like:
|
||||
* root
|
||||
* - A
|
||||
* - B
|
||||
* - C
|
||||
* - D
|
||||
* - E
|
||||
* - F
|
||||
* - (JS)
|
||||
* - (GC)
|
||||
* - (JS)
|
||||
*/
|
||||
|
||||
let threadNode = new ThreadNode(gSamples, { contentOnly: true });
|
||||
let treeRoot = new CallView({ frame: threadNode, autoExpandDepth: 10 });
|
||||
|
||||
let container = document.createElement("vbox");
|
||||
treeRoot.attachTo(container);
|
||||
|
||||
let A = treeRoot.getChild(0);
|
||||
let JS = treeRoot.getChild(1);
|
||||
let GC = A.getChild(1);
|
||||
let JS2 = A.getChild(2).getChild().getChild();
|
||||
|
||||
is(JS.target.getAttribute("category"), "js",
|
||||
"Generalized JS node has correct category");
|
||||
is(JS.target.getAttribute("tooltiptext"), "JIT",
|
||||
"Generalized JS node has correct category");
|
||||
is(JS.target.querySelector(".call-tree-name").getAttribute("value"), "JIT",
|
||||
"Generalized JS node has correct display value as just the category name.");
|
||||
|
||||
is(JS2.target.getAttribute("category"), "js",
|
||||
"Generalized second JS node has correct category");
|
||||
is(JS2.target.getAttribute("tooltiptext"), "JIT",
|
||||
"Generalized second JS node has correct category");
|
||||
is(JS2.target.querySelector(".call-tree-name").getAttribute("value"), "JIT",
|
||||
"Generalized second JS node has correct display value as just the category name.");
|
||||
|
||||
is(GC.target.getAttribute("category"), "gc",
|
||||
"Generalized GC node has correct category");
|
||||
is(GC.target.getAttribute("tooltiptext"), "GC",
|
||||
"Generalized GC node has correct category");
|
||||
is(GC.target.querySelector(".call-tree-name").getAttribute("value"), "GC",
|
||||
"Generalized GC node has correct display value as just the category name.");
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
let gSamples = [{
|
||||
time: 5,
|
||||
frames: [
|
||||
{ location: "(root)" },
|
||||
{ location: "http://content/A" },
|
||||
{ location: "http://content/B" },
|
||||
{ location: "http://content/C" }
|
||||
]
|
||||
}, {
|
||||
time: 5 + 6,
|
||||
frames: [
|
||||
{ location: "(root)" },
|
||||
{ location: "http://content/A" },
|
||||
{ location: "http://content/B" },
|
||||
{ location: "contentY", category: CATEGORY_MASK("css") },
|
||||
{ location: "http://content/D" }
|
||||
]
|
||||
}, {
|
||||
time: 5 + 6 + 7,
|
||||
frames: [
|
||||
{ location: "(root)" },
|
||||
{ location: "http://content/A" },
|
||||
{ location: "contentY", category: CATEGORY_MASK("css") },
|
||||
{ location: "http://content/E" },
|
||||
{ location: "http://content/F" },
|
||||
{ location: "contentY", category: CATEGORY_MASK("js") },
|
||||
]
|
||||
}, {
|
||||
time: 5 + 20,
|
||||
frames: [
|
||||
{ location: "(root)" },
|
||||
{ location: "contentX", category: CATEGORY_MASK("js") },
|
||||
]
|
||||
}, {
|
||||
time: 5 + 25,
|
||||
frames: [
|
||||
{ location: "(root)" },
|
||||
{ location: "http://content/A" },
|
||||
{ location: "contentZ", category: CATEGORY_MASK("gc", 1) },
|
||||
]
|
||||
}];
|
|
@ -17,10 +17,8 @@ function spawnTest () {
|
|||
for (let [key, value] of Iterator(TIMELINE_BLUEPRINT)) {
|
||||
ok("group" in value,
|
||||
"Each entry in the timeline blueprint contains a `group` key.");
|
||||
ok("fill" in value,
|
||||
"Each entry in the timeline blueprint contains a `fill` key.");
|
||||
ok("stroke" in value,
|
||||
"Each entry in the timeline blueprint contains a `stroke` key.");
|
||||
ok("colorName" in value,
|
||||
"Each entry in the timeline blueprint contains a `colorName` key.");
|
||||
ok("label" in value,
|
||||
"Each entry in the timeline blueprint contains a `label` key.");
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
const URL_LABEL_TOOLTIP = L10N.getStr("table.url.tooltiptext");
|
||||
const OPTIMIZATION_FAILURE = L10N.getStr("jit.optimizationFailure");
|
||||
const JIT_SAMPLES = L10N.getStr("jit.samples");
|
||||
const JIT_SAMPLES = L10N.getStr("jit.samples2");
|
||||
const JIT_EMPTY_TEXT = L10N.getStr("jit.empty");
|
||||
|
||||
/**
|
||||
|
@ -209,7 +209,8 @@ let JITOptimizationsView = {
|
|||
node.appendChild(icon);
|
||||
}
|
||||
|
||||
desc.textContent = `${lastStrategy} - (${site.samples} ${JIT_SAMPLES})`;
|
||||
let sampleString = PluralForm.get(site.samples, JIT_SAMPLES).replace("#1", site.samples);
|
||||
desc.textContent = `${lastStrategy} – (${sampleString})`;
|
||||
line.textContent = site.data.line;
|
||||
line.className = "opt-line";
|
||||
column.textContent = site.data.column;
|
||||
|
|
|
@ -11,11 +11,9 @@ const OVERVIEW_UPDATE_INTERVAL = 200; // ms
|
|||
const FRAMERATE_GRAPH_LOW_RES_INTERVAL = 100; // ms
|
||||
const FRAMERATE_GRAPH_HIGH_RES_INTERVAL = 16; // ms
|
||||
|
||||
const FRAMERATE_GRAPH_HEIGHT = 40; // px
|
||||
const MARKERS_GRAPH_HEADER_HEIGHT = 14; // px
|
||||
const MARKERS_GRAPH_ROW_HEIGHT = 10; // px
|
||||
const MARKERS_GROUP_VERTICAL_PADDING = 4; // px
|
||||
const MEMORY_GRAPH_HEIGHT = 30; // px
|
||||
|
||||
/**
|
||||
* View handler for the overview panel's time view, displaying
|
||||
|
@ -101,6 +99,11 @@ let OverviewView = {
|
|||
setTheme: function (options={}) {
|
||||
let theme = options.theme || PerformanceController.getTheme();
|
||||
|
||||
if (this.framerateGraph) {
|
||||
this.framerateGraph.setTheme(theme);
|
||||
this.framerateGraph.refresh({ force: options.redraw });
|
||||
}
|
||||
|
||||
if (this.markersOverview) {
|
||||
this.markersOverview.setTheme(theme);
|
||||
this.markersOverview.refresh({ force: options.redraw });
|
||||
|
@ -191,8 +194,7 @@ let OverviewView = {
|
|||
yield this.memoryOverview.ready();
|
||||
return true;
|
||||
}
|
||||
this.memoryOverview = new MemoryOverview($("#memory-overview"));
|
||||
this.memoryOverview.fixedHeight = MEMORY_GRAPH_HEIGHT;
|
||||
this.memoryOverview = new MemoryGraph($("#memory-overview"));
|
||||
yield this.memoryOverview.ready();
|
||||
this.setTheme();
|
||||
|
||||
|
@ -216,10 +218,9 @@ let OverviewView = {
|
|||
yield this.framerateGraph.ready();
|
||||
return true;
|
||||
}
|
||||
let metric = L10N.getStr("graphs.fps");
|
||||
this.framerateGraph = new LineGraphWidget($("#time-framerate"), { metric });
|
||||
this.framerateGraph.fixedHeight = FRAMERATE_GRAPH_HEIGHT;
|
||||
this.framerateGraph = new FramerateGraph($("#time-framerate"));
|
||||
yield this.framerateGraph.ready();
|
||||
this.setTheme();
|
||||
|
||||
CanvasGraphUtils.linkAnimation(this.markersOverview, this.framerateGraph);
|
||||
CanvasGraphUtils.linkSelection(this.markersOverview, this.framerateGraph);
|
||||
|
|
|
@ -53,14 +53,10 @@ let ToolbarView = {
|
|||
menuitem.setAttribute("flex", "1");
|
||||
menuitem.setAttribute("label", markerDetails.label);
|
||||
menuitem.setAttribute("marker-type", markerName);
|
||||
menuitem.className = markerDetails.colorName;
|
||||
|
||||
menuitem.addEventListener("command", this._onHiddenMarkersChanged);
|
||||
|
||||
// Style used by pseudo element ::before in performance.inc.css
|
||||
let bulletStyle = `--bullet-bg: ${markerDetails.fill};`
|
||||
bulletStyle += `--bullet-border: ${markerDetails.stroke}`;
|
||||
menuitem.setAttribute("style", bulletStyle);
|
||||
|
||||
$("#performance-filter-menupopup").appendChild(menuitem);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -42,7 +42,6 @@ EXTRA_JS_MODULES.devtools.shared.timeline += [
|
|||
'timeline/global.js',
|
||||
'timeline/marker-details.js',
|
||||
'timeline/markers-overview.js',
|
||||
'timeline/memory-overview.js',
|
||||
'timeline/waterfall.js',
|
||||
]
|
||||
|
||||
|
|
|
@ -4,16 +4,21 @@
|
|||
"use strict";
|
||||
|
||||
const {Cc, Ci, Cu, Cr} = require("chrome");
|
||||
const {extend} = require("sdk/util/object");
|
||||
|
||||
loader.lazyRequireGetter(this, "Services");
|
||||
loader.lazyRequireGetter(this, "L10N",
|
||||
"devtools/shared/profiler/global", true);
|
||||
loader.lazyRequireGetter(this, "CATEGORY_MAPPINGS",
|
||||
"devtools/shared/profiler/global", true);
|
||||
loader.lazyRequireGetter(this, "CATEGORIES",
|
||||
"devtools/shared/profiler/global", true);
|
||||
loader.lazyRequireGetter(this, "CATEGORY_JIT",
|
||||
"devtools/shared/profiler/global", true);
|
||||
loader.lazyRequireGetter(this, "JITOptimizations",
|
||||
"devtools/shared/profiler/jit", true);
|
||||
loader.lazyRequireGetter(this, "CATEGORY_OTHER",
|
||||
"devtools/shared/profiler/global", true);
|
||||
|
||||
const CHROME_SCHEMES = ["chrome://", "resource://", "jar:file://"];
|
||||
const CONTENT_SCHEMES = ["http://", "https://", "file://", "app://"];
|
||||
|
@ -97,7 +102,7 @@ ThreadNode.prototype = {
|
|||
// should be taken into consideration.
|
||||
if (options.contentOnly) {
|
||||
// The (root) node is not considered a content function, it'll be removed.
|
||||
sampleFrames = sampleFrames.filter(isContent);
|
||||
sampleFrames = filterPlatformData(sampleFrames);
|
||||
} else {
|
||||
// Remove the (root) node manually.
|
||||
sampleFrames = sampleFrames.slice(1);
|
||||
|
@ -161,8 +166,11 @@ ThreadNode.prototype = {
|
|||
* The category type of this function call ("js", "graphics" etc.).
|
||||
* @param number allocations
|
||||
* The number of memory allocations performed in this frame.
|
||||
* @param boolean isMetaCategory
|
||||
* Whether or not this is a platform node that should appear as a
|
||||
* generalized meta category or not.
|
||||
*/
|
||||
function FrameNode({ location, line, column, category, allocations }) {
|
||||
function FrameNode({ location, line, column, category, allocations, isMetaCategory }) {
|
||||
this.location = location;
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
|
@ -173,6 +181,7 @@ function FrameNode({ location, line, column, category, allocations }) {
|
|||
this.duration = 0;
|
||||
this.calls = {};
|
||||
this._optimizations = null;
|
||||
this.isMetaCategory = isMetaCategory;
|
||||
}
|
||||
|
||||
FrameNode.prototype = {
|
||||
|
@ -202,8 +211,12 @@ FrameNode.prototype = {
|
|||
if (!frame) {
|
||||
return;
|
||||
}
|
||||
let location = frame.location;
|
||||
let child = _store[location] || (_store[location] = new FrameNode(frame));
|
||||
// If we are only displaying content, then platform data will have
|
||||
// a `isMetaCategory` property. Group by category (GC, Graphics, etc.)
|
||||
// to group together frames so they're displayed only once, since we don't
|
||||
// need the location anyway.
|
||||
let key = frame.isMetaCategory ? frame.category : frame.location;
|
||||
let child = _store[key] || (_store[key] = new FrameNode(frame));
|
||||
child.sampleTimes.push({ start: time, end: time + duration });
|
||||
child.samples++;
|
||||
child.duration += duration;
|
||||
|
@ -273,7 +286,8 @@ FrameNode.prototype = {
|
|||
line: line,
|
||||
column: column,
|
||||
categoryData: categoryData,
|
||||
isContent: !!isContent(this)
|
||||
isContent: !!isContent(this),
|
||||
isMetaCategory: this.isMetaCategory
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -332,3 +346,47 @@ function nsIURL(url) {
|
|||
|
||||
// The cache used in the `nsIURL` function.
|
||||
let gNSURLStore = new Map();
|
||||
|
||||
/**
|
||||
* This filters out platform data frames in a sample. With latest performance
|
||||
* tool in Fx40, when displaying only content, we still filter out all platform data,
|
||||
* except we generalize platform data that are leaves. We do this because of two
|
||||
* observations:
|
||||
*
|
||||
* 1. The leaf is where time is _actually_ being spent, so we _need_ to show it
|
||||
* to developers in some way to give them accurate profiling data. We decide to
|
||||
* split the platform into various category buckets and just show time spent in
|
||||
* each bucket.
|
||||
*
|
||||
* 2. The calls leading to the leaf _aren't_ where we are spending time, but
|
||||
* _do_ give the developer context for how they got to the leaf where they _are_
|
||||
* spending time. For non-platform hackers, the non-leaf platform frames don't
|
||||
* give any meaningful context, and so we can safely filter them out.
|
||||
*
|
||||
* Example transformations:
|
||||
* Before: PlatformA -> PlatformB -> ContentA -> ContentB
|
||||
* After: ContentA -> ContentB
|
||||
*
|
||||
* Before: PlatformA -> ContentA -> PlatformB -> PlatformC
|
||||
* After: ContentA -> Category(PlatformC)
|
||||
*/
|
||||
function filterPlatformData (frames) {
|
||||
let result = [];
|
||||
let last = frames.length - 1;
|
||||
let frame;
|
||||
|
||||
for (let i = 0; i < frames.length; i++) {
|
||||
frame = frames[i];
|
||||
if (isContent(frame)) {
|
||||
result.push(frame);
|
||||
} else if (last === i) {
|
||||
// Extend here so we're not destructively editing
|
||||
// the original profiler data. Set isMetaCategory `true`,
|
||||
// and ensure we have a category set by default, because that's how
|
||||
// the generalized frame nodes are organized.
|
||||
result.push(extend({ isMetaCategory: true, category: CATEGORY_OTHER }, frame));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -187,7 +187,8 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
|||
targetNode.className = "call-tree-item";
|
||||
targetNode.setAttribute("origin", frameInfo.isContent ? "content" : "chrome");
|
||||
targetNode.setAttribute("category", frameInfo.categoryData.abbrev || "");
|
||||
targetNode.setAttribute("tooltiptext", this.frame.location || "");
|
||||
targetNode.setAttribute("tooltiptext", frameInfo.isMetaCategory ? frameInfo.categoryData.label :
|
||||
this.frame.location || "");
|
||||
if (this.hidden) {
|
||||
targetNode.style.display = "none";
|
||||
}
|
||||
|
@ -309,48 +310,53 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
|||
nameNode.className = "plain call-tree-name";
|
||||
nameNode.setAttribute("flex", "1");
|
||||
nameNode.setAttribute("crop", "end");
|
||||
nameNode.setAttribute("value", frameInfo.functionName || "");
|
||||
nameNode.setAttribute("value", frameInfo.isMetaCategory
|
||||
? frameInfo.categoryData.label
|
||||
: frameInfo.functionName || "");
|
||||
cell.appendChild(nameNode);
|
||||
|
||||
let urlNode = this.document.createElement("label");
|
||||
urlNode.className = "plain call-tree-url";
|
||||
urlNode.setAttribute("flex", "1");
|
||||
urlNode.setAttribute("crop", "end");
|
||||
urlNode.setAttribute("value", frameInfo.fileName || "");
|
||||
urlNode.setAttribute("tooltiptext", URL_LABEL_TOOLTIP + " → " + frameInfo.url);
|
||||
urlNode.addEventListener("mousedown", this._onUrlClick);
|
||||
cell.appendChild(urlNode);
|
||||
// Don't render detailed labels for meta category frames
|
||||
if (!frameInfo.isMetaCategory) {
|
||||
let urlNode = this.document.createElement("label");
|
||||
urlNode.className = "plain call-tree-url";
|
||||
urlNode.setAttribute("flex", "1");
|
||||
urlNode.setAttribute("crop", "end");
|
||||
urlNode.setAttribute("value", frameInfo.fileName || "");
|
||||
urlNode.setAttribute("tooltiptext", URL_LABEL_TOOLTIP + " → " + frameInfo.url);
|
||||
urlNode.addEventListener("mousedown", this._onUrlClick);
|
||||
cell.appendChild(urlNode);
|
||||
|
||||
let lineNode = this.document.createElement("label");
|
||||
lineNode.className = "plain call-tree-line";
|
||||
lineNode.setAttribute("value", frameInfo.line ? ":" + frameInfo.line : "");
|
||||
cell.appendChild(lineNode);
|
||||
let lineNode = this.document.createElement("label");
|
||||
lineNode.className = "plain call-tree-line";
|
||||
lineNode.setAttribute("value", frameInfo.line ? ":" + frameInfo.line : "");
|
||||
cell.appendChild(lineNode);
|
||||
|
||||
let columnNode = this.document.createElement("label");
|
||||
columnNode.className = "plain call-tree-column";
|
||||
columnNode.setAttribute("value", frameInfo.column ? ":" + frameInfo.column : "");
|
||||
cell.appendChild(columnNode);
|
||||
let columnNode = this.document.createElement("label");
|
||||
columnNode.className = "plain call-tree-column";
|
||||
columnNode.setAttribute("value", frameInfo.column ? ":" + frameInfo.column : "");
|
||||
cell.appendChild(columnNode);
|
||||
|
||||
let hostNode = this.document.createElement("label");
|
||||
hostNode.className = "plain call-tree-host";
|
||||
hostNode.setAttribute("value", frameInfo.hostName || "");
|
||||
cell.appendChild(hostNode);
|
||||
let hostNode = this.document.createElement("label");
|
||||
hostNode.className = "plain call-tree-host";
|
||||
hostNode.setAttribute("value", frameInfo.hostName || "");
|
||||
cell.appendChild(hostNode);
|
||||
|
||||
let zoomNode = this.document.createElement("button");
|
||||
zoomNode.className = "plain call-tree-zoom";
|
||||
zoomNode.setAttribute("tooltiptext", ZOOM_BUTTON_TOOLTIP);
|
||||
zoomNode.addEventListener("mousedown", this._onZoomClick);
|
||||
cell.appendChild(zoomNode);
|
||||
let zoomNode = this.document.createElement("button");
|
||||
zoomNode.className = "plain call-tree-zoom";
|
||||
zoomNode.setAttribute("tooltiptext", ZOOM_BUTTON_TOOLTIP);
|
||||
zoomNode.addEventListener("mousedown", this._onZoomClick);
|
||||
cell.appendChild(zoomNode);
|
||||
|
||||
let spacerNode = this.document.createElement("spacer");
|
||||
spacerNode.setAttribute("flex", "10000");
|
||||
cell.appendChild(spacerNode);
|
||||
let spacerNode = this.document.createElement("spacer");
|
||||
spacerNode.setAttribute("flex", "10000");
|
||||
cell.appendChild(spacerNode);
|
||||
|
||||
let categoryNode = this.document.createElement("label");
|
||||
categoryNode.className = "plain call-tree-category";
|
||||
categoryNode.style.color = frameInfo.categoryData.color;
|
||||
categoryNode.setAttribute("value", frameInfo.categoryData.label || "");
|
||||
cell.appendChild(categoryNode);
|
||||
let categoryNode = this.document.createElement("label");
|
||||
categoryNode.className = "plain call-tree-category";
|
||||
categoryNode.style.color = frameInfo.categoryData.color;
|
||||
categoryNode.setAttribute("value", frameInfo.categoryData.label || "");
|
||||
cell.appendChild(categoryNode);
|
||||
}
|
||||
|
||||
let hasDescendants = Object.keys(this.frame.calls).length > 0;
|
||||
if (hasDescendants == false) {
|
||||
|
|
|
@ -18,9 +18,11 @@ const L10N = new ViewHelpers.L10N(STRINGS_URI);
|
|||
* to marker names, while the values are objects with the following format:
|
||||
* - group: the row index in the timeline overview graph; multiple markers
|
||||
* can be added on the same row. @see <overview.js/buildGraphImage>
|
||||
* - fill: a fill color used when drawing the marker
|
||||
* - stroke: a stroke color used when drawing the marker
|
||||
* - label: the label used in the waterfall to identify the marker
|
||||
* - colorName: the name of the DevTools color used for this marker. If adding
|
||||
* a new color, be sure to check that there's an entry for
|
||||
* `.marker-details-bullet.{COLORNAME}` for the equivilent entry.
|
||||
* https://developer.mozilla.org/en-US/docs/Tools/DevToolsColors
|
||||
*
|
||||
* Whenever this is changed, browser_timeline_waterfall-styles.js *must* be
|
||||
* updated as well.
|
||||
|
@ -28,38 +30,32 @@ const L10N = new ViewHelpers.L10N(STRINGS_URI);
|
|||
const TIMELINE_BLUEPRINT = {
|
||||
"Styles": {
|
||||
group: 0,
|
||||
fill: "hsl(285,50%,68%)",
|
||||
stroke: "hsl(285,50%,48%)",
|
||||
colorName: "highlight-pink",
|
||||
label: L10N.getStr("timeline.label.styles2")
|
||||
},
|
||||
"Reflow": {
|
||||
group: 0,
|
||||
fill: "hsl(285,50%,68%)",
|
||||
stroke: "hsl(285,50%,48%)",
|
||||
colorName: "highlight-pink",
|
||||
label: L10N.getStr("timeline.label.reflow2")
|
||||
},
|
||||
"Paint": {
|
||||
group: 0,
|
||||
fill: "hsl(104,57%,71%)",
|
||||
stroke: "hsl(104,57%,51%)",
|
||||
colorName: "highlight-green",
|
||||
label: L10N.getStr("timeline.label.paint")
|
||||
},
|
||||
"DOMEvent": {
|
||||
group: 1,
|
||||
fill: "hsl(39,82%,69%)",
|
||||
stroke: "hsl(39,82%,49%)",
|
||||
colorName: "highlight-lightorange",
|
||||
label: L10N.getStr("timeline.label.domevent")
|
||||
},
|
||||
"Javascript": {
|
||||
group: 1,
|
||||
fill: "hsl(39,82%,69%)",
|
||||
stroke: "hsl(39,82%,49%)",
|
||||
colorName: "highlight-lightorange",
|
||||
label: L10N.getStr("timeline.label.javascript2")
|
||||
},
|
||||
"ConsoleTime": {
|
||||
group: 2,
|
||||
fill: "hsl(0,0%,80%)",
|
||||
stroke: "hsl(0,0%,60%)",
|
||||
colorName: "highlight-bluegrey",
|
||||
label: L10N.getStr("timeline.label.consoleTime")
|
||||
},
|
||||
};
|
||||
|
|
|
@ -64,9 +64,7 @@ MarkerDetails.prototype = {
|
|||
hbox.setAttribute("align", "center");
|
||||
|
||||
let bullet = this._document.createElement("hbox");
|
||||
bullet.className = "marker-details-bullet";
|
||||
bullet.style.backgroundColor = blueprint.fill;
|
||||
bullet.style.borderColor = blueprint.stroke;
|
||||
bullet.className = `marker-details-bullet ${blueprint.colorName}`;
|
||||
|
||||
let label = this._document.createElement("label");
|
||||
label.className = "marker-details-type";
|
||||
|
|
|
@ -169,12 +169,8 @@ MarkersOverview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
|||
let top = headerHeight + style.group * groupHeight + groupPadding / 2;
|
||||
let height = groupHeight - groupPadding;
|
||||
|
||||
let gradient = ctx.createLinearGradient(0, top, 0, top + height);
|
||||
gradient.addColorStop(OVERVIEW_MARKERS_COLOR_STOPS[0], style.stroke);
|
||||
gradient.addColorStop(OVERVIEW_MARKERS_COLOR_STOPS[1], style.fill);
|
||||
gradient.addColorStop(OVERVIEW_MARKERS_COLOR_STOPS[2], style.fill);
|
||||
gradient.addColorStop(OVERVIEW_MARKERS_COLOR_STOPS[3], style.stroke);
|
||||
ctx.fillStyle = gradient;
|
||||
let color = getColor(style.colorName, this.theme);
|
||||
ctx.fillStyle = color;
|
||||
ctx.beginPath();
|
||||
|
||||
for (let { start, end } of batch) {
|
||||
|
@ -226,7 +222,7 @@ MarkersOverview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
|||
* to see the effects.
|
||||
*/
|
||||
setTheme: function (theme) {
|
||||
theme = theme || "light";
|
||||
this.theme = theme = theme || "light";
|
||||
this.backgroundColor = getColor("body-background", theme);
|
||||
this.selectionBackgroundColor = setAlpha(getColor("selection-background", theme), 0.25);
|
||||
this.selectionStripesColor = setAlpha("#fff", 0.1);
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* This file contains the "memory overview" graph, a simple representation of
|
||||
* of all the memory measurements taken while streaming the timeline data.
|
||||
*/
|
||||
|
||||
const {Cc, Ci, Cu, Cr} = require("chrome");
|
||||
|
||||
Cu.import("resource:///modules/devtools/Graphs.jsm");
|
||||
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
||||
|
||||
const { colorUtils: { setAlpha }} = require("devtools/css-color");
|
||||
const { getColor } = require("devtools/shared/theme");
|
||||
|
||||
loader.lazyRequireGetter(this, "L10N",
|
||||
"devtools/shared/timeline/global", true);
|
||||
|
||||
const OVERVIEW_DAMPEN_VALUES = 0.95;
|
||||
|
||||
const OVERVIEW_HEIGHT = 30; // px
|
||||
const OVERVIEW_STROKE_WIDTH = 1; // px
|
||||
const OVERVIEW_MAXIMUM_LINE_COLOR = "rgba(0,136,204,0.4)";
|
||||
const OVERVIEW_AVERAGE_LINE_COLOR = "rgba(0,136,204,0.7)";
|
||||
const OVERVIEW_MINIMUM_LINE_COLOR = "rgba(0,136,204,0.9)";
|
||||
const OVERVIEW_CLIPHEAD_LINE_COLOR = "#666";
|
||||
const OVERVIEW_SELECTION_LINE_COLOR = "#555";
|
||||
|
||||
/**
|
||||
* An overview for the memory data.
|
||||
*
|
||||
* @param nsIDOMNode parent
|
||||
* The parent node holding the overview.
|
||||
*/
|
||||
function MemoryOverview(parent) {
|
||||
LineGraphWidget.call(this, parent, { metric: L10N.getStr("graphs.memory") });
|
||||
this.setTheme();
|
||||
}
|
||||
|
||||
MemoryOverview.prototype = Heritage.extend(LineGraphWidget.prototype, {
|
||||
dampenValuesFactor: OVERVIEW_DAMPEN_VALUES,
|
||||
fixedHeight: OVERVIEW_HEIGHT,
|
||||
strokeWidth: OVERVIEW_STROKE_WIDTH,
|
||||
maximumLineColor: OVERVIEW_MAXIMUM_LINE_COLOR,
|
||||
averageLineColor: OVERVIEW_AVERAGE_LINE_COLOR,
|
||||
minimumLineColor: OVERVIEW_MINIMUM_LINE_COLOR,
|
||||
clipheadLineColor: OVERVIEW_CLIPHEAD_LINE_COLOR,
|
||||
selectionLineColor: OVERVIEW_SELECTION_LINE_COLOR,
|
||||
withTooltipArrows: false,
|
||||
withFixedTooltipPositions: true,
|
||||
|
||||
/**
|
||||
* Disables selection and empties this graph.
|
||||
*/
|
||||
clearView: function() {
|
||||
this.selectionEnabled = false;
|
||||
this.dropSelection();
|
||||
this.setData([]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the theme via `theme` to either "light" or "dark",
|
||||
* and updates the internal styling to match. Requires a redraw
|
||||
* to see the effects.
|
||||
*/
|
||||
setTheme: function (theme) {
|
||||
theme = theme || "light";
|
||||
this.backgroundColor = getColor("body-background", theme);
|
||||
this.backgroundGradientStart = setAlpha(getColor("highlight-blue", theme), 0.2);
|
||||
this.backgroundGradientEnd = setAlpha(getColor("highlight-blue", theme), 0.05);
|
||||
this.strokeColor = getColor("highlight-blue", theme);
|
||||
this.selectionBackgroundColor = setAlpha(getColor("selection-background", theme), 0.25);
|
||||
this.selectionStripesColor = "rgba(255, 255, 255, 0.1)";
|
||||
}
|
||||
});
|
||||
|
||||
exports.MemoryOverview = MemoryOverview;
|
|
@ -432,9 +432,7 @@ Waterfall.prototype = {
|
|||
sidebar.setAttribute("align", "center");
|
||||
|
||||
let bullet = this._document.createElement("hbox");
|
||||
bullet.className = "waterfall-marker-bullet";
|
||||
bullet.style.backgroundColor = blueprint.fill;
|
||||
bullet.style.borderColor = blueprint.stroke;
|
||||
bullet.className = `waterfall-marker-bullet ${blueprint.colorName}`;
|
||||
bullet.setAttribute("type", marker.name);
|
||||
sidebar.appendChild(bullet);
|
||||
|
||||
|
@ -483,12 +481,8 @@ Waterfall.prototype = {
|
|||
let offset = this._isRTL ? this._waterfallWidth : 0;
|
||||
|
||||
let bar = this._document.createElement("hbox");
|
||||
bar.className = "waterfall-marker-bar";
|
||||
bar.style.backgroundColor = blueprint.fill;
|
||||
bar.style.borderColor = blueprint.stroke;
|
||||
bar.className = `waterfall-marker-bar ${blueprint.colorName}`;
|
||||
bar.style.transform = "translateX(" + (start - offset) + "px)";
|
||||
// Save border color. It will change when marker is selected.
|
||||
bar.setAttribute("borderColor", blueprint.stroke);
|
||||
bar.setAttribute("type", marker.name);
|
||||
bar.setAttribute("width", Math.max(width, WATERFALL_MARKER_BAR_WIDTH_MIN));
|
||||
waterfall.appendChild(bar);
|
||||
|
|
|
@ -22,6 +22,7 @@ this.EXPORTED_SYMBOLS = ["SideMenuWidget"];
|
|||
* @param nsIDOMNode aNode
|
||||
* The element associated with the widget.
|
||||
* @param Object aOptions
|
||||
* - contextMenu: optional element or element ID that serves as a context menu.
|
||||
* - showArrows: specifies if items should display horizontal arrows.
|
||||
* - showItemCheckboxes: specifies if items should display checkboxes.
|
||||
* - showGroupCheckboxes: specifies if groups should display checkboxes.
|
||||
|
@ -31,7 +32,8 @@ this.SideMenuWidget = function SideMenuWidget(aNode, aOptions={}) {
|
|||
this.window = this.document.defaultView;
|
||||
this._parent = aNode;
|
||||
|
||||
let { showArrows, showItemCheckboxes, showGroupCheckboxes } = aOptions;
|
||||
let { contextMenu, showArrows, showItemCheckboxes, showGroupCheckboxes } = aOptions;
|
||||
this._contextMenu = contextMenu || null;
|
||||
this._showArrows = showArrows || false;
|
||||
this._showItemCheckboxes = showItemCheckboxes || false;
|
||||
this._showGroupCheckboxes = showGroupCheckboxes || false;
|
||||
|
@ -45,6 +47,7 @@ this.SideMenuWidget = function SideMenuWidget(aNode, aOptions={}) {
|
|||
this._list.setAttribute("with-item-checkboxes", this._showItemCheckboxes);
|
||||
this._list.setAttribute("with-group-checkboxes", this._showGroupCheckboxes);
|
||||
this._list.setAttribute("tabindex", "0");
|
||||
this._list.addEventListener("contextmenu", e => this._showContextMenu(e), false);
|
||||
this._list.addEventListener("keypress", e => this.emit("keyPress", e), false);
|
||||
this._list.addEventListener("mousedown", e => this.emit("mousePress", e), false);
|
||||
this._parent.appendChild(this._list);
|
||||
|
@ -389,6 +392,17 @@ SideMenuWidget.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows the contextMenu element.
|
||||
*/
|
||||
_showContextMenu: function(e) {
|
||||
if (!this._contextMenu) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._contextMenu.openPopupAtScreen(e.screenX, e.screenY, true);
|
||||
},
|
||||
|
||||
window: null,
|
||||
document: null,
|
||||
_showArrows: false,
|
||||
|
|
|
@ -198,3 +198,17 @@
|
|||
<!ENTITY debuggerUI.stepping.stepIn2 "VK_SEMICOLON">
|
||||
<!ENTITY debuggerUI.stepping.stepOut1 "VK_F11">
|
||||
<!ENTITY debuggerUI.stepping.stepOut2 "VK_SEMICOLON">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.context.newTab): This is the label
|
||||
- for the Open in New Tab menu item displayed in the context menu of the
|
||||
- debugger sources side menu. This should be the same as
|
||||
- netmonitorUI.context.newTab -->
|
||||
<!ENTITY debuggerUI.context.newTab "Open in New Tab">
|
||||
<!ENTITY debuggerUI.context.newTab.accesskey "O">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.context.copyUrl): This is the label displayed
|
||||
- on the context menu that copies the selected request's url. This should be
|
||||
- the same as netmonitorUI.context.copyUrl -->
|
||||
<!ENTITY debuggerUI.context.copyUrl "Copy URL">
|
||||
<!ENTITY debuggerUI.context.copyUrl.accesskey "C">
|
||||
<!ENTITY debuggerUI.context.copyUrl.key "C">
|
||||
|
|
|
@ -1529,16 +1529,16 @@ folderInvalidPath=Please enter a valid path
|
|||
# The argument (%1$S) is the folder path.
|
||||
folderOpenDirResult=Opened %1$S
|
||||
|
||||
# LOCALIZATION NOTE (rulesDesc) A very short description of the
|
||||
# 'rules' command. See highlightManual for a fuller description of what
|
||||
# LOCALIZATION NOTE (rulersDesc) A very short description of the
|
||||
# 'rulers' command. See rulersManual for a fuller description of what
|
||||
# it does. This string is designed to be shown in a menu alongside the
|
||||
# command name, which is why it should be as short as possible.
|
||||
rulersDesc=Toggle rulers for the page
|
||||
|
||||
# LOCALIZATION NOTE (rulesManual) A fuller description of the 'rules'
|
||||
# LOCALIZATION NOTE (rulersManual) A fuller description of the 'rulers'
|
||||
# command, displayed when the user asks for help on what it does.
|
||||
rulersManual=Toggle the horizontal and vertical rulers for the current page
|
||||
|
||||
# LOCALIZATION NOTE (rulersTooltip) A string displayed as the
|
||||
# tooltip of button in devtools toolbox which toggles the rulers highligher.
|
||||
# tooltip of button in devtools toolbox which toggles the rulers.
|
||||
rulersTooltip=Toggle rulers for the page
|
||||
|
|
|
@ -54,3 +54,13 @@ previewTooltip.image.brokenImage=Could not load the image
|
|||
|
||||
#LOCALIZATION NOTE: Used in the image preview tooltip when the image could not be loaded
|
||||
eventsTooltip.openInDebugger=Open in Debugger
|
||||
|
||||
# LOCALIZATION NOTE (inspector.collapsePane): This is the tooltip for the button
|
||||
# that collapses the right panel (rules, computed, box-model, etc...) in the
|
||||
# inspector UI.
|
||||
inspector.collapsePane=Collapse pane
|
||||
|
||||
# LOCALIZATION NOTE (inspector.expandPane): This is the tooltip for the button
|
||||
# that expands the right panel (rules, computed, box-model, etc...) in the
|
||||
# inspector UI.
|
||||
inspector.expandPane=Expand pane
|
||||
|
|
|
@ -125,10 +125,13 @@ recordingsList.saveDialogAllFilter=All Files
|
|||
# This string is displayed in a tooltip when no JIT optimizations were detected.
|
||||
jit.optimizationFailure=Optimization failed
|
||||
|
||||
# LOCALIZATION NOTE (jit.samples):
|
||||
# This string is displayed for the unit representing thenumber of times a
|
||||
# LOCALIZATION NOTE (jit.samples2):
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
# This string is displayed for the unit representing the number of times a
|
||||
# frame is sampled.
|
||||
jit.samples=samples
|
||||
# "#1" represents the number of samples
|
||||
# example: 30 samples
|
||||
jit.samples2=#1 sample;#1 samples
|
||||
|
||||
# LOCALIZATION NOTE (jit.empty):
|
||||
# This string is displayed when there are no JIT optimizations to display.
|
||||
|
|
|
@ -159,6 +159,13 @@ let ReaderParent = {
|
|||
}
|
||||
},
|
||||
|
||||
buttonClick: function(event) {
|
||||
if (event.button != 0) {
|
||||
return;
|
||||
}
|
||||
this.toggleReaderMode(event);
|
||||
},
|
||||
|
||||
toggleReaderMode: function(event) {
|
||||
let win = event.target.ownerDocument.defaultView;
|
||||
let browser = win.gBrowser.selectedBrowser;
|
||||
|
|
|
@ -39,6 +39,44 @@
|
|||
max-width: 200px !important;
|
||||
}
|
||||
|
||||
/* Expand/collapse panel toolbar button */
|
||||
|
||||
#inspector-pane-toggle {
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
list-style-image: url(debugger-collapse.png);
|
||||
-moz-image-region: rect(0px,16px,16px,0px);
|
||||
}
|
||||
|
||||
#inspector-pane-toggle > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#inspector-pane-toggle[pane-collapsed] {
|
||||
list-style-image: url(debugger-expand.png);
|
||||
}
|
||||
|
||||
#inspector-pane-toggle:active {
|
||||
-moz-image-region: rect(0px,32px,16px,16px);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#inspector-pane-toggle {
|
||||
list-style-image: url(debugger-collapse@2x.png);
|
||||
-moz-image-region: rect(0px,32px,32px,0px);
|
||||
}
|
||||
|
||||
#inspector-pane-toggle[pane-collapsed] {
|
||||
list-style-image: url(debugger-expand@2x.png);
|
||||
}
|
||||
|
||||
#inspector-pane-toggle:active {
|
||||
-moz-image-region: rect(0px,64px,32px,32px);
|
||||
}
|
||||
}
|
||||
|
||||
/* Tooltip: Events */
|
||||
|
||||
#devtools-tooltip-events-container {
|
||||
|
|
|
@ -57,10 +57,7 @@
|
|||
width: 8px;
|
||||
height: 8px;
|
||||
margin: 0 8px;
|
||||
border: 1px solid;
|
||||
border-radius: 1px;
|
||||
background-color: var(--bullet-bg);
|
||||
border-color: var(--bullet-border);
|
||||
}
|
||||
|
||||
/* Recording Notice */
|
||||
|
@ -380,7 +377,6 @@
|
|||
height: 8px;
|
||||
-moz-margin-start: 8px;
|
||||
-moz-margin-end: 6px;
|
||||
border: 1px solid;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
|
@ -391,9 +387,8 @@
|
|||
|
||||
.waterfall-marker-bar {
|
||||
height: 9px;
|
||||
border: 1px solid;
|
||||
border-radius: 1px;
|
||||
transform-origin: left center;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.waterfall-marker-container.selected > .waterfall-sidebar,
|
||||
|
@ -402,11 +397,6 @@
|
|||
color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
.waterfall-marker-container.selected .waterfall-marker-bullet,
|
||||
.waterfall-marker-container.selected .waterfall-marker-bar {
|
||||
border-color: initial !important;
|
||||
}
|
||||
|
||||
.waterfall-marker-location {
|
||||
color: -moz-nativehyperlinktext;
|
||||
}
|
||||
|
@ -426,10 +416,34 @@
|
|||
.marker-details-bullet {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border: 1px solid;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
#performance-filter-menupopup > menuitem.highlight-pink:before,
|
||||
.marker-details-bullet.highlight-pink,
|
||||
.waterfall-marker-bar.highlight-pink,
|
||||
.waterfall-marker-bullet.highlight-pink {
|
||||
background-color: var(--theme-highlight-pink);
|
||||
}
|
||||
#performance-filter-menupopup > menuitem.highlight-bluegrey:before,
|
||||
.marker-details-bullet.highlight-bluegrey,
|
||||
.waterfall-marker-bar.highlight-bluegrey,
|
||||
.waterfall-marker-bullet.highlight-bluegrey {
|
||||
background-color: var(--theme-highlight-bluegrey);
|
||||
}
|
||||
#performance-filter-menupopup > menuitem.highlight-green:before,
|
||||
.marker-details-bullet.highlight-green,
|
||||
.waterfall-marker-bar.highlight-green,
|
||||
.waterfall-marker-bullet.highlight-green {
|
||||
background-color: var(--theme-highlight-green);
|
||||
}
|
||||
#performance-filter-menupopup > menuitem.highlight-lightorange:before,
|
||||
.marker-details-bullet.highlight-lightorange,
|
||||
.waterfall-marker-bar.highlight-lightorange,
|
||||
.waterfall-marker-bullet.highlight-lightorange {
|
||||
background-color: var(--theme-highlight-lightorange);
|
||||
}
|
||||
|
||||
#waterfall-details > * {
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
|
|
@ -6425,11 +6425,7 @@ MOZ_ARG_ENABLE_BOOL(verify-mar,
|
|||
MOZ_VERIFY_MAR_SIGNATURE= )
|
||||
|
||||
if test -n "$MOZ_VERIFY_MAR_SIGNATURE"; then
|
||||
if test "$OS_ARCH" = "WINNT"; then
|
||||
AC_DEFINE(MOZ_VERIFY_MAR_SIGNATURE)
|
||||
else
|
||||
AC_MSG_ERROR([Can only build with --enable-verify-mar with a Windows target])
|
||||
fi
|
||||
AC_DEFINE(MOZ_VERIFY_MAR_SIGNATURE)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
|
|
|
@ -503,7 +503,6 @@ this.AppsUtils = {
|
|||
* Checks if the app role is allowed:
|
||||
* Only certified apps can be themes.
|
||||
* Only privileged or certified apps can be addons.
|
||||
* Langpacks need to be privileged.
|
||||
* @param aRole : the role assigned to this app.
|
||||
* @param aStatus : the APP_STATUS_* for this app.
|
||||
*/
|
||||
|
@ -511,13 +510,6 @@ this.AppsUtils = {
|
|||
if (aRole == "theme" && aStatus !== Ci.nsIPrincipal.APP_STATUS_CERTIFIED) {
|
||||
return false;
|
||||
}
|
||||
if (aRole == "langpack" && aStatus !== Ci.nsIPrincipal.APP_STATUS_PRIVILEGED) {
|
||||
let allow = false;
|
||||
try {
|
||||
allow = Services.prefs.getBoolPref("dom.apps.allow_unsigned_langpacks");
|
||||
} catch(e) {}
|
||||
return allow;
|
||||
}
|
||||
if (!this.allowUnsignedAddons &&
|
||||
(aRole == "addon" &&
|
||||
aStatus !== Ci.nsIPrincipal.APP_STATUS_CERTIFIED &&
|
||||
|
|
|
@ -26,6 +26,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "PermissionsInstaller",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["ImportExport"];
|
||||
|
||||
const kAppArchiveMimeType = "application/openwebapp+zip";
|
||||
|
@ -225,7 +228,12 @@ this.ImportExport = {
|
|||
// |file| now points to application.zip, open it.
|
||||
let appZipReader = Cc["@mozilla.org/libjar/zip-reader;1"]
|
||||
.createInstance(Ci.nsIZipReader);
|
||||
appZipReader.open(file);
|
||||
try {
|
||||
appZipReader.open(file);
|
||||
} catch(e) {
|
||||
throw "InvalidZip";
|
||||
}
|
||||
|
||||
if (!appZipReader.hasEntry("manifest.webapp")) {
|
||||
throw "NoManifestFound";
|
||||
}
|
||||
|
@ -233,10 +241,35 @@ this.ImportExport = {
|
|||
return [readObjectFromZip(appZipReader, "manifest.webapp"), file];
|
||||
},
|
||||
|
||||
// Returns a promise that resolves to the temp file path.
|
||||
_writeBlobToTempFile: function(aBlob) {
|
||||
// Save the blob to a temp file.
|
||||
debug("_writeBlobToTempFile");
|
||||
let path;
|
||||
return new Promise((aResolve, aReject) => {
|
||||
let reader = Cc['@mozilla.org/files/filereader;1']
|
||||
.createInstance(Ci.nsIDOMFileReader);
|
||||
reader.onloadend = () => {
|
||||
path = OS.Path.join(OS.Constants.Path.tmpDir, "app-blob.zip");
|
||||
debug("onloadend path=" + path);
|
||||
OS.File.openUnique(path).then(obj => {
|
||||
path = obj.path;
|
||||
let file = obj.file;
|
||||
debug("openUnique path=" + path);
|
||||
return file.write(new Uint8Array(reader.result))
|
||||
.then(file.close.bind(file))
|
||||
})
|
||||
.then(() => aResolve(path))
|
||||
.catch(aReject);
|
||||
}
|
||||
reader.readAsArrayBuffer(aBlob);
|
||||
});
|
||||
},
|
||||
|
||||
// Imports a blob, returning a Promise that resolves to
|
||||
// [manifestURL, manifest]
|
||||
// Possible errors are:
|
||||
// NoBlobFound, UnsupportedBlobArchive, MissingMetadataFile, IncorrectVersion,
|
||||
// NoBlobFound, InvalidZip, MissingMetadataFile, IncorrectVersion,
|
||||
// AppAlreadyInstalled, DontImportCertifiedApps, InvalidManifest,
|
||||
// InvalidPrivilegeLevel, InvalidOrigin, DuplicateOrigin
|
||||
import: Task.async(function*(aBlob) {
|
||||
|
@ -246,15 +279,15 @@ this.ImportExport = {
|
|||
throw "NoBlobFound";
|
||||
}
|
||||
|
||||
let isFile = aBlob instanceof Ci.nsIDOMFile;
|
||||
if (!isFile) {
|
||||
// XXX: TODO Store the blob on disk.
|
||||
throw "UnsupportedBlobArchive";
|
||||
}
|
||||
|
||||
let isFileBlob = aBlob instanceof Ci.nsIDOMFile;
|
||||
// We can't QI the DOMFile to nsIFile, so we need to create one.
|
||||
let zipFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
zipFile.initWithPath(aBlob.mozFullPath);
|
||||
if (!isFileBlob) {
|
||||
let path = yield this._writeBlobToTempFile(aBlob);
|
||||
zipFile.initWithPath(path);
|
||||
} else {
|
||||
zipFile.initWithPath(aBlob.mozFullPath);
|
||||
}
|
||||
|
||||
debug("Importing from " + zipFile.path);
|
||||
|
||||
|
@ -263,8 +296,13 @@ this.ImportExport = {
|
|||
let manifest;
|
||||
let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"]
|
||||
.createInstance(Ci.nsIZipReader);
|
||||
zipReader.open(zipFile);
|
||||
try {
|
||||
try {
|
||||
zipReader.open(zipFile);
|
||||
} catch(e) {
|
||||
throw "InvalidZip";
|
||||
}
|
||||
|
||||
// Do some sanity checks on the metadata.json and manifest.webapp files.
|
||||
if (!zipReader.hasEntry("metadata.json")) {
|
||||
throw "MissingMetadataFile";
|
||||
|
@ -431,6 +469,9 @@ this.ImportExport = {
|
|||
throw e;
|
||||
} finally {
|
||||
zipReader.close();
|
||||
if (!isFileBlob) {
|
||||
zipFile.remove(false);
|
||||
}
|
||||
}
|
||||
|
||||
return [meta.manifestURL, manifest];
|
||||
|
@ -439,31 +480,37 @@ this.ImportExport = {
|
|||
// Extracts the manifest from a blob, returning a Promise that resolves to
|
||||
// the manifest
|
||||
// Possible errors are:
|
||||
// NoBlobFound, UnsupportedBlobArchive, MissingMetadataFile.
|
||||
// NoBlobFound, InvalidZip, MissingMetadataFile.
|
||||
extractManifest: Task.async(function*(aBlob) {
|
||||
// First, do we even have a blob?
|
||||
if (!aBlob || !aBlob instanceof Ci.nsIDOMBlob) {
|
||||
throw "NoBlobFound";
|
||||
}
|
||||
|
||||
let isFile = aBlob instanceof Ci.nsIDOMFile;
|
||||
if (!isFile) {
|
||||
// XXX: TODO Store the blob on disk.
|
||||
throw "UnsupportedBlobArchive";
|
||||
}
|
||||
|
||||
let isFileBlob = aBlob instanceof Ci.nsIDOMFile;
|
||||
// We can't QI the DOMFile to nsIFile, so we need to create one.
|
||||
let zipFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
zipFile.initWithPath(aBlob.mozFullPath);
|
||||
if (!isFileBlob) {
|
||||
let path = yield this._writeBlobToTempFile(aBlob);
|
||||
zipFile.initWithPath(path);
|
||||
} else {
|
||||
zipFile.initWithPath(aBlob.mozFullPath);
|
||||
}
|
||||
|
||||
debug("extractManifest from " + zipFile.path);
|
||||
|
||||
// Do some sanity checks on the metadata.json and manifest.webapp files.
|
||||
let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"]
|
||||
.createInstance(Ci.nsIZipReader);
|
||||
zipReader.open(zipFile);
|
||||
|
||||
let manifest;
|
||||
try {
|
||||
try {
|
||||
zipReader.open(zipFile);
|
||||
} catch(e) {
|
||||
throw "InvalidZip";
|
||||
}
|
||||
|
||||
if (zipReader.hasEntry("manifest.webapp")) {
|
||||
manifest = readObjectFromZip(zipReader, "manifest.webapp");
|
||||
if (!manifest) {
|
||||
|
@ -484,6 +531,9 @@ this.ImportExport = {
|
|||
}
|
||||
} finally {
|
||||
zipReader.close();
|
||||
if (!isFileBlob) {
|
||||
zipFile.remove(false);
|
||||
}
|
||||
}
|
||||
|
||||
return manifest;
|
||||
|
|
|
@ -3901,8 +3901,16 @@ this.DOMApplicationRegistry = {
|
|||
? Ci.nsIPrincipal.APP_STATUS_PRIVILEGED
|
||||
: Ci.nsIPrincipal.APP_STATUS_INSTALLED;
|
||||
|
||||
let allowUnsignedLangpack = false;
|
||||
try {
|
||||
allowUnsignedLangpack =
|
||||
Services.prefs.getBoolPref("dom.apps.allow_unsigned_langpacks");
|
||||
} catch(e) {}
|
||||
let isLangPack = newManifest.role === "langpack" &&
|
||||
(aIsSigned || allowUnsignedLangpack);
|
||||
|
||||
let status = AppsUtils.getAppManifestStatus(newManifest);
|
||||
if (status > maxStatus) {
|
||||
if (status > maxStatus && !isLangPack) {
|
||||
throw "INVALID_SECURITY_LEVEL";
|
||||
}
|
||||
|
||||
|
|
|
@ -299,6 +299,21 @@ function runTest() {
|
|||
is(request.result, miniManifestURL, "Packaged App uninstalled.");
|
||||
navigator.mozApps.mgmt.onuninstall = null;
|
||||
|
||||
|
||||
// Check that we support memory backed blobs.
|
||||
// The blob here is not a valid app, but that's fine for this test.
|
||||
let blob = new Blob(["This is a test blob."]);
|
||||
navigator.mozApps.mgmt.import(blob)
|
||||
.then(() => {
|
||||
ok(false, "This is not an app!");
|
||||
continueTest();
|
||||
})
|
||||
.catch(aError => {
|
||||
is(aError.name, "InvalidZip", "Memory blob processed.");
|
||||
continueTest();
|
||||
});
|
||||
yield undefined;
|
||||
|
||||
// Check that we restored the app registry.
|
||||
request = navigator.mozApps.mgmt.getAll();
|
||||
request.onerror = cbError;
|
||||
|
|
|
@ -223,6 +223,7 @@ class RefTest(object):
|
|||
|
||||
#Don't use auto-enabled e10s
|
||||
prefs['browser.tabs.remote.autostart.1'] = False
|
||||
prefs['browser.tabs.remote.autostart.2'] = False
|
||||
if options.e10s:
|
||||
prefs['browser.tabs.remote.autostart'] = True
|
||||
|
||||
|
|
|
@ -115,6 +115,10 @@ public final class PrefsHelper {
|
|||
}
|
||||
|
||||
public static void setPref(String pref, Object value) {
|
||||
setPref(pref, value, false);
|
||||
}
|
||||
|
||||
public static void setPref(String pref, Object value, boolean flush) {
|
||||
if (pref == null || pref.length() == 0) {
|
||||
throw new IllegalArgumentException("Pref name must be non-empty");
|
||||
}
|
||||
|
@ -122,6 +126,8 @@ public final class PrefsHelper {
|
|||
try {
|
||||
JSONObject jsonPref = new JSONObject();
|
||||
jsonPref.put("name", pref);
|
||||
jsonPref.put("flush", flush);
|
||||
|
||||
if (value instanceof Boolean) {
|
||||
jsonPref.put("type", "bool");
|
||||
jsonPref.put("value", ((Boolean)value).booleanValue());
|
||||
|
|
До Ширина: | Высота: | Размер: 2.8 KiB После Ширина: | Высота: | Размер: 2.8 KiB |
|
@ -141,9 +141,11 @@ public class GeckoMenuItem implements MenuItem {
|
|||
public View getActionView() {
|
||||
if (mActionProvider != null) {
|
||||
if (getActionEnum() == MenuItem.SHOW_AS_ACTION_IF_ROOM) {
|
||||
return mActionProvider.onCreateActionView(SECONDARY_ACTION_BAR_HISTORY_SIZE, false);
|
||||
return mActionProvider.onCreateActionView(SECONDARY_ACTION_BAR_HISTORY_SIZE,
|
||||
GeckoActionProvider.ActionViewType.DEFAULT);
|
||||
} else {
|
||||
return mActionProvider.onCreateActionView(QUICK_SHARE_ACTION_BAR_HISTORY_SIZE, true);
|
||||
return mActionProvider.onCreateActionView(QUICK_SHARE_ACTION_BAR_HISTORY_SIZE,
|
||||
GeckoActionProvider.ActionViewType.QUICK_SHARE_ICON);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -165,4 +165,18 @@ public class MenuItemActionView extends LinearLayout
|
|||
listener.onClick(view);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the styles if this view is being used in the context menus.
|
||||
*
|
||||
* Ideally, we just use different layout files and styles to set this, but
|
||||
* MenuItemActionView is too integrated into GeckoActionProvider to provide
|
||||
* an easy separation so instead I provide this hack. I'm sorry.
|
||||
*/
|
||||
public void initContextMenuStyles() {
|
||||
final int defaultContextMenuPadding = getContext().getResources().getDimensionPixelOffset(
|
||||
R.dimen.context_menu_item_horizontal_padding);
|
||||
mMenuItem.setPadding(defaultContextMenuPadding, getPaddingTop(),
|
||||
defaultContextMenuPadding, getPaddingBottom());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,16 +5,17 @@
|
|||
|
||||
package org.mozilla.gecko.overlays.ui;
|
||||
|
||||
import android.util.AttributeSet;
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
@ -29,25 +30,17 @@ import android.widget.TextView;
|
|||
public class OverlayDialogButton extends LinearLayout {
|
||||
private static final String LOGTAG = "GeckoOverlayDialogButton";
|
||||
|
||||
// The views making up this button.
|
||||
private final ImageView icon;
|
||||
private final TextView label;
|
||||
|
||||
// Label/icon used when enabled.
|
||||
private String enabledLabel;
|
||||
private Drawable enabledIcon;
|
||||
|
||||
// Label/icon used when disabled.
|
||||
private String disabledLabel;
|
||||
private Drawable disabledIcon;
|
||||
|
||||
// Click listeners used when enabled/disabled. Currently, disabledOnClickListener is set
|
||||
// internally to something that causes the icon to pulse.
|
||||
private OnClickListener enabledOnClickListener;
|
||||
private OnClickListener disabledOnClickListener;
|
||||
|
||||
// We can't use super.isEnabled(), since we want to stay clickable in disabled state.
|
||||
private boolean isEnabled = true;
|
||||
|
||||
private final ImageView iconView;
|
||||
private final TextView labelView;
|
||||
|
||||
private String enabledText = "";
|
||||
private String disabledText = "";
|
||||
|
||||
private OnClickListener enabledOnClickListener;
|
||||
|
||||
public OverlayDialogButton(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
@ -59,71 +52,60 @@ public class OverlayDialogButton extends LinearLayout {
|
|||
|
||||
LayoutInflater.from(context).inflate(R.layout.overlay_share_button, this);
|
||||
|
||||
icon = (ImageView) findViewById(R.id.overlaybtn_icon);
|
||||
label = (TextView) findViewById(R.id.overlaybtn_label);
|
||||
}
|
||||
iconView = (ImageView) findViewById(R.id.overlaybtn_icon);
|
||||
labelView = (TextView) findViewById(R.id.overlaybtn_label);
|
||||
|
||||
public void setEnabledLabelAndIcon(String s, Drawable d) {
|
||||
enabledLabel = s;
|
||||
enabledIcon = d;
|
||||
super.setOnClickListener(new OnClickListener() {
|
||||
|
||||
if (isEnabled) {
|
||||
updateViews();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
public void setDisabledLabelAndIcon(String s, Drawable d) {
|
||||
disabledLabel = s;
|
||||
disabledIcon = d;
|
||||
|
||||
if (!isEnabled) {
|
||||
updateViews();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign the appropriate label and icon to the views, and update the onClickListener for this
|
||||
* view to the correct one (based on current enabledness state).
|
||||
*/
|
||||
private void updateViews() {
|
||||
label.setEnabled(isEnabled);
|
||||
if (isEnabled) {
|
||||
label.setText(enabledLabel);
|
||||
icon.setImageDrawable(enabledIcon);
|
||||
super.setOnClickListener(enabledOnClickListener);
|
||||
} else {
|
||||
label.setText(disabledLabel);
|
||||
icon.setImageDrawable(disabledIcon);
|
||||
super.setOnClickListener(getPopListener());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to lazily-initialise disabledOnClickListener to a listener that performs the
|
||||
* "pop" animation on the icon.
|
||||
* updateViews handles making this the actual onClickListener for this view.
|
||||
*/
|
||||
private OnClickListener getPopListener() {
|
||||
if (disabledOnClickListener == null) {
|
||||
disabledOnClickListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (isEnabled) {
|
||||
if (enabledOnClickListener != null) {
|
||||
enabledOnClickListener.onClick(v);
|
||||
} else {
|
||||
Log.e(LOGTAG, "enabledOnClickListener is null.");
|
||||
}
|
||||
} else {
|
||||
Animation anim = AnimationUtils.loadAnimation(getContext(), R.anim.overlay_pop);
|
||||
icon.startAnimation(anim);
|
||||
iconView.startAnimation(anim);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.OverlayDialogButton);
|
||||
|
||||
Drawable drawable = typedArray.getDrawable(R.styleable.OverlayDialogButton_drawable);
|
||||
if (drawable != null) {
|
||||
setDrawable(drawable);
|
||||
}
|
||||
|
||||
return disabledOnClickListener;
|
||||
String disabledText = typedArray.getString(R.styleable.OverlayDialogButton_disabledText);
|
||||
if (disabledText != null) {
|
||||
this.disabledText = disabledText;
|
||||
}
|
||||
|
||||
String enabledText = typedArray.getString(R.styleable.OverlayDialogButton_enabledText);
|
||||
if (enabledText != null) {
|
||||
this.enabledText = enabledText;
|
||||
}
|
||||
|
||||
typedArray.recycle();
|
||||
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
public void setDrawable(Drawable drawable) {
|
||||
iconView.setImageDrawable(drawable);
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
labelView.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnClickListener(OnClickListener l) {
|
||||
enabledOnClickListener = l;
|
||||
|
||||
if (isEnabled) {
|
||||
updateViews();
|
||||
}
|
||||
public void setOnClickListener(OnClickListener listener) {
|
||||
enabledOnClickListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -132,11 +114,15 @@ public class OverlayDialogButton extends LinearLayout {
|
|||
*/
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
if (enabled == isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
isEnabled = enabled;
|
||||
updateViews();
|
||||
iconView.setEnabled(enabled);
|
||||
labelView.setEnabled(enabled);
|
||||
|
||||
if (enabled) {
|
||||
setText(enabledText);
|
||||
} else {
|
||||
setText(disabledText);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -105,7 +105,8 @@ public class SendTabDeviceListArrayAdapter extends ArrayAdapter<ParcelableClient
|
|||
if (currentState != State.LIST) {
|
||||
// If we're in a special "Button-like" state, use the override string and a generic icon.
|
||||
final Drawable sendTabIcon = context.getResources().getDrawable(R.drawable.overlay_send_tab_icon);
|
||||
row.setEnabledLabelAndIcon(dummyRecordName, sendTabIcon);
|
||||
row.setText(dummyRecordName);
|
||||
row.setDrawable(sendTabIcon);
|
||||
}
|
||||
|
||||
// If we're just a button to launch the dialog, set the listener and abort.
|
||||
|
@ -124,7 +125,8 @@ public class SendTabDeviceListArrayAdapter extends ArrayAdapter<ParcelableClient
|
|||
final ParcelableClientRecord clientRecord = getItem(position);
|
||||
if (currentState == State.LIST) {
|
||||
final Drawable clientIcon = context.getResources().getDrawable(getImage(clientRecord));
|
||||
row.setEnabledLabelAndIcon(clientRecord.name, clientIcon);
|
||||
row.setText(clientRecord.name);
|
||||
row.setDrawable(clientIcon);
|
||||
|
||||
final String listenerGUID = clientRecord.guid;
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ import android.content.ContentResolver;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
|
@ -41,8 +40,6 @@ import android.view.MotionEvent;
|
|||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
@ -188,15 +185,8 @@ public class ShareDialog extends Locales.LocaleAwareActivity implements SendTabT
|
|||
|
||||
readingListButtonDrawable = readingListButton.getBackground();
|
||||
|
||||
final Resources resources = getResources();
|
||||
final String bookmarkEnabledLabel = resources.getString(R.string.overlay_share_bookmark_btn_label);
|
||||
final Drawable bookmarkEnabledIcon = resources.getDrawable(R.drawable.overlay_bookmark_icon);
|
||||
bookmarkButton.setEnabledLabelAndIcon(bookmarkEnabledLabel, bookmarkEnabledIcon);
|
||||
|
||||
final String bookmarkDisabledLabel = resources.getString(R.string.overlay_share_bookmark_btn_label_already);
|
||||
final Drawable bookmarkDisabledIcon = resources.getDrawable(R.drawable.overlay_bookmarked_already_icon);
|
||||
bookmarkButton.setDisabledLabelAndIcon(bookmarkDisabledLabel, bookmarkDisabledIcon);
|
||||
|
||||
// Bookmark button
|
||||
bookmarkButton = (OverlayDialogButton) findViewById(R.id.overlay_share_bookmark_btn);
|
||||
bookmarkButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
|
@ -204,14 +194,8 @@ public class ShareDialog extends Locales.LocaleAwareActivity implements SendTabT
|
|||
}
|
||||
});
|
||||
|
||||
final String readingListEnabledLabel = resources.getString(R.string.overlay_share_reading_list_btn_label);
|
||||
final Drawable readingListEnabledIcon = resources.getDrawable(R.drawable.overlay_readinglist_icon);
|
||||
readingListButton.setEnabledLabelAndIcon(readingListEnabledLabel, readingListEnabledIcon);
|
||||
|
||||
final String readingListDisabledLabel = resources.getString(R.string.overlay_share_reading_list_btn_label_already);
|
||||
final Drawable readingListDisabledIcon = resources.getDrawable(R.drawable.overlay_readinglist_already_icon);
|
||||
readingListButton.setDisabledLabelAndIcon(readingListDisabledLabel, readingListDisabledIcon);
|
||||
|
||||
// Reading List button
|
||||
readingListButton = (OverlayDialogButton) findViewById(R.id.overlay_share_reading_list_btn);
|
||||
readingListButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
|
|
|
@ -1088,7 +1088,7 @@ OnSharedPreferenceChangeListener
|
|||
|
||||
// Send Gecko-side pref changes to Gecko
|
||||
if (isGeckoPref(prefName)) {
|
||||
PrefsHelper.setPref(prefName, newValue);
|
||||
PrefsHelper.setPref(prefName, newValue, true /* flush */);
|
||||
}
|
||||
|
||||
if (preference instanceof ListPreference) {
|
||||
|
@ -1191,6 +1191,7 @@ OnSharedPreferenceChangeListener
|
|||
JSONObject jsonPref = new JSONObject();
|
||||
try {
|
||||
jsonPref.put("name", PREFS_MP_ENABLED);
|
||||
jsonPref.put("flush", true);
|
||||
jsonPref.put("type", "string");
|
||||
jsonPref.put("value", input1.getText().toString());
|
||||
|
||||
|
|
|
@ -179,7 +179,8 @@ public class PromptListAdapter extends ArrayAdapter<PromptListItem> {
|
|||
final GeckoActionProvider provider = GeckoActionProvider.getForType(item.getIntent().getType(), getContext());
|
||||
provider.setIntent(item.getIntent());
|
||||
|
||||
final MenuItemActionView view = (MenuItemActionView) provider.onCreateActionView();
|
||||
final MenuItemActionView view = (MenuItemActionView) provider.onCreateActionView(
|
||||
GeckoActionProvider.ActionViewType.CONTEXT_MENU);
|
||||
// If a quickshare button is clicked, we need to close the dialog.
|
||||
view.addActionButtonClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
|
|
|
@ -260,6 +260,11 @@ public class ReadingListSyncAdapter extends AbstractThreadedSyncAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
// The poll timed out. Let's call this an error.
|
||||
result = Result.Error;
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case Success:
|
||||
requestPeriodicSync(account, ReadingListSyncAdapter.AFTER_SUCCESS_SYNC_DELAY_SECONDS);
|
||||
|
|
Двоичные данные
mobile/android/base/resources/drawable-hdpi-v11/alert_guest.png
До Ширина: | Высота: | Размер: 1.1 KiB После Ширина: | Высота: | Размер: 885 B |
До Ширина: | Высота: | Размер: 174 B После Ширина: | Высота: | Размер: 160 B |
До Ширина: | Высота: | Размер: 725 B После Ширина: | Высота: | Размер: 723 B |
До Ширина: | Высота: | Размер: 820 B После Ширина: | Высота: | Размер: 811 B |
Двоичные данные
mobile/android/base/resources/drawable-hdpi/ab_background.9.png
До Ширина: | Высота: | Размер: 139 B После Ширина: | Высота: | Размер: 132 B |
Двоичные данные
mobile/android/base/resources/drawable-hdpi/ab_copy.png
До Ширина: | Высота: | Размер: 156 B После Ширина: | Высота: | Размер: 149 B |
Двоичные данные
mobile/android/base/resources/drawable-hdpi/ab_mic.png
До Ширина: | Высота: | Размер: 514 B После Ширина: | Высота: | Размер: 511 B |
Двоичные данные
mobile/android/base/resources/drawable-hdpi/ab_search.png
До Ширина: | Высота: | Размер: 3.9 KiB После Ширина: | Высота: | Размер: 819 B |
Двоичные данные
mobile/android/base/resources/drawable-hdpi/ab_select_all.png
До Ширина: | Высота: | Размер: 153 B После Ширина: | Высота: | Размер: 145 B |
До Ширина: | Высота: | Размер: 679 B После Ширина: | Высота: | Размер: 676 B |
До Ширина: | Высота: | Размер: 604 B После Ширина: | Высота: | Размер: 601 B |
До Ширина: | Высота: | Размер: 573 B После Ширина: | Высота: | Размер: 570 B |
До Ширина: | Высота: | Размер: 620 B После Ширина: | Высота: | Размер: 617 B |
До Ширина: | Высота: | Размер: 665 B После Ширина: | Высота: | Размер: 662 B |
До Ширина: | Высота: | Размер: 561 B После Ширина: | Высота: | Размер: 558 B |
До Ширина: | Высота: | Размер: 618 B После Ширина: | Высота: | Размер: 615 B |
До Ширина: | Высота: | Размер: 433 B После Ширина: | Высота: | Размер: 430 B |
До Ширина: | Высота: | Размер: 432 B После Ширина: | Высота: | Размер: 429 B |
До Ширина: | Высота: | Размер: 436 B После Ширина: | Высота: | Размер: 433 B |
До Ширина: | Высота: | Размер: 433 B После Ширина: | Высота: | Размер: 430 B |
До Ширина: | Высота: | Размер: 436 B После Ширина: | Высота: | Размер: 433 B |
До Ширина: | Высота: | Размер: 436 B После Ширина: | Высота: | Размер: 433 B |
Двоичные данные
mobile/android/base/resources/drawable-hdpi/alert_guest.png
До Ширина: | Высота: | Размер: 1.3 KiB После Ширина: | Высота: | Размер: 884 B |