Chromium Code Reviews| Index: third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js |
| diff --git a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js |
| index 13b5de4e4fd21e80c5f72eb25df571108d69d02f..be26a174d1c4247950056b45e38babdde924b5e0 100644 |
| --- a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js |
| +++ b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js |
| @@ -211,13 +211,16 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame { |
| function populate(resolve, reject) { |
| var uiLocation = new Workspace.UILocation(this.uiSourceCode(), lineNumber, 0); |
| this._scriptsPanel.appendUILocationItems(contextMenu, uiLocation); |
| - var breakpoints = this._lineBreakpointDecorations(lineNumber).map(decoration => decoration.breakpoint); |
| + var breakpoints = this._lineBreakpointDecorations(lineNumber) |
| + .map(decoration => decoration.breakpoint) |
| + .filter(breakpoint => !!breakpoint); |
| if (!breakpoints.length) { |
| // This row doesn't have a breakpoint: We want to show Add Breakpoint and Add and Edit Breakpoint. |
| contextMenu.appendItem( |
| Common.UIString('Add breakpoint'), this._createNewBreakpoint.bind(this, lineNumber, '', true)); |
| contextMenu.appendItem( |
| - Common.UIString('Add conditional breakpoint\u2026'), this._editBreakpointCondition.bind(this, lineNumber)); |
| + Common.UIString('Add conditional breakpoint\u2026'), |
| + this._editBreakpointCondition.bind(this, lineNumber, null, null)); |
| contextMenu.appendItem( |
| Common.UIString('Never pause here'), this._createNewBreakpoint.bind(this, lineNumber, 'false', true)); |
| } else { |
| @@ -228,7 +231,7 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame { |
| if (hasOneBreakpoint) { |
| contextMenu.appendItem( |
| Common.UIString('Edit breakpoint\u2026'), |
| - this._editBreakpointCondition.bind(this, lineNumber, breakpoints[0])); |
| + this._editBreakpointCondition.bind(this, lineNumber, breakpoints[0], null)); |
| } |
| var hasEnabled = breakpoints.some(breakpoint => breakpoint.enabled()); |
| if (hasEnabled) { |
| @@ -348,6 +351,9 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame { |
| var decorations = Array.from(this._breakpointDecorations); |
| this._breakpointDecorations.clear(); |
| for (var decoration of decorations) { |
| + decoration.hide(); |
| + if (!decoration.breakpoint) |
| + continue; |
| decoration.breakpoint.remove(); |
| var location = decoration.handle.resolve(); |
| if (location) |
| @@ -490,9 +496,10 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame { |
| /** |
| * @param {number} lineNumber |
| - * @param {!Bindings.BreakpointManager.Breakpoint=} breakpoint |
| + * @param {?Bindings.BreakpointManager.Breakpoint} breakpoint |
| + * @param {?{lineNumber: number, columnNumber: number}} location |
| */ |
| - _editBreakpointCondition(lineNumber, breakpoint) { |
| + _editBreakpointCondition(lineNumber, breakpoint, location) { |
| this._conditionElement = this._createConditionElement(lineNumber); |
| this.textEditor.addDecoration(this._conditionElement, lineNumber); |
| @@ -508,6 +515,8 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame { |
| if (breakpoint) |
| breakpoint.setCondition(newText); |
| + else if (location) |
| + this._setBreakpoint(location.lineNumber, location.columnNumber, newText, true); |
| else |
| this._createNewBreakpoint(lineNumber, newText, true); |
| } |
| @@ -758,20 +767,79 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame { |
| continue; |
| lineNumbers.add(location.lineNumber); |
| } |
| + var promises = []; |
| for (var lineNumber of lineNumbers) { |
| this.textEditor.toggleLineClass(lineNumber, 'cm-breakpoint', false); |
| this.textEditor.toggleLineClass(lineNumber, 'cm-breakpoint-disabled', false); |
| this.textEditor.toggleLineClass(lineNumber, 'cm-breakpoint-conditional', false); |
| var decorations = this._lineBreakpointDecorations(lineNumber); |
| - if (!decorations.length) |
| + if (!decorations.some(decoration => !!decoration.breakpoint)) { |
| + for (var decoration of decorations) { |
| + decoration.hide(); |
| + this._breakpointDecorations.delete(decoration); |
| + } |
| continue; |
| + } |
| decorations.sort(Sources.JavaScriptSourceFrame.BreakpointDecoration.mostSpecificFirst); |
| this.textEditor.toggleLineClass(lineNumber, 'cm-breakpoint', true); |
| this.textEditor.toggleLineClass(lineNumber, 'cm-breakpoint-disabled', !decorations[0].enabled || this._muted); |
| this.textEditor.toggleLineClass(lineNumber, 'cm-breakpoint-conditional', !!decorations[0].condition); |
| + if (Runtime.experiments.isEnabled('inlineBreakpoints')) { |
| + promises.push( |
| + this._breakpointManager |
| + .possibleBreakpoints(this.uiSourceCode(), new Common.TextRange(lineNumber, 0, lineNumber + 1, 0)) |
| + .then( |
| + locations => this._textEditor.operation(addInlineDecorations.bind(this, lineNumber, locations)))); |
| + } |
| } |
| delete this._scheduledBreakpointDecorationUpdates; |
| - this._breakpointDecorationsUpdatedForTest(); |
| + if (!promises.length) |
| + this._breakpointDecorationsUpdatedForTest(); |
| + else |
| + Promise.all(promises).then(() => this._breakpointDecorationsUpdatedForTest()); |
| + } |
| + |
| + /** |
| + * @this {Sources.JavaScriptSourceFrame} |
| + * @param {number} lineNumber |
| + * @param {!Array<!Workspace.UILocation>} possibleLocations |
| + */ |
| + function addInlineDecorations(lineNumber, possibleLocations) { |
| + var decorations = this._lineBreakpointDecorations(lineNumber); |
| + // Hide all inline decoration, remove decoration if decoration doesn't have a breakpoint. |
| + for (var decoration of decorations) { |
| + decoration.hide(); |
| + if (!decoration.breakpoint) |
| + this._breakpointDecorations.delete(decoration); |
| + } |
| + decorations = decorations.filter(decoration => !!decoration.breakpoint); |
| + // If less then two locations or no real breakpoints in this line - don't show any inline decorations. |
| + if (possibleLocations.length <= 1 || !decorations.length) |
| + return; |
| + // Add missing decorations for possible locations without breakpoint. |
| + /** @type {!Set<number>} */ |
| + var columns = new Set(); |
| + for (var decoration of decorations) { |
| + var location = decoration.handle.resolve(); |
| + if (location) |
| + columns.add(location.columnNumber); |
| + } |
| + for (var location of possibleLocations) { |
| + if (columns.has(location.columnNumber)) |
| + continue; |
| + var handle = this._textEditor.textEditorPositionHandle(location.lineNumber, location.columnNumber); |
| + var decoration = new Sources.JavaScriptSourceFrame.BreakpointDecoration(handle, '', false, null); |
| + this._breakpointDecorations.add(decoration); |
| + decorations.push(decoration); |
| + } |
| + // Render inline decorations. |
| + for (var decoration of decorations) { |
| + var element = decoration.show(this._textEditor); |
| + if (!element) |
| + continue; |
| + element.addEventListener('click', this._inlineBreakpointClick.bind(this, decoration), true); |
| + element.addEventListener('contextmenu', this._inlineBreakpointContextMenu.bind(this, decoration), true); |
| + } |
| } |
| } |
| @@ -779,6 +847,50 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame { |
| } |
| /** |
| + * @param {!Sources.JavaScriptSourceFrame.BreakpointDecoration} decoration |
| + * @param {!Event} event |
| + */ |
| + _inlineBreakpointClick(decoration, event) { |
| + event.consume(true); |
| + if (decoration.breakpoint) { |
| + if (event.shiftKey) |
| + decoration.breakpoint.setEnabled(!decoration.breakpoint.enabled()); |
| + else |
| + decoration.breakpoint.remove(); |
| + } else { |
| + var location = decoration.handle.resolve(); |
| + if (!location) |
| + return; |
| + this._setBreakpoint(location.lineNumber, location.columnNumber, decoration.condition, true); |
| + } |
| + } |
| + |
| + /** |
| + * @param {!Sources.JavaScriptSourceFrame.BreakpointDecoration} decoration |
| + * @param {!Event} event |
| + */ |
| + _inlineBreakpointContextMenu(decoration, event) { |
| + event.consume(true); |
| + var location = decoration.handle.resolve(); |
| + if (!location) |
| + return; |
| + var contextMenu = new UI.ContextMenu(event); |
| + if (decoration.breakpoint) { |
| + contextMenu.appendItem( |
| + Common.UIString('Edit breakpoint\u2026'), |
| + this._editBreakpointCondition.bind(this, location.lineNumber, decoration.breakpoint, null)); |
| + } else { |
| + contextMenu.appendItem( |
| + Common.UIString('Add conditional breakpoint\u2026'), |
| + this._editBreakpointCondition.bind(this, location.lineNumber, null, location)); |
| + contextMenu.appendItem( |
| + Common.UIString('Never pause here'), |
| + this._setBreakpoint.bind(this, location.lineNumber, location.columnNumber, 'false', true)); |
| + } |
| + contextMenu.show(); |
| + } |
| + |
| + /** |
| * @param {!Common.Event} event |
| * @return {boolean} |
| */ |
| @@ -807,7 +919,8 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame { |
| var uiLocation = /** @type {!Workspace.UILocation} */ (event.data.uiLocation); |
| var handle = this._textEditor.textEditorPositionHandle(uiLocation.lineNumber, uiLocation.columnNumber); |
| var breakpoint = /** @type {!Bindings.BreakpointManager.Breakpoint} */ (event.data.breakpoint); |
| - var decoration = new Sources.JavaScriptSourceFrame.BreakpointDecoration(handle, breakpoint); |
| + var decoration = new Sources.JavaScriptSourceFrame.BreakpointDecoration( |
| + handle, breakpoint.condition(), breakpoint.enabled(), breakpoint); |
| this._breakpointDecorations.add(decoration); |
| breakpoint[Sources.JavaScriptSourceFrame.BreakpointDecoration._decorationSymbol] = decoration; |
| this._updateBreakpointDecoration(decoration); |
| @@ -824,6 +937,7 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame { |
| if (!decoration) |
| return; |
| this._breakpointDecorations.delete(decoration); |
| + decoration.hide(); |
| delete breakpoint[Sources.JavaScriptSourceFrame.BreakpointDecoration._decorationSymbol]; |
| this._updateBreakpointDecoration(decoration); |
| } |
| @@ -973,7 +1087,7 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame { |
| return; |
| } |
| var hasDisabled = this._textEditor.hasLineClass(lineNumber, 'cm-breakpoint-disabled'); |
| - var breakpoints = decorations.map(decoration => decoration.breakpoint); |
| + var breakpoints = decorations.map(decoration => decoration.breakpoint).filter(breakpoint => !!breakpoint); |
| for (var breakpoint of breakpoints) { |
| if (onlyDisable) |
| breakpoint.setEnabled(hasDisabled); |
| @@ -1098,13 +1212,18 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame { |
| Sources.JavaScriptSourceFrame.BreakpointDecoration = class { |
|
lushnikov
2016/11/23 21:54:39
What is BreakpointDecoration? It used to be a gutt
kozy
2016/11/23 23:08:47
BreakpointDecoration represents decoration for bre
|
| /** |
| * @param {!TextEditor.TextEditorPositionHandle} handle |
| - * @param {!Bindings.BreakpointManager.Breakpoint} breakpoint |
| + * @param {string} condition |
| + * @param {boolean} enabled |
| + * @param {?Bindings.BreakpointManager.Breakpoint} breakpoint |
| */ |
| - constructor(handle, breakpoint) { |
| + constructor(handle, condition, enabled, breakpoint) { |
|
lushnikov
2016/11/23 21:54:39
let's make decoration texteditor-aware:
construct
kozy
2016/11/23 23:08:47
Done.
|
| this.handle = handle; |
| - this.condition = breakpoint.condition(); |
| - this.enabled = breakpoint.enabled(); |
| + this.condition = condition; |
| + this.enabled = enabled; |
| this.breakpoint = breakpoint; |
| + |
| + /** @type {?TextEditor.TextEditorBookMark} */ |
| + this._bookmark = null; |
| } |
| /** |
| @@ -1119,6 +1238,35 @@ Sources.JavaScriptSourceFrame.BreakpointDecoration = class { |
| return decoration1.enabled ? -1 : 1; |
| return 0; |
| } |
| + |
| + /** |
| + * @param {!TextEditor.CodeMirrorTextEditor} textEditor |
| + * @return {?Element} |
| + */ |
| + show(textEditor) { |
| + if (this._bookmark) |
| + return null; |
| + var location = this.handle.resolve(); |
| + if (!location) |
| + return null; |
| + var inlineBreakpoint = createElementWithClass('div', 'cm-inline-breakpoint'); |
| + inlineBreakpoint.classList.toggle('cm-inline-conditional', !!this.condition); |
| + inlineBreakpoint.classList.toggle('cm-inline-disabled', !this.enabled); |
| + this._bookmark = textEditor.addBookmark( |
| + location.lineNumber, location.columnNumber, inlineBreakpoint, |
| + Sources.JavaScriptSourceFrame.BreakpointDecoration._bookmarkSymbol); |
| + this._bookmark[Sources.JavaScriptSourceFrame.BreakpointDecoration._elementSymbolForTest] = inlineBreakpoint; |
| + return inlineBreakpoint; |
| + } |
| + |
| + hide() { |
| + if (!this._bookmark) |
| + return; |
| + this._bookmark.clear(); |
| + this._bookmark = null; |
| + } |
| }; |
| Sources.JavaScriptSourceFrame.BreakpointDecoration._decorationSymbol = Symbol('decoration'); |
| +Sources.JavaScriptSourceFrame.BreakpointDecoration._bookmarkSymbol = Symbol('bookmark'); |
| +Sources.JavaScriptSourceFrame.BreakpointDecoration._elementSymbolForTest = Symbol('element'); |