WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
235924
Web Inspector: [Flexbox] Show flex badge next to flex containers in DOM Tree
https://bugs.webkit.org/show_bug.cgi?id=235924
Summary
Web Inspector: [Flexbox] Show flex badge next to flex containers in DOM Tree
Nikita Vasilyev
Reported
2022-01-31 16:03:47 PST
Show "flex" badge for elements with `display: flex` and `display: inline-flex`. <
rdar://problem/87886003
>
Attachments
WIP
(25.29 KB, patch)
2022-02-03 01:31 PST
,
Nikita Vasilyev
nvasilyev
: review-
nvasilyev
: commit-queue-
Details
Formatted Diff
Diff
Patch
(24.19 KB, patch)
2022-02-09 00:45 PST
,
Nikita Vasilyev
no flags
Details
Formatted Diff
Diff
Patch
(36.38 KB, patch)
2022-02-09 16:50 PST
,
Nikita Vasilyev
no flags
Details
Formatted Diff
Diff
Patch
(36.26 KB, patch)
2022-02-10 14:45 PST
,
Nikita Vasilyev
pangle
: review+
ews-feeder
: commit-queue-
Details
Formatted Diff
Diff
Patch
(36.15 KB, patch)
2022-02-10 23:56 PST
,
Nikita Vasilyev
no flags
Details
Formatted Diff
Diff
Show Obsolete
(4)
View All
Add attachment
proposed patch, testcase, etc.
Nikita Vasilyev
Comment 1
2022-02-03 01:31:11 PST
Created
attachment 450746
[details]
WIP NOT ready for review. This adds "Engineering -> Enable flexbox inspector" checkbox. Once enabled, it displays "flex" badges. Because this patch depends on
bug 236013
, Clicking on "flex" badges currently throws an exception: undefined is not an object (evaluating 'target.DOMAgent.showFlexOverlay.invoke') (at OverlayManager.js:116:40)
Razvan Caliman
Comment 2
2022-02-03 07:21:23 PST
Comment on
attachment 450746
[details]
WIP View in context:
https://bugs.webkit.org/attachment.cgi?id=450746&action=review
> Source/WebInspectorUI/UserInterface/Controllers/OverlayManager.js:253 > + this._nextDefaultGridColorIndex = (this._nextDefaultFlexColorIndex + 1) % WI.OverlayManager.defaultHSLColors.length;
We can make an infinitely looping iterator from the colors array and remove the all the associated logic for managing indexes. Context:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol
Perhaps this helper can live in `Source/WebInspectorUI/UserInterface/Base/Utilities.js`: ``` function makeInfiniteLoopingIterable(iterable) { console.assert(typeof iterable[Symbol.iterator] === "function", "Object is not iterable"); let _iterator = iterable[Symbol.iterator](); return { next: function() { let result = _iterator.next(); if (result.done) { this.reset(); return this.next(); } return result; }, reset: function() { _iterator = iterable[Symbol.iterator](); }, [Symbol.iterator]: function() { return this; } } } ``` It can be used like this: ``` // Create separate iterators for each overlay type this._defaultGridColorsIterator = makeInfiniteLoopingIterable(WI.OverlayManager.defaultHSLColors); this._defaultFlexColorsIterator = makeInfiniteLoopingIterable(WI.OverlayManager.defaultHSLColors); // ... // Keep calling .next() to the next color. Will loop automatically to the beginning when it reaches the end. defaultColor = this._defaultGridColorsIterator.next().value; // Manually reset the iterator to the first position, for example in `_handleMainResourceDidChange()` this._defaultGridColorsIterator.reset() ```
Razvan Caliman
Comment 3
2022-02-03 07:21:24 PST
Comment on
attachment 450746
[details]
WIP View in context:
https://bugs.webkit.org/attachment.cgi?id=450746&action=review
> Source/WebInspectorUI/UserInterface/Controllers/OverlayManager.js:253 > + this._nextDefaultGridColorIndex = (this._nextDefaultFlexColorIndex + 1) % WI.OverlayManager.defaultHSLColors.length;
We can make an infinitely looping iterator from the colors array and remove the all the associated logic for managing indexes. Context:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol
Perhaps this helper can live in `Source/WebInspectorUI/UserInterface/Base/Utilities.js`: ``` function makeInfiniteLoopingIterable(iterable) { console.assert(typeof iterable[Symbol.iterator] === "function", "Object is not iterable"); let _iterator = iterable[Symbol.iterator](); return { next: function() { let result = _iterator.next(); if (result.done) { this.reset(); return this.next(); } return result; }, reset: function() { _iterator = iterable[Symbol.iterator](); }, [Symbol.iterator]: function() { return this; } } } ``` It can be used like this: ``` // Create separate iterators for each overlay type this._defaultGridColorsIterator = makeInfiniteLoopingIterable(WI.OverlayManager.defaultHSLColors); this._defaultFlexColorsIterator = makeInfiniteLoopingIterable(WI.OverlayManager.defaultHSLColors); // ... // Keep calling .next() to the next color. Will loop automatically to the beginning when it reaches the end. defaultColor = this._defaultGridColorsIterator.next().value; // Manually reset the iterator to the first position, for example in `_handleMainResourceDidChange()` this._defaultGridColorsIterator.reset() ```
Nikita Vasilyev
Comment 4
2022-02-09 00:45:01 PST
Created
attachment 451344
[details]
Patch Fixed the bug when all flexbox overlays used the same pink color. The patch has a lot of straightforward changes to OverlayManager.js. Most grid-related methods and variables now have their flex counterparts, e.g. showGridOverlay/showFlexOverlay. This doesn't change the existing grid logic, which is good. The downside is that now we have a fair amount of code duplication. It's tempting to refactor this, but I don't think it's a good idea for the next 7 days.
Nikita Vasilyev
Comment 5
2022-02-09 01:05:00 PST
(In reply to Razvan Caliman from
comment #2
) Hm, I'm not strongly opposed to this, but I'm trying to minimize amount of changes (such as refactoring) in this patch.
Patrick Angle
Comment 6
2022-02-09 12:06:35 PST
Comment on
attachment 451344
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=451344&action=review
I'm not convinced that what you've done in OverlayManager is the right approach. Other than the actual command arguments and underlying protocol command, all the logic is shared between flex/grid overlays. Why do we need separate maps of nodes-to-color for the visible overlays? Why have separate events for grid/flex overlays when the event includes the overlay which has a node that tells you if it was/is a grid/flex container? I understand some things like getting the default colors need separate buckets to make sure that each set is a clean, repeating, sequence of colors, but a lot of other logic in here appears to just be duplicated between flex/grid which will only get more annoying if more overlays were to exist some day.
> Source/WebInspectorUI/UserInterface/Views/DOMTreeElement.js:2024 > + let isGrid = this.representedObject.layoutContextType === WI.DOMNode.LayoutContextType.Grid; > + let isFlex = this.representedObject.layoutContextType === WI.DOMNode.LayoutContextType.Flex && WI.settings.engineeringEnableFlexboxInspector.value;
We should probably just do a switch-case below where we set the text. And then here do a check for no layout context type (null) and iff the layout context is Flex then check the setting as well. E.g. ``` if (!this.representedObject.layoutContextType) return; if (this.representedObject.layoutContextType = WI.DOMNode.LayoutContextType.Flex && !WI.settings.engineeringEnableFlexboxInspector.value) return; ``` which makes it easier to scale with future overlays. And then use switch-case below for :2031-2034 with an assertion that we don't hit the `default` case.
> Source/WebInspectorUI/UserInterface/Views/DOMTreeElement.js:2087 > if (domNode.layoutContextType === WI.DOMNode.LayoutContextType.Grid) { > - WI.overlayManager.addEventListener(WI.OverlayManager.Event.GridOverlayShown, this._updateGridBadgeStatus, this); > - WI.overlayManager.addEventListener(WI.OverlayManager.Event.GridOverlayHidden, this._updateGridBadgeStatus, this); > + WI.overlayManager.addEventListener(WI.OverlayManager.Event.GridOverlayShown, this._updateLayoutBadgeStatus, this); > + WI.overlayManager.addEventListener(WI.OverlayManager.Event.GridOverlayHidden, this._updateLayoutBadgeStatus, this); > } else { > - WI.overlayManager.removeEventListener(WI.OverlayManager.Event.GridOverlayShown, this._updateGridBadgeStatus, this); > - WI.overlayManager.removeEventListener(WI.OverlayManager.Event.GridOverlayHidden, this._updateGridBadgeStatus, this); > + WI.overlayManager.removeEventListener(WI.OverlayManager.Event.GridOverlayShown, this._updateLayoutBadgeStatus, this); > + WI.overlayManager.removeEventListener(WI.OverlayManager.Event.GridOverlayHidden, this._updateLayoutBadgeStatus, this); > }
This doesn't seem correct. Don't we need to update for flex as well?
Nikita Vasilyev
Comment 7
2022-02-09 12:24:16 PST
(In reply to Patrick Angle from
comment #6
)
> Comment on
attachment 451344
[details]
> Patch > > View in context: >
https://bugs.webkit.org/attachment.cgi?id=451344&action=review
> > I'm not convinced that what you've done in OverlayManager is the right > approach. Other than the actual command arguments and underlying protocol > command, all the logic is shared between flex/grid overlays. Why do we need > separate maps of nodes-to-color for the visible overlays? Why have separate > events for grid/flex overlays when the event includes the overlay which has > a node that tells you if it was/is a grid/flex container? I understand some > things like getting the default colors need separate buckets to make sure > that each set is a clean, repeating, sequence of colors, but a lot of other > logic in here appears to just be duplicated between flex/grid which will > only get more annoying if more overlays were to exist some day.
I think you might be right. I'm going to try to reduce duplication now.
Nikita Vasilyev
Comment 8
2022-02-09 16:50:44 PST
Created
attachment 451462
[details]
Patch
Devin Rousso
Comment 9
2022-02-09 18:01:59 PST
Comment on
attachment 451462
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=451462&action=review
> Source/WebInspectorUI/UserInterface/Controllers/OverlayManager.js:56 > + console.assert(domNode.layoutContextType === WI.DOMNode.LayoutContextType.Grid || domNode.layoutContextType === WI.DOMNode.LayoutContextType.Flex, domNode.layoutContextType);
NIT: Is there any reason to enumerate each of the `WI.DOMNode.LayoutContextType`? Or can we just `Object.values(WI.DOMNode.LayoutContextType).includes(domNode.layoutContextType)`?
> Source/WebInspectorUI/UserInterface/Controllers/OverlayManager.js:72 > + break; > + case WI.DOMNode.LayoutContextType.Flex:
NIT: I'd add a newline between these
> Source/WebInspectorUI/UserInterface/Controllers/OverlayManager.js:-85 > - console.assert(domNode.layoutContextType === WI.DOMNode.LayoutContextType.Grid, domNode.layoutContextType);
Why is this removed? We could have this instead of the `default:` below.
> Source/WebInspectorUI/UserInterface/Controllers/OverlayManager.js:106 > + break; > + case WI.DOMNode.LayoutContextType.Flex:
ditto (:71)
> Source/WebInspectorUI/UserInterface/Controllers/OverlayManager.js:111 > + default: > + console.assert(false, domNode.layoutContextType); > + }
missing a `break;`
> Source/WebInspectorUI/UserInterface/Controllers/OverlayManager.js:126 > + isOverlayVisible(domNode)
NIT: Maybe `hasVisibleOverlay` instead?
> Source/WebInspectorUI/UserInterface/Controllers/OverlayManager.js:153 > + break; > + case WI.DOMNode.LayoutContextType.Flex:
ditto (:71)
> Source/WebInspectorUI/UserInterface/Controllers/OverlayManager.js:188 > + console.assert(domNode.layoutContextType !== WI.DOMNode.LayoutContextType.Grid && domNode.layoutContextType !== WI.DOMNode.LayoutContextType.Flex, domNode);
ditto (:56)
> Source/WebInspectorUI/UserInterface/Controllers/OverlayManager.js:222 > +WI.OverlayManager.defaultHSLColors = [
NIT: this should probably be `WI.OverlayManager._defaultHSLColors` since it's not meant to be used externally
> Source/WebInspectorUI/UserInterface/Views/DOMTreeElement.js:2030 > + this._layoutBadgeElement.className = "badge";
please make this `layout-badge` to better match the variable name (and be less generic)
> Source/WebInspectorUI/UserInterface/Views/DOMTreeElement.js:2036 > + break; > + case WI.DOMNode.LayoutContextType.Flex:
ditto (Source/WebInspectorUI/UserInterface/Controllers/OverlayManager.js:71)
> Source/WebInspectorUI/UserInterface/Views/DOMTreeElement.js:2041 > + default: > + console.assert(false, this.representedObject.layoutContextType); > + }
ditto (Source/WebInspectorUI/UserInterface/Controllers/OverlayManager.js:109)
> Source/WebInspectorUI/UserInterface/Views/DOMTreeElement.js:2044 > + this.title.append(this._layoutBadgeElement);
NIT: you can(/should) combine this with :2029 ``` this._layoutBadgeElement = this.title.appendChild(document.createElement("span")); ```
> Source/WebInspectorUI/UserInterface/Views/DOMTreeElement.js:2058 > + let initiator = this.representedObject.layoutContextType === WI.DOMNode.LayoutContextType.Grid ? WI.GridOverlayDiagnosticEventRecorder.Initiator.Badge : null;
NIT: I'd either inline this ``` WI.overlayManager.toggleOverlay(this.representedObject, { initiator: this.representedObject.layoutContextType === WI.DOMNode.LayoutContextType.Grid ? WI.GridOverlayDiagnosticEventRecorder.Initiator.Badge : null, }); ``` or make it so that you don't even create the property unless it has a value ``` let options = {}; if (this.representedObject.layoutContextType === WI.DOMNode.LayoutContextType.Grid) options.initiator = WI.GridOverlayDiagnosticEventRecorder.Initiator.Badge; WI.overlayManager.toggleOverlay(this.representedObject, options); ```
Nikita Vasilyev
Comment 10
2022-02-10 14:45:04 PST
Created
attachment 451603
[details]
Patch
Patrick Angle
Comment 11
2022-02-10 20:03:25 PST
Comment on
attachment 451603
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=451603&action=review
r=me, nice work! I'm glad we were able to do this with a lot less duplicated code.
> Source/WebInspectorUI/UserInterface/Controllers/OverlayManager.js:190 > + console.assert(Object.values(WI.DOMNode.LayoutContextType).includes(domNode.layoutContextType), domNode);
I don't think this assertion will pass if a node becomes something other than the currently recognized context types of Grid and Flex. Because changing from one context type to any other context type, or null, is valid I don't think we need an assertion here any more.
> Source/WebInspectorUI/UserInterface/Controllers/OverlayManager.js:220 > this._nextDefaultGridColorIndex = 0; > + this._nextDefaultFlexColorIndex = 0;
As an aside, I think we might have a pre-existing bug where the order of colors is possibly dependent on if the Layout sidebar panel is open when loading a page because only when it is open are all the various layout containers sent to the frontend. If just the DOM tree is visible, only the DOM nodes that have made it from the backend to the frontend will get badges, which means deeply nested child nodes with grid or flex contexts aren't known about until the tree is expanded, at which point you might have used color 1 before the child somewhere and color 2 after the child somewhere, which means we might use color 3 for the child, which in the document is declared between the first and second nodes that happened to already be visible. In practice I don't think this is too big of a deal, and given it is an existing potential issue with mild symptoms we certainly don't need to solve it in this patch. But I thought I'd mention it while it was fresh in my mind.
Nikita Vasilyev
Comment 12
2022-02-10 23:56:43 PST
Created
attachment 451650
[details]
Patch
EWS
Comment 13
2022-02-11 00:45:34 PST
Committed
r289610
(
247123@main
): <
https://commits.webkit.org/247123@main
> All reviewed patches have been landed. Closing bug and clearing flags on
attachment 451650
[details]
.
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug