OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2007 Apple Inc. All rights reserved. | 2 * Copyright (C) 2007 Apple Inc. All rights reserved. |
3 * Copyright (C) 2014 Google Inc. All rights reserved. | 3 * Copyright (C) 2014 Google Inc. All rights reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
7 * are met: | 7 * are met: |
8 * | 8 * |
9 * 1. Redistributions of source code must retain the above copyright | 9 * 1. Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
11 * 2. Redistributions in binary form must reproduce the above copyright | 11 * 2. Redistributions in binary form must reproduce the above copyright |
12 * notice, this list of conditions and the following disclaimer in the | 12 * notice, this list of conditions and the following disclaimer in the |
13 * documentation and/or other materials provided with the distribution. | 13 * documentation and/or other materials provided with the distribution. |
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of | 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
15 * its contributors may be used to endorse or promote products derived | 15 * its contributors may be used to endorse or promote products derived |
16 * from this software without specific prior written permission. | 16 * from this software without specific prior written permission. |
17 * | 17 * |
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 */ | 28 */ |
| 29 /** |
| 30 * @unrestricted |
| 31 */ |
| 32 WebInspector.PropertiesWidget = class extends WebInspector.ThrottledWidget { |
| 33 constructor() { |
| 34 super(); |
29 | 35 |
30 /** | 36 WebInspector.targetManager.addModelListener( |
31 * @constructor | 37 WebInspector.DOMModel, WebInspector.DOMModel.Events.AttrModified, this._
onNodeChange, this); |
32 * @extends {WebInspector.ThrottledWidget} | 38 WebInspector.targetManager.addModelListener( |
33 */ | 39 WebInspector.DOMModel, WebInspector.DOMModel.Events.AttrRemoved, this._o
nNodeChange, this); |
34 WebInspector.PropertiesWidget = function() | 40 WebInspector.targetManager.addModelListener( |
35 { | 41 WebInspector.DOMModel, WebInspector.DOMModel.Events.CharacterDataModifie
d, this._onNodeChange, this); |
36 WebInspector.ThrottledWidget.call(this); | 42 WebInspector.targetManager.addModelListener( |
37 | 43 WebInspector.DOMModel, WebInspector.DOMModel.Events.ChildNodeCountUpdate
d, this._onNodeChange, this); |
38 WebInspector.targetManager.addModelListener(WebInspector.DOMModel, WebInspec
tor.DOMModel.Events.AttrModified, this._onNodeChange, this); | |
39 WebInspector.targetManager.addModelListener(WebInspector.DOMModel, WebInspec
tor.DOMModel.Events.AttrRemoved, this._onNodeChange, this); | |
40 WebInspector.targetManager.addModelListener(WebInspector.DOMModel, WebInspec
tor.DOMModel.Events.CharacterDataModified, this._onNodeChange, this); | |
41 WebInspector.targetManager.addModelListener(WebInspector.DOMModel, WebInspec
tor.DOMModel.Events.ChildNodeCountUpdated, this._onNodeChange, this); | |
42 WebInspector.context.addFlavorChangeListener(WebInspector.DOMNode, this._set
Node, this); | 44 WebInspector.context.addFlavorChangeListener(WebInspector.DOMNode, this._set
Node, this); |
43 this._node = WebInspector.context.flavor(WebInspector.DOMNode); | 45 this._node = WebInspector.context.flavor(WebInspector.DOMNode); |
44 this.update(); | 46 this.update(); |
| 47 } |
| 48 |
| 49 /** |
| 50 * @param {!WebInspector.Event} event |
| 51 */ |
| 52 _setNode(event) { |
| 53 this._node = /** @type {?WebInspector.DOMNode} */ (event.data); |
| 54 this.update(); |
| 55 } |
| 56 |
| 57 /** |
| 58 * @override |
| 59 * @protected |
| 60 * @return {!Promise.<?>} |
| 61 */ |
| 62 doUpdate() { |
| 63 if (this._lastRequestedNode) { |
| 64 this._lastRequestedNode.target().runtimeAgent().releaseObjectGroup( |
| 65 WebInspector.PropertiesWidget._objectGroupName); |
| 66 delete this._lastRequestedNode; |
| 67 } |
| 68 |
| 69 if (!this._node) { |
| 70 this.element.removeChildren(); |
| 71 this.sections = []; |
| 72 return Promise.resolve(); |
| 73 } |
| 74 |
| 75 this._lastRequestedNode = this._node; |
| 76 return this._node.resolveToObjectPromise(WebInspector.PropertiesWidget._obje
ctGroupName) |
| 77 .then(nodeResolved.bind(this)); |
| 78 |
| 79 /** |
| 80 * @param {?WebInspector.RemoteObject} object |
| 81 * @this {WebInspector.PropertiesWidget} |
| 82 */ |
| 83 function nodeResolved(object) { |
| 84 if (!object) |
| 85 return; |
| 86 |
| 87 /** |
| 88 * @suppressReceiverCheck |
| 89 * @this {*} |
| 90 */ |
| 91 function protoList() { |
| 92 var proto = this; |
| 93 var result = {__proto__: null}; |
| 94 var counter = 1; |
| 95 while (proto) { |
| 96 result[counter++] = proto; |
| 97 proto = proto.__proto__; |
| 98 } |
| 99 return result; |
| 100 } |
| 101 var promise = object.callFunctionPromise(protoList).then(nodePrototypesRea
dy.bind(this)); |
| 102 object.release(); |
| 103 return promise; |
| 104 } |
| 105 |
| 106 /** |
| 107 * @param {!{object: ?WebInspector.RemoteObject, wasThrown: (boolean|undefin
ed)}} result |
| 108 * @this {WebInspector.PropertiesWidget} |
| 109 */ |
| 110 function nodePrototypesReady(result) { |
| 111 if (!result.object || result.wasThrown) |
| 112 return; |
| 113 |
| 114 var promise = result.object.getOwnPropertiesPromise().then(fillSection.bin
d(this)); |
| 115 result.object.release(); |
| 116 return promise; |
| 117 } |
| 118 |
| 119 /** |
| 120 * @param {!{properties: ?Array.<!WebInspector.RemoteObjectProperty>, intern
alProperties: ?Array.<!WebInspector.RemoteObjectProperty>}} result |
| 121 * @this {WebInspector.PropertiesWidget} |
| 122 */ |
| 123 function fillSection(result) { |
| 124 if (!result || !result.properties) |
| 125 return; |
| 126 |
| 127 var properties = result.properties; |
| 128 var expanded = []; |
| 129 var sections = this.sections || []; |
| 130 for (var i = 0; i < sections.length; ++i) |
| 131 expanded.push(sections[i].expanded); |
| 132 |
| 133 this.element.removeChildren(); |
| 134 this.sections = []; |
| 135 |
| 136 // Get array of property user-friendly names. |
| 137 for (var i = 0; i < properties.length; ++i) { |
| 138 if (!parseInt(properties[i].name, 10)) |
| 139 continue; |
| 140 var property = properties[i].value; |
| 141 var title = property.description; |
| 142 title = title.replace(/Prototype$/, ''); |
| 143 var section = new WebInspector.ObjectPropertiesSection(property, title); |
| 144 section.element.classList.add('properties-widget-section'); |
| 145 this.sections.push(section); |
| 146 this.element.appendChild(section.element); |
| 147 if (expanded[this.sections.length - 1]) |
| 148 section.expand(); |
| 149 section.addEventListener(TreeOutline.Events.ElementExpanded, this._prope
rtyExpanded, this); |
| 150 } |
| 151 } |
| 152 } |
| 153 |
| 154 /** |
| 155 * @param {!WebInspector.Event} event |
| 156 */ |
| 157 _propertyExpanded(event) { |
| 158 WebInspector.userMetrics.actionTaken(WebInspector.UserMetrics.Action.DOMProp
ertiesExpanded); |
| 159 for (var section of this.sections) { |
| 160 section.removeEventListener(TreeOutline.Events.ElementExpanded, this._prop
ertyExpanded, this); |
| 161 } |
| 162 } |
| 163 |
| 164 /** |
| 165 * @param {!WebInspector.Event} event |
| 166 */ |
| 167 _onNodeChange(event) { |
| 168 if (!this._node) |
| 169 return; |
| 170 var data = event.data; |
| 171 var node = /** @type {!WebInspector.DOMNode} */ (data instanceof WebInspecto
r.DOMNode ? data : data.node); |
| 172 if (this._node !== node) |
| 173 return; |
| 174 this.update(); |
| 175 } |
45 }; | 176 }; |
46 | 177 |
47 WebInspector.PropertiesWidget._objectGroupName = "properties-sidebar-pane"; | 178 WebInspector.PropertiesWidget._objectGroupName = 'properties-sidebar-pane'; |
48 | |
49 WebInspector.PropertiesWidget.prototype = { | |
50 /** | |
51 * @param {!WebInspector.Event} event | |
52 */ | |
53 _setNode: function(event) | |
54 { | |
55 this._node = /** @type {?WebInspector.DOMNode} */(event.data); | |
56 this.update(); | |
57 }, | |
58 | |
59 /** | |
60 * @override | |
61 * @protected | |
62 * @return {!Promise.<?>} | |
63 */ | |
64 doUpdate: function() | |
65 { | |
66 if (this._lastRequestedNode) { | |
67 this._lastRequestedNode.target().runtimeAgent().releaseObjectGroup(W
ebInspector.PropertiesWidget._objectGroupName); | |
68 delete this._lastRequestedNode; | |
69 } | |
70 | |
71 if (!this._node) { | |
72 this.element.removeChildren(); | |
73 this.sections = []; | |
74 return Promise.resolve(); | |
75 } | |
76 | |
77 this._lastRequestedNode = this._node; | |
78 return this._node.resolveToObjectPromise(WebInspector.PropertiesWidget._
objectGroupName) | |
79 .then(nodeResolved.bind(this)); | |
80 | |
81 /** | |
82 * @param {?WebInspector.RemoteObject} object | |
83 * @this {WebInspector.PropertiesWidget} | |
84 */ | |
85 function nodeResolved(object) | |
86 { | |
87 if (!object) | |
88 return; | |
89 | |
90 /** | |
91 * @suppressReceiverCheck | |
92 * @this {*} | |
93 */ | |
94 function protoList() | |
95 { | |
96 var proto = this; | |
97 var result = { __proto__: null }; | |
98 var counter = 1; | |
99 while (proto) { | |
100 result[counter++] = proto; | |
101 proto = proto.__proto__; | |
102 } | |
103 return result; | |
104 } | |
105 var promise = object.callFunctionPromise(protoList).then(nodePrototy
pesReady.bind(this)); | |
106 object.release(); | |
107 return promise; | |
108 } | |
109 | |
110 /** | |
111 * @param {!{object: ?WebInspector.RemoteObject, wasThrown: (boolean|und
efined)}} result | |
112 * @this {WebInspector.PropertiesWidget} | |
113 */ | |
114 function nodePrototypesReady(result) | |
115 { | |
116 if (!result.object || result.wasThrown) | |
117 return; | |
118 | |
119 var promise = result.object.getOwnPropertiesPromise().then(fillSecti
on.bind(this)); | |
120 result.object.release(); | |
121 return promise; | |
122 } | |
123 | |
124 /** | |
125 * @param {!{properties: ?Array.<!WebInspector.RemoteObjectProperty>, in
ternalProperties: ?Array.<!WebInspector.RemoteObjectProperty>}} result | |
126 * @this {WebInspector.PropertiesWidget} | |
127 */ | |
128 function fillSection(result) | |
129 { | |
130 if (!result || !result.properties) | |
131 return; | |
132 | |
133 var properties = result.properties; | |
134 var expanded = []; | |
135 var sections = this.sections || []; | |
136 for (var i = 0; i < sections.length; ++i) | |
137 expanded.push(sections[i].expanded); | |
138 | |
139 this.element.removeChildren(); | |
140 this.sections = []; | |
141 | |
142 // Get array of property user-friendly names. | |
143 for (var i = 0; i < properties.length; ++i) { | |
144 if (!parseInt(properties[i].name, 10)) | |
145 continue; | |
146 var property = properties[i].value; | |
147 var title = property.description; | |
148 title = title.replace(/Prototype$/, ""); | |
149 var section = new WebInspector.ObjectPropertiesSection(property,
title); | |
150 section.element.classList.add("properties-widget-section"); | |
151 this.sections.push(section); | |
152 this.element.appendChild(section.element); | |
153 if (expanded[this.sections.length - 1]) | |
154 section.expand(); | |
155 section.addEventListener(TreeOutline.Events.ElementExpanded, thi
s._propertyExpanded, this); | |
156 } | |
157 } | |
158 }, | |
159 | |
160 /** | |
161 * @param {!WebInspector.Event} event | |
162 */ | |
163 _propertyExpanded: function(event) | |
164 { | |
165 WebInspector.userMetrics.actionTaken(WebInspector.UserMetrics.Action.DOM
PropertiesExpanded); | |
166 for (var section of this.sections) { | |
167 section.removeEventListener(TreeOutline.Events.ElementExpanded, this
._propertyExpanded, this); | |
168 } | |
169 }, | |
170 | |
171 /** | |
172 * @param {!WebInspector.Event} event | |
173 */ | |
174 _onNodeChange: function(event) | |
175 { | |
176 if (!this._node) | |
177 return; | |
178 var data = event.data; | |
179 var node = /** @type {!WebInspector.DOMNode} */ (data instanceof WebInsp
ector.DOMNode ? data : data.node); | |
180 if (this._node !== node) | |
181 return; | |
182 this.update(); | |
183 }, | |
184 | |
185 __proto__: WebInspector.ThrottledWidget.prototype | |
186 }; | |
OLD | NEW |