atom-nuclide
Version:
A unified developer experience for web and mobile development, built as a suite of features on top of Atom to provide hackability and the support of an active community.
379 lines (333 loc) • 12.8 kB
JavaScript
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @constructor
* @extends {WebInspector.BreakpointsSidebarPaneBase}
* @implements {WebInspector.TargetManager.Observer}
*/
WebInspector.AsyncOperationsSidebarPane = function()
{
WebInspector.BreakpointsSidebarPaneBase.call(this, WebInspector.UIString("Async Operation Breakpoints"));
this.bodyElement.classList.add("async-operations");
this._updateEmptyElement();
var refreshButton = this.titleElement.createChild("button", "pane-title-button refresh");
refreshButton.addEventListener("click", this._refreshButtonClicked.bind(this), false);
refreshButton.title = WebInspector.UIString("Refresh");
/** @type {!Map.<!WebInspector.Target, !Map.<number, !DebuggerAgent.AsyncOperation>>} */
this._asyncOperationsByTarget = new Map();
/** @type {!Map.<number, !Element>} */
this._operationIdToElement = new Map();
this._revealBlackboxedCallFrames = false;
this._linkifier = new WebInspector.Linkifier(new WebInspector.Linkifier.DefaultFormatter(30));
this._popoverHelper = new WebInspector.PopoverHelper(this.bodyElement, this._getPopoverAnchor.bind(this), this._showPopover.bind(this));
this._popoverHelper.setTimeout(250, 250);
this.bodyElement.addEventListener("click", this._hidePopover.bind(this), true);
WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.AsyncOperationStarted, this._onAsyncOperationStarted, this);
WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.AsyncOperationCompleted, this._onAsyncOperationCompleted, this);
WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.DebuggerResumed, this._debuggerResumed, this);
WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._debuggerReset, this);
WebInspector.context.addFlavorChangeListener(WebInspector.Target, this._targetChanged, this);
WebInspector.settings.skipStackFramesPattern.addChangeListener(this._refresh, this);
WebInspector.settings.enableAsyncStackTraces.addChangeListener(this._asyncStackTracesStateChanged, this);
WebInspector.targetManager.observeTargets(this);
}
WebInspector.AsyncOperationsSidebarPane.prototype = {
_operationIdSymbol: Symbol("operationId"),
_checkedSymbol: Symbol("checked"),
/**
* @override
* @param {!WebInspector.Target} target
*/
targetAdded: function(target)
{
},
/**
* @override
* @param {!WebInspector.Target} target
*/
targetRemoved: function(target)
{
this._asyncOperationsByTarget.delete(target);
if (this._target === target) {
this._clear();
delete this._target;
}
},
/**
* @param {!WebInspector.Event} event
*/
_targetChanged: function(event)
{
var target = /** @type {!WebInspector.Target} */ (event.data);
if (this._target === target)
return;
this._target = target;
this._refresh();
},
/**
* @param {?WebInspector.Target} target
* @param {number} operationId
* @return {?DebuggerAgent.AsyncOperation}
*/
operationById: function(target, operationId)
{
if (!target)
return null;
var operationsMap = this._asyncOperationsByTarget.get(target);
if (!operationsMap)
return null;
return operationsMap.get(operationId) || null;
},
_asyncStackTracesStateChanged: function()
{
var enabled = WebInspector.settings.enableAsyncStackTraces.get();
if (enabled) {
this._target = WebInspector.context.flavor(WebInspector.Target);
} else if (this._target) {
this._asyncOperationsByTarget.delete(this._target);
delete this._target;
}
this._updateEmptyElement();
this._refresh();
},
_updateEmptyElement: function()
{
var enabled = WebInspector.settings.enableAsyncStackTraces.get();
if (enabled) {
this.emptyElement.textContent = WebInspector.UIString("No Async Operations");
} else {
this.emptyElement.textContent = WebInspector.UIString("Async stack traces are disabled.");
this.emptyElement.createTextChild(" ");
var enableLink = this.emptyElement.createChild("span", "link");
enableLink.textContent = WebInspector.UIString("Enable");
enableLink.addEventListener("click", enableAsyncStackTraces, true);
}
function enableAsyncStackTraces()
{
WebInspector.settings.enableAsyncStackTraces.set(true);
}
},
/** @override */
wasShown: function()
{
if (!this._target && WebInspector.settings.enableAsyncStackTraces.get()) {
this._target = WebInspector.context.flavor(WebInspector.Target);
this._refresh();
}
},
/** @override */
willHide: function()
{
this._hidePopover();
},
/** @override */
onResize: function()
{
this._hidePopover();
},
/**
* @param {!WebInspector.Target} target
*/
revealHiddenCallFrames: function(target)
{
if (this._target !== target || this._revealBlackboxedCallFrames)
return;
this._revealBlackboxedCallFrames = true;
this._refresh();
},
/**
* @param {number} operationId
*/
highlightBreakpoint: function(operationId)
{
this._breakpointHitId = operationId;
var element = this._operationIdToElement.get(operationId);
if (!element)
return;
this.expand();
element.classList.add("breakpoint-hit");
},
clearBreakpointHighlight: function()
{
if (!this._breakpointHitId)
return;
var element = this._operationIdToElement.get(this._breakpointHitId);
if (element)
element.classList.remove("breakpoint-hit");
delete this._breakpointHitId;
},
/**
* @param {!WebInspector.Event} event
*/
_debuggerResumed: function(event)
{
var target = /** @type {!WebInspector.Target} */ (event.target.target());
if (this._target !== target || !this._revealBlackboxedCallFrames)
return;
this._revealBlackboxedCallFrames = false;
this._refresh();
},
/**
* @param {!WebInspector.Event} event
*/
_debuggerReset: function(event)
{
var target = /** @type {!WebInspector.Target} */ (event.target.target());
this._asyncOperationsByTarget.delete(target);
if (this._target === target)
this._clear();
},
/**
* @param {!Event} event
*/
_refreshButtonClicked: function(event)
{
event.consume();
this.expand();
if (this._target)
this._target.debuggerAgent().flushAsyncOperationEvents();
},
/**
* @param {!WebInspector.Event} event
*/
_onAsyncOperationStarted: function(event)
{
var target = /** @type {!WebInspector.Target} */ (event.target.target());
var operation = /** @type {!DebuggerAgent.AsyncOperation} */ (event.data);
var operationsMap = this._asyncOperationsByTarget.get(target);
if (!operationsMap) {
operationsMap = new Map();
this._asyncOperationsByTarget.set(target, operationsMap)
}
operationsMap.set(operation.id, operation);
if (this._target === target)
this._createAsyncOperationItem(operation);
},
/**
* @param {!WebInspector.Event} event
*/
_onAsyncOperationCompleted: function(event)
{
var target = /** @type {!WebInspector.Target} */ (event.target.target());
var operationId = /** @type {number} */ (event.data);
var operationsMap = this._asyncOperationsByTarget.get(target);
if (operationsMap)
operationsMap.delete(operationId);
if (this._target === target) {
var element = this._operationIdToElement.get(operationId);
if (element)
this.removeListElement(element);
this._operationIdToElement.delete(operationId);
if (!this._operationIdToElement.size)
this._clear();
}
},
_refresh: function()
{
this._clear();
if (!this._target)
return;
var operationsMap = this._asyncOperationsByTarget.get(this._target);
if (!operationsMap || !operationsMap.size)
return;
// The for..of loop iterates in insertion order.
for (var pair of operationsMap) {
var operation = /** @type {!DebuggerAgent.AsyncOperation} */ (pair[1]);
this._createAsyncOperationItem(operation);
}
},
/**
* @param {!DebuggerAgent.AsyncOperation} operation
*/
_createAsyncOperationItem: function(operation)
{
var element = createElementWithClass("li", "async-operation");
var title = operation.description || WebInspector.UIString("Async Operation");
var label = createCheckboxLabel(title, operation[this._checkedSymbol]);
label.classList.add("checkbox-elem");
label.checkboxElement.addEventListener("click", this._checkboxClicked.bind(this, operation.id), false);
element.appendChild(label);
var callFrame = WebInspector.DebuggerPresentationUtils.callFrameAnchorFromStackTrace(this._target, operation.stackTrace, operation.asyncStackTrace, this._revealBlackboxedCallFrames);
if (callFrame)
element.createChild("div").appendChild(this._linkifier.linkifyConsoleCallFrame(this._target, callFrame));
element[this._operationIdSymbol] = operation.id;
this._operationIdToElement.set(operation.id, element);
this.addListElement(element, this.listElement.firstChild);
if (operation.id === this._breakpointHitId) {
element.classList.add("breakpoint-hit");
this.expand();
}
},
/**
* @param {number} operationId
* @param {!Event} event
*/
_checkboxClicked: function(operationId, event)
{
var operation = this.operationById(this._target, operationId);
if (!operation)
return;
operation[this._checkedSymbol] = event.target.checked;
if (event.target.checked)
this._target.debuggerAgent().setAsyncOperationBreakpoint(operationId);
else
this._target.debuggerAgent().removeAsyncOperationBreakpoint(operationId);
},
_clear: function()
{
this._hidePopover();
this.reset();
this._operationIdToElement.clear();
this._linkifier.reset();
},
_hidePopover: function()
{
this._popoverHelper.hidePopover();
},
/**
* @param {!Element} element
* @param {!Event} event
* @return {!Element|!AnchorBox|undefined}
*/
_getPopoverAnchor: function(element, event)
{
var anchor = /** @type {?Element} */ (element.enclosingNodeOrSelfWithNodeName("a"));
if (!anchor)
return undefined;
var operation = this._operationForPopover(anchor);
return operation ? anchor : undefined;
},
/**
* @param {!Element} anchor
* @param {!WebInspector.Popover} popover
*/
_showPopover: function(anchor, popover)
{
var operation = this._operationForPopover(anchor);
if (!operation)
return;
var content = WebInspector.DOMPresentationUtils.buildStackTracePreviewContents(this._target, this._linkifier, operation.stackTrace, operation.asyncStackTrace);
popover.setCanShrink(true);
popover.showForAnchor(content, anchor);
},
/**
* @param {!Element} element
* @return {?DebuggerAgent.AsyncOperation}
*/
_operationForPopover: function(element)
{
var asyncOperations = this._target && this._asyncOperationsByTarget.get(this._target);
if (!asyncOperations)
return null;
var anchor = element.enclosingNodeOrSelfWithClass("async-operation");
if (!anchor)
return null;
var operationId = anchor[this._operationIdSymbol];
var operation = operationId && asyncOperations.get(operationId);
if (!operation || !operation.stackTrace)
return null;
return operation;
},
__proto__: WebInspector.BreakpointsSidebarPaneBase.prototype
}