UNPKG

@dcloudio/uni-debugger

Version:

uni-app debugger

228 lines (201 loc) 9.33 kB
// Copyright (c) 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. /** * @implements {UI.ContextFlavorListener} * @unrestricted */ Sources.JavaScriptBreakpointsSidebarPane = class extends UI.ThrottledWidget { constructor() { super(true); this.registerRequiredCSS('sources/javaScriptBreakpointsSidebarPane.css'); this._breakpointManager = Bindings.breakpointManager; this._breakpointManager.addEventListener(Bindings.BreakpointManager.Events.BreakpointAdded, this.update, this); this._breakpointManager.addEventListener(Bindings.BreakpointManager.Events.BreakpointRemoved, this.update, this); Common.moduleSetting('breakpointsActive').addChangeListener(this.update, this); /** @type {?Element} */ this._listElement = null; this.update(); } /** * @override * @return {!Promise<?>} */ doUpdate() { const breakpointLocations = this._breakpointManager.allBreakpointLocations(); if (!breakpointLocations.length) { this._listElement = null; this.contentElement.removeChildren(); const emptyElement = this.contentElement.createChild('div', 'gray-info-message'); emptyElement.textContent = Common.UIString('No breakpoints'); this.contentElement.appendChild(emptyElement); this._didUpdateForTest(); return Promise.resolve(); } if (!this._listElement) { this.contentElement.removeChildren(); this._listElement = this.contentElement.createChild('div'); this.contentElement.appendChild(this._listElement); } breakpointLocations.sort((item1, item2) => item1.uiLocation.compareTo(item2.uiLocation)); /** @type {!Multimap<string, !{breakpoint: !Bindings.BreakpointManager.Breakpoint, uiLocation: !Workspace.UILocation}>} */ const locationForEntry = new Multimap(); for (const breakpointLocation of breakpointLocations) { const uiLocation = breakpointLocation.uiLocation; const entryDescriptor = uiLocation.uiSourceCode.url() + ':' + uiLocation.lineNumber; locationForEntry.set(entryDescriptor, breakpointLocation); } const details = UI.context.flavor(SDK.DebuggerPausedDetails); const selectedUILocation = details && details.callFrames.length ? Bindings.debuggerWorkspaceBinding.rawLocationToUILocation(details.callFrames[0].location()) : null; let shouldShowView = false; let entry = this._listElement.firstChild; const promises = []; for (const descriptor of locationForEntry.keysArray()) { if (!entry) { entry = this._listElement.createChild('div', 'breakpoint-entry'); entry.addEventListener('contextmenu', this._breakpointContextMenu.bind(this), true); entry.addEventListener('click', this._revealLocation.bind(this), false); const checkboxLabel = UI.CheckboxLabel.create(''); checkboxLabel.addEventListener('click', this._breakpointCheckboxClicked.bind(this), false); entry.appendChild(checkboxLabel); entry[Sources.JavaScriptBreakpointsSidebarPane._checkboxLabelSymbol] = checkboxLabel; const snippetElement = entry.createChild('div', 'source-text monospace'); entry[Sources.JavaScriptBreakpointsSidebarPane._snippetElementSymbol] = snippetElement; } const locations = Array.from(locationForEntry.get(descriptor)); const uiLocation = locations[0].uiLocation; const isSelected = !!selectedUILocation && locations.some(location => location.uiLocation.id() === selectedUILocation.id()); const hasEnabled = locations.some(location => location.breakpoint.enabled()); const hasDisabled = locations.some(location => !location.breakpoint.enabled()); promises.push(this._resetEntry(/** @type {!Element}*/ (entry), uiLocation, isSelected, hasEnabled, hasDisabled)); if (isSelected) shouldShowView = true; entry = entry.nextSibling; } while (entry) { const next = entry.nextSibling; entry.remove(); entry = next; } if (shouldShowView) UI.viewManager.showView('sources.jsBreakpoints'); this._listElement.classList.toggle( 'breakpoints-list-deactivated', !Common.moduleSetting('breakpointsActive').get()); Promise.all(promises).then(() => this._didUpdateForTest()); return Promise.resolve(); } /** * @param {!Element} element * @param {!Workspace.UILocation} uiLocation * @param {boolean} isSelected * @param {boolean} hasEnabled * @param {boolean} hasDisabled * @return {!Promise<undefined>} */ _resetEntry(element, uiLocation, isSelected, hasEnabled, hasDisabled) { element[Sources.JavaScriptBreakpointsSidebarPane._locationSymbol] = uiLocation; element.classList.toggle('breakpoint-hit', isSelected); const checkboxLabel = element[Sources.JavaScriptBreakpointsSidebarPane._checkboxLabelSymbol]; checkboxLabel.textElement.textContent = uiLocation.linkText(); checkboxLabel.checkboxElement.checked = hasEnabled; checkboxLabel.checkboxElement.indeterminate = hasEnabled && hasDisabled; const snippetElement = element[Sources.JavaScriptBreakpointsSidebarPane._snippetElementSymbol]; return uiLocation.uiSourceCode.requestContent().then(fillSnippetElement.bind(null, snippetElement)); /** * @param {!Element} snippetElement * @param {?string} content */ function fillSnippetElement(snippetElement, content) { const lineNumber = uiLocation.lineNumber; const text = new TextUtils.Text(content || ''); if (lineNumber < text.lineCount()) { const lineText = text.lineAt(lineNumber); const maxSnippetLength = 200; snippetElement.textContent = lineText.trimEnd(maxSnippetLength); } } } /** * @param {!Event} event * @return {?Workspace.UILocation} */ _uiLocationFromEvent(event) { const node = event.target.enclosingNodeOrSelfWithClass('breakpoint-entry'); if (!node) return null; return node[Sources.JavaScriptBreakpointsSidebarPane._locationSymbol] || null; } /** * @param {!Event} event */ _breakpointCheckboxClicked(event) { const uiLocation = this._uiLocationFromEvent(event); if (!uiLocation) return; const breakpoints = this._breakpointManager.findBreakpoints(uiLocation.uiSourceCode, uiLocation.lineNumber); const newState = event.target.checkboxElement.checked; for (const breakpoint of breakpoints) breakpoint.setEnabled(newState); event.consume(); } /** * @param {!Event} event */ _revealLocation(event) { const uiLocation = this._uiLocationFromEvent(event); if (uiLocation) Common.Revealer.reveal(uiLocation); } /** * @param {!Event} event */ _breakpointContextMenu(event) { const uiLocation = this._uiLocationFromEvent(event); if (!uiLocation) return; const breakpoints = this._breakpointManager.findBreakpoints(uiLocation.uiSourceCode, uiLocation.lineNumber); const contextMenu = new UI.ContextMenu(event); const removeEntryTitle = breakpoints.length > 1 ? Common.UIString('Remove all breakpoints in line') : Common.UIString('Remove breakpoint'); contextMenu.defaultSection().appendItem( removeEntryTitle, () => breakpoints.map(breakpoint => breakpoint.remove(false /* keepInStorage */))); const breakpointActive = Common.moduleSetting('breakpointsActive').get(); const breakpointActiveTitle = breakpointActive ? Common.UIString('Deactivate breakpoints') : Common.UIString('Activate breakpoints'); contextMenu.defaultSection().appendItem( breakpointActiveTitle, () => Common.moduleSetting('breakpointsActive').set(!breakpointActive)); if (breakpoints.some(breakpoint => !breakpoint.enabled())) { const enableTitle = Common.UIString('Enable all breakpoints'); contextMenu.defaultSection().appendItem( enableTitle, this._breakpointManager.toggleAllBreakpoints.bind(this._breakpointManager, true)); } if (breakpoints.some(breakpoint => breakpoint.enabled())) { const disableTitle = Common.UIString('Disable all breakpoints'); contextMenu.defaultSection().appendItem( disableTitle, this._breakpointManager.toggleAllBreakpoints.bind(this._breakpointManager, false)); } const removeAllTitle = Common.UIString('Remove all breakpoints'); contextMenu.defaultSection().appendItem( removeAllTitle, this._breakpointManager.removeAllBreakpoints.bind(this._breakpointManager)); const removeOtherTitle = Common.UIString('Remove other breakpoints'); contextMenu.defaultSection().appendItem( removeOtherTitle, this._breakpointManager.removeOtherBreakpoints.bind(this._breakpointManager, new Set(breakpoints))); contextMenu.show(); } /** * @override * @param {?Object} object */ flavorChanged(object) { this.update(); } _didUpdateForTest() { } }; Sources.JavaScriptBreakpointsSidebarPane._locationSymbol = Symbol('location'); Sources.JavaScriptBreakpointsSidebarPane._checkboxLabelSymbol = Symbol('checkbox-label'); Sources.JavaScriptBreakpointsSidebarPane._snippetElementSymbol = Symbol('snippet-element');