Web Inspector: DOM: provide a way to disable/breakpoint all event listeners for a...
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / LayerDetailsSidebarPanel.js
1 /*
2  * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
3  * Copyright (C) 2017 Sony Interactive Entertainment Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 WI.LayerDetailsSidebarPanel = class LayerDetailsSidebarPanel extends WI.DetailsSidebarPanel
28 {
29     constructor()
30     {
31         super("layer", WI.UIString("All Layers"));
32
33         this.element.classList.add("layer");
34
35         this._layers = [];
36         this._layerIdToSelect = null;
37
38         this._dataGrid = null;
39         this._hoveredDataGridNode = null;
40         this._dataGridNodesByLayerId = new Map;
41
42         this._bottomBar = null;
43         this._layersCountLabel = null;
44         this._layersMemoryLabel = null;
45     }
46
47     // Public
48
49     inspect(objects)
50     {
51         if (!(objects instanceof Array))
52             objects = [objects];
53
54         let layers = objects.filter((object) => object instanceof WI.Layer);
55         this._updateLayers(layers);
56
57         return !!layers.length;
58     }
59
60     selectNodeByLayerId(layerId)
61     {
62         this._layerIdToSelect = null;
63
64         let node = this._dataGridNodesByLayerId.get(layerId);
65         if (node === this._dataGrid.selectedNode)
66             return;
67
68         const suppressEvent = true;
69         if (node)
70             node.revealAndSelect(suppressEvent);
71         else if (this._dataGrid.selectedNode)
72             this._dataGrid.selectedNode.deselect(suppressEvent);
73         else
74             this._layerIdToSelect = layerId;
75     }
76
77     // Private
78
79     _buildDataGrid()
80     {
81         const columns = {
82             name: {
83                 title: WI.UIString("Node"),
84                 sortable: false,
85             },
86             paintCount: {
87                 title: WI.UIString("Paints"),
88                 sortable: true,
89                 aligned: "right",
90                 width: "70px",
91             },
92             memory: {
93                 title: WI.UIString("Memory"),
94                 sortable: true,
95                 aligned: "right",
96                 width: "70px",
97             }
98         };
99
100         this._dataGrid = new WI.DataGrid(columns);
101         this._dataGrid.addEventListener(WI.DataGrid.Event.SortChanged, this._sortDataGrid, this);
102         this._dataGrid.addEventListener(WI.DataGrid.Event.SelectedNodeChanged, this._dataGridSelectedNodeChanged, this);
103
104         this._dataGrid.sortColumnIdentifier = "memory";
105         this._dataGrid.sortOrder = WI.DataGrid.SortOrder.Descending;
106         this._dataGrid.createSettings("layer-details-sidebar-panel");
107
108         this._dataGrid.element.addEventListener("mousemove", this._dataGridMouseMove.bind(this));
109         this._dataGrid.element.addEventListener("mouseleave", this._dataGridMouseLeave.bind(this));
110
111         // FIXME: We can't use virtualized rows until DataGrid is able to scroll them programmatically.
112         //        See TreeElement#reveal -> TreeOutline#updateVirtualizedElements for an analogy.
113         this._dataGrid.inline = true;
114         this._dataGrid.element.classList.remove("inline");
115
116         this.contentView.addSubview(this._dataGrid);
117     }
118
119     _buildBottomBar()
120     {
121         this._bottomBar = this.element.appendChild(document.createElement("div"));
122         this._bottomBar.className = "bottom-bar";
123
124         this._layersCountLabel = this._bottomBar.appendChild(document.createElement("div"));
125         this._layersCountLabel.className = "layers-count-label";
126
127         this._layersMemoryLabel = this._bottomBar.appendChild(document.createElement("div"));
128         this._layersMemoryLabel.className = "layers-memory-label";
129     }
130
131     _sortDataGrid()
132     {
133         let sortColumnIdentifier = this._dataGrid.sortColumnIdentifier;
134
135         function comparator(a, b) {
136             let itemA = a.layer[sortColumnIdentifier] || 0;
137             let itemB = b.layer[sortColumnIdentifier] || 0;
138             return itemA - itemB;
139         }
140
141         this._dataGrid.sortNodes(comparator);
142     }
143
144     _dataGridSelectedNodeChanged()
145     {
146         let layerId = this._dataGrid.selectedNode ? this._dataGrid.selectedNode.layer.layerId : null;
147         this.dispatchEventToListeners(WI.LayerDetailsSidebarPanel.Event.SelectedLayerChanged, {layerId});
148     }
149
150     _dataGridMouseMove(event)
151     {
152         let node = this._dataGrid.dataGridNodeFromNode(event.target);
153         if (node === this._hoveredDataGridNode)
154             return;
155
156         if (!node) {
157             this._hideDOMNodeHighlight();
158             return;
159         }
160
161         this._hoveredDataGridNode = node;
162
163         if (node.layer.isGeneratedContent || node.layer.isReflection || node.layer.isAnonymous) {
164             const usePageCoordinates = true;
165             WI.domManager.highlightRect(node.layer.bounds, usePageCoordinates);
166         } else
167             WI.domManager.highlightDOMNode(node.layer.nodeId);
168     }
169
170     _dataGridMouseLeave(event)
171     {
172         this._hideDOMNodeHighlight();
173     }
174
175     _hideDOMNodeHighlight()
176     {
177         WI.domManager.hideDOMNodeHighlight();
178         this._hoveredDataGridNode = null;
179     }
180
181     _updateLayers(newLayers)
182     {
183         this._updateDataGrid(newLayers);
184         this._updateBottomBar(newLayers);
185
186         this._layers = newLayers;
187     }
188
189     _updateDataGrid(newLayers)
190     {
191         if (!this._dataGrid)
192             this._buildDataGrid();
193
194         let {removals, additions, preserved} = WI.layerTreeManager.layerTreeMutations(this._layers, newLayers);
195
196         removals.forEach((layer) => {
197             let node = this._dataGridNodesByLayerId.get(layer.layerId);
198             this._dataGrid.removeChild(node);
199             this._dataGridNodesByLayerId.delete(layer.layerId);
200         });
201
202         additions.forEach((layer) => {
203             let node = new WI.LayerTreeDataGridNode(layer);
204             this._dataGridNodesByLayerId.set(layer.layerId, node);
205             this._dataGrid.appendChild(node);
206         });
207
208         preserved.forEach((layer) => {
209             let node = this._dataGridNodesByLayerId.get(layer.layerId);
210             node.layer = layer;
211         });
212
213         this._sortDataGrid();
214
215         if (this._layerIdToSelect)
216             this.selectNodeByLayerId(this._layerIdToSelect);
217     }
218
219     _updateBottomBar(newLayers)
220     {
221         if (!this._bottomBar)
222             this._buildBottomBar();
223
224         this._layersCountLabel.textContent = WI.UIString("Layer Count: %d").format(newLayers.length);
225
226         let totalMemory = newLayers.reduce((total, layer) => total + (layer.memory || 0), 0);
227         this._layersMemoryLabel.textContent = WI.UIString("Memory: %s").format(Number.bytesToString(totalMemory));
228     }
229 };
230
231 WI.LayerDetailsSidebarPanel.Event = {
232     SelectedLayerChanged: "selected-layer-changed"
233 };