зеркало из https://github.com/mozilla/gecko-dev.git
Bug 876277 - Convert the debugger frontend to use the EventEmitter instead of relying on DOM events, r=past
This commit is contained in:
Родитель
65f00c1176
Коммит
2ce3425857
|
@ -14,10 +14,64 @@ const FETCH_SOURCE_RESPONSE_DELAY = 200; // ms
|
|||
const FRAME_STEP_CLEAR_DELAY = 100; // ms
|
||||
const CALL_STACK_PAGE_SIZE = 25; // frames
|
||||
|
||||
// The panel's window global is an EventEmitter firing the following events:
|
||||
const EVENTS = {
|
||||
// When the debugger's source editor instance finishes loading or unloading.
|
||||
EDITOR_LOADED: "Debugger:EditorLoaded",
|
||||
EDITOR_UNLOADED: "Debugger:EditorUnoaded",
|
||||
|
||||
// When new sources are received from the debugger server.
|
||||
NEW_SOURCE: "Debugger:NewSource",
|
||||
SOURCES_ADDED: "Debugger:SourcesAdded",
|
||||
|
||||
// When a source is shown in the source editor.
|
||||
SOURCE_SHOWN: "Debugger:EditorSourceShown",
|
||||
SOURCE_ERROR_SHOWN: "Debugger:EditorSourceErrorShown",
|
||||
|
||||
// When scopes, variables, properties and watch expressions are fetched and
|
||||
// displayed in the variables view.
|
||||
FETCHED_SCOPES: "Debugger:FetchedScopes",
|
||||
FETCHED_VARIABLES: "Debugger:FetchedVariables",
|
||||
FETCHED_PROPERTIES: "Debugger:FetchedProperties",
|
||||
FETCHED_WATCH_EXPRESSIONS: "Debugger:FetchedWatchExpressions",
|
||||
|
||||
// When a breakpoint has been added or removed on the debugger server.
|
||||
BREAKPOINT_ADDED: "Debugger:BreakpointAdded",
|
||||
BREAKPOINT_REMOVED: "Debugger:BreakpointRemoved",
|
||||
|
||||
// When a breakpoint has been shown or hidden in the source editor.
|
||||
BREAKPOINT_SHOWN: "Debugger:BreakpointShown",
|
||||
BREAKPOINT_HIDDEN: "Debugger:BreakpointHidden",
|
||||
|
||||
// When a conditional breakpoint's popup is showing or hiding.
|
||||
CONDITIONAL_BREAKPOINT_POPUP_SHOWING: "Debugger:ConditionalBreakpointPopupShowing",
|
||||
CONDITIONAL_BREAKPOINT_POPUP_HIDING: "Debugger:ConditionalBreakpointPopupHiding",
|
||||
|
||||
// When a file search was performed.
|
||||
FILE_SEARCH_MATCH_FOUND: "Debugger:FileSearch:MatchFound",
|
||||
FILE_SEARCH_MATCH_NOT_FOUND: "Debugger:FileSearch:MatchNotFound",
|
||||
|
||||
// When a function search was performed.
|
||||
FUNCTION_SEARCH_MATCH_FOUND: "Debugger:FunctionSearch:MatchFound",
|
||||
FUNCTION_SEARCH_MATCH_NOT_FOUND: "Debugger:FunctionSearch:MatchNotFound",
|
||||
|
||||
// When a global text search was performed.
|
||||
GLOBAL_SEARCH_MATCH_FOUND: "Debugger:GlobalSearch:MatchFound",
|
||||
GLOBAL_SEARCH_MATCH_NOT_FOUND: "Debugger:GlobalSearch:MatchNotFound",
|
||||
|
||||
// After the stackframes are cleared and debugger won't pause anymore.
|
||||
AFTER_FRAMES_CLEARED: "Debugger:AfterFramesCleared",
|
||||
|
||||
// When the options popup is showing or hiding.
|
||||
OPTIONS_POPUP_SHOWING: "Debugger:OptionsPopupShowing",
|
||||
OPTIONS_POPUP_HIDDEN: "Debugger:OptionsPopupHidden",
|
||||
};
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
|
||||
let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
|
||||
Cu.import("resource:///modules/devtools/shared/event-emitter.js");
|
||||
Cu.import("resource:///modules/source-editor.jsm");
|
||||
Cu.import("resource:///modules/devtools/BreadcrumbsWidget.jsm");
|
||||
Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
|
||||
|
@ -643,7 +697,6 @@ StackFrames.prototype = {
|
|||
let title = StackFrameUtils.getFrameTitle(frame);
|
||||
DebuggerView.StackFrames.addFrame(title, location, line, depth, isBlackBoxed);
|
||||
}
|
||||
|
||||
if (this.currentFrameDepth == -1) {
|
||||
DebuggerView.StackFrames.selectedDepth = 0;
|
||||
}
|
||||
|
@ -691,7 +744,8 @@ StackFrames.prototype = {
|
|||
DebuggerView.Sources.unhighlightBreakpoint();
|
||||
DebuggerView.WatchExpressions.toggleContents(true);
|
||||
DebuggerView.Variables.empty(0);
|
||||
window.dispatchEvent(document, "Debugger:AfterFramesCleared");
|
||||
|
||||
window.emit(EVENTS.AFTER_FRAMES_CLEARED);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -771,8 +825,10 @@ StackFrames.prototype = {
|
|||
}
|
||||
} while ((environment = environment.parent));
|
||||
|
||||
// Signal that variables have been fetched.
|
||||
window.dispatchEvent(document, "Debugger:FetchedVariables");
|
||||
// Signal that scope environments have been shown and commit the current
|
||||
// variables view hierarchy to briefly flash items that changed between the
|
||||
// previous and current scope/variables/properties.
|
||||
window.emit(EVENTS.FETCHED_SCOPES);
|
||||
DebuggerView.Variables.commitHierarchy();
|
||||
},
|
||||
|
||||
|
@ -859,8 +915,10 @@ StackFrames.prototype = {
|
|||
expRef.separatorStr = L10N.getStr("variablesSeparatorLabel");
|
||||
}
|
||||
|
||||
// Signal that watch expressions have been fetched.
|
||||
window.dispatchEvent(document, "Debugger:FetchedWatchExpressions");
|
||||
// Signal that watch expressions have been fetched and commit the
|
||||
// current variables view hierarchy to briefly flash items that changed
|
||||
// between the previous and current scope/variables/properties.
|
||||
window.emit(EVENTS.FETCHED_WATCH_EXPRESSIONS);
|
||||
DebuggerView.Variables.commitHierarchy();
|
||||
});
|
||||
},
|
||||
|
@ -1012,7 +1070,7 @@ SourceScripts.prototype = {
|
|||
DebuggerController.Breakpoints.updatePaneBreakpoints();
|
||||
|
||||
// Signal that a new source has been added.
|
||||
window.dispatchEvent(document, "Debugger:AfterNewSource");
|
||||
window.emit(EVENTS.NEW_SOURCE);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1053,7 +1111,7 @@ SourceScripts.prototype = {
|
|||
DebuggerController.Breakpoints.updatePaneBreakpoints();
|
||||
|
||||
// Signal that sources have been added.
|
||||
window.dispatchEvent(document, "Debugger:AfterSourcesAdded");
|
||||
window.emit(EVENTS.SOURCES_ADDED);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1274,7 +1332,7 @@ Breakpoints.prototype = {
|
|||
DebuggerView.editor.addBreakpoint(aBreakpointClient.location.line - 1);
|
||||
}
|
||||
// Notify that we've shown a breakpoint in the source editor.
|
||||
window.dispatchEvent(document, "Debugger:BreakpointShown", aEditorBreakpoint);
|
||||
window.emit(EVENTS.BREAKPOINT_SHOWN, aEditorBreakpoint);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -1293,7 +1351,7 @@ Breakpoints.prototype = {
|
|||
// is invoked because a breakpoint was removed from the editor itself.
|
||||
this.removeBreakpoint(location, { noEditorUpdate: true }).then(() => {
|
||||
// Notify that we've hidden a breakpoint in the source editor.
|
||||
window.dispatchEvent(document, "Debugger:BreakpointHidden", aEditorBreakpoint);
|
||||
window.emit(EVENTS.BREAKPOINT_HIDDEN, aEditorBreakpoint);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -1406,6 +1464,9 @@ Breakpoints.prototype = {
|
|||
|
||||
// Show the breakpoint in the editor and breakpoints pane, and resolve.
|
||||
this._showBreakpoint(aBreakpointClient, aOptions);
|
||||
|
||||
// Notify that we've added a breakpoint.
|
||||
window.emit(EVENTS.BREAKPOINT_ADDED, aBreakpointClient);
|
||||
deferred.resolve(aBreakpointClient);
|
||||
});
|
||||
|
||||
|
@ -1466,6 +1527,9 @@ Breakpoints.prototype = {
|
|||
|
||||
// Hide the breakpoint from the editor and breakpoints pane, and resolve.
|
||||
this._hideBreakpoint(aLocation, aOptions);
|
||||
|
||||
// Notify that we've removed a breakpoint.
|
||||
window.emit(EVENTS.BREAKPOINT_REMOVED, aLocation);
|
||||
deferred.resolve(aLocation);
|
||||
});
|
||||
});
|
||||
|
@ -1631,6 +1695,11 @@ XPCOMUtils.defineLazyGetter(window, "_isChromeDebugger", function() {
|
|||
return !(window.frameElement instanceof XULElement);
|
||||
});
|
||||
|
||||
/**
|
||||
* Convenient way of emitting events from the panel window.
|
||||
*/
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
/**
|
||||
* Preliminary setup for the DebuggerController object.
|
||||
*/
|
||||
|
|
|
@ -52,8 +52,8 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
this._editorDeck = document.getElementById("editor-deck");
|
||||
this._stopBlackBoxButton = document.getElementById("black-boxed-message-button");
|
||||
|
||||
window.addEventListener("Debugger:EditorLoaded", this._onEditorLoad, false);
|
||||
window.addEventListener("Debugger:EditorUnloaded", this._onEditorUnload, false);
|
||||
window.on(EVENTS.EDITOR_LOADED, this._onEditorLoad, false);
|
||||
window.on(EVENTS.EDITOR_UNLOADED, this._onEditorUnload, false);
|
||||
this.widget.addEventListener("select", this._onSourceSelect, false);
|
||||
this.widget.addEventListener("click", this._onSourceClick, false);
|
||||
this.widget.addEventListener("check", this._onSourceCheck, false);
|
||||
|
@ -76,8 +76,8 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
destroy: function() {
|
||||
dumpn("Destroying the SourcesView");
|
||||
|
||||
window.removeEventListener("Debugger:EditorLoaded", this._onEditorLoad, false);
|
||||
window.removeEventListener("Debugger:EditorUnloaded", this._onEditorUnload, false);
|
||||
window.off(EVENTS.EDITOR_LOADED, this._onEditorLoad, false);
|
||||
window.off(EVENTS.EDITOR_UNLOADED, this._onEditorUnload, false);
|
||||
this.widget.removeEventListener("select", this._onSourceSelect, false);
|
||||
this.widget.removeEventListener("click", this._onSourceClick, false);
|
||||
this.widget.removeEventListener("check", this._onSourceCheck, false);
|
||||
|
@ -600,17 +600,17 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
/**
|
||||
* The load listener for the source editor.
|
||||
*/
|
||||
_onEditorLoad: function({ detail: editor }) {
|
||||
editor.addEventListener("Selection", this._onEditorSelection, false);
|
||||
editor.addEventListener("ContextMenu", this._onEditorContextMenu, false);
|
||||
_onEditorLoad: function(aName, aEditor) {
|
||||
aEditor.addEventListener(SourceEditor.EVENTS.SELECTION, this._onEditorSelection, false);
|
||||
aEditor.addEventListener(SourceEditor.EVENTS.CONTEXT_MENU, this._onEditorContextMenu, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* The unload listener for the source editor.
|
||||
*/
|
||||
_onEditorUnload: function({ detail: editor }) {
|
||||
editor.removeEventListener("Selection", this._onEditorSelection, false);
|
||||
editor.removeEventListener("ContextMenu", this._onEditorContextMenu, false);
|
||||
_onEditorUnload: function(aName, aEditor) {
|
||||
aEditor.removeEventListener(SourceEditor.EVENTS.SELECTION, this._onEditorSelection, false);
|
||||
aEditor.removeEventListener(SourceEditor.EVENTS.CONTEXT_MENU, this._onEditorContextMenu, false);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -740,6 +740,7 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
*/
|
||||
_onConditionalPopupShowing: function() {
|
||||
this._conditionalPopupVisible = true; // Used in tests.
|
||||
window.emit(EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWING);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -755,6 +756,7 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
*/
|
||||
_onConditionalPopupHiding: function() {
|
||||
this._conditionalPopupVisible = false; // Used in tests.
|
||||
window.emit(EVENTS.CONDITIONAL_BREAKPOINT_POPUP_HIDING);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1517,7 +1519,6 @@ GlobalSearchView.prototype = Heritage.extend(WidgetMethods, {
|
|||
clearView: function() {
|
||||
this.hidden = true;
|
||||
this.empty();
|
||||
window.dispatchEvent(document, "Debugger:GlobalSearch:ViewCleared");
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1589,7 +1590,6 @@ GlobalSearchView.prototype = Heritage.extend(WidgetMethods, {
|
|||
// Don't continue filtering if the searched token is an empty string.
|
||||
if (!aToken) {
|
||||
this.clearView();
|
||||
window.dispatchEvent(document, "Debugger:GlobalSearch:TokenEmpty");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1657,9 +1657,9 @@ GlobalSearchView.prototype = Heritage.extend(WidgetMethods, {
|
|||
this.hidden = false;
|
||||
this._currentlyFocusedMatch = -1;
|
||||
this._createGlobalResultsUI(globalResults);
|
||||
window.dispatchEvent(document, "Debugger:GlobalSearch:MatchFound");
|
||||
window.emit(EVENTS.GLOBAL_SEARCH_MATCH_FOUND);
|
||||
} else {
|
||||
window.dispatchEvent(document, "Debugger:GlobalSearch:MatchNotFound");
|
||||
window.emit(EVENTS.GLOBAL_SEARCH_MATCH_NOT_FOUND);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -233,6 +233,7 @@ OptionsView.prototype = {
|
|||
*/
|
||||
_onPopupShowing: function() {
|
||||
this._button.setAttribute("open", "true");
|
||||
window.emit(EVENTS.OPTIONS_POPUP_SHOWING);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -246,7 +247,7 @@ OptionsView.prototype = {
|
|||
* Listener handling the 'gear menu' popup hidden event.
|
||||
*/
|
||||
_onPopupHidden: function() {
|
||||
window.dispatchEvent(document, "Debugger:OptionsPopupHidden");
|
||||
window.emit(EVENTS.OPTIONS_POPUP_HIDDEN);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -306,9 +307,7 @@ OptionsView.prototype = {
|
|||
this._showOriginalSourceItem.getAttribute("checked") == "true";
|
||||
|
||||
// Don't block the UI while reconfiguring the server.
|
||||
window.addEventListener("Debugger:OptionsPopupHidden", function onHidden() {
|
||||
window.removeEventListener("Debugger:OptionsPopupHidden", onHidden, false);
|
||||
|
||||
window.once(EVENTS.OPTIONS_POPUP_HIDDEN, () => {
|
||||
// The popup panel needs more time to hide after triggering onpopuphidden.
|
||||
window.setTimeout(() => {
|
||||
DebuggerController.reconfigureThread(pref);
|
||||
|
@ -1308,6 +1307,7 @@ FilteredSourcesView.prototype = Heritage.extend(ResultsPanelContainer.prototype,
|
|||
// If there are no matches found, keep the popup hidden and avoid
|
||||
// creating the view.
|
||||
if (!aSearchResults.length) {
|
||||
window.emit(EVENTS.FILE_SEARCH_MATCH_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1328,6 +1328,9 @@ FilteredSourcesView.prototype = Heritage.extend(ResultsPanelContainer.prototype,
|
|||
// Select the first entry in this container.
|
||||
this.selectedIndex = 0;
|
||||
this.hidden = false;
|
||||
|
||||
// Signal that file search matches were found and displayed.
|
||||
window.emit(EVENTS.FILE_SEARCH_MATCH_FOUND);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1479,6 +1482,7 @@ FilteredFunctionsView.prototype = Heritage.extend(ResultsPanelContainer.prototyp
|
|||
// If there are no matches found, keep the popup hidden and avoid
|
||||
// creating the view.
|
||||
if (!aSearchResults.length) {
|
||||
window.emit(EVENTS.FUNCTION_SEARCH_MATCH_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1523,6 +1527,9 @@ FilteredFunctionsView.prototype = Heritage.extend(ResultsPanelContainer.prototyp
|
|||
// Select the first entry in this container.
|
||||
this.selectedIndex = 0;
|
||||
this.hidden = false;
|
||||
|
||||
// Signal that function search matches were found and displayed.
|
||||
window.emit(EVENTS.FUNCTION_SEARCH_MATCH_FOUND);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -155,10 +155,10 @@ let DebuggerView = {
|
|||
this.Variables.on("fetched", (aEvent, aType) => {
|
||||
switch (aType) {
|
||||
case "variables":
|
||||
window.dispatchEvent(document, "Debugger:FetchedVariables");
|
||||
window.emit(EVENTS.FETCHED_VARIABLES);
|
||||
break;
|
||||
case "properties":
|
||||
window.dispatchEvent(document, "Debugger:FetchedProperties");
|
||||
window.emit(EVENTS.FETCHED_PROPERTIES);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
@ -191,7 +191,7 @@ let DebuggerView = {
|
|||
dumpn("Finished loading the DebuggerView editor");
|
||||
|
||||
DebuggerController.Breakpoints.initialize().then(() => {
|
||||
window.dispatchEvent(document, "Debugger:EditorLoaded", this.editor);
|
||||
window.emit(EVENTS.EDITOR_LOADED, this.editor);
|
||||
aCallback();
|
||||
});
|
||||
},
|
||||
|
@ -207,7 +207,7 @@ let DebuggerView = {
|
|||
dumpn("Destroying the DebuggerView editor");
|
||||
|
||||
DebuggerController.Breakpoints.destroy().then(() => {
|
||||
window.dispatchEvent(document, "Debugger:EditorUnloaded", this.editor);
|
||||
window.emit(EVENTS.EDITOR_UNLOADED, this.editor);
|
||||
aCallback();
|
||||
});
|
||||
},
|
||||
|
@ -300,7 +300,7 @@ let DebuggerView = {
|
|||
DebuggerController.Breakpoints.updateEditorBreakpoints();
|
||||
|
||||
// Resolve and notify that a source file was shown.
|
||||
window.dispatchEvent(document, "Debugger:SourceShown", aSource);
|
||||
window.emit(EVENTS.SOURCE_SHOWN, aSource);
|
||||
deferred.resolve([aSource, aText]);
|
||||
},
|
||||
([, aError]) => {
|
||||
|
@ -310,7 +310,7 @@ let DebuggerView = {
|
|||
dumpn(msg);
|
||||
|
||||
// Reject and notify that there was an error showing the source file.
|
||||
window.dispatchEvent(document, "Debugger:SourceErrorShown", aError);
|
||||
window.emit(EVENTS.SOURCE_ERROR_SHOWN, aSource);
|
||||
deferred.reject([aSource, aError]);
|
||||
});
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче