OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. | |
3 * Copyright (C) 2009 Joseph Pecoraro | |
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. ``AS IS'' AND ANY | |
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
25 */ | |
26 | |
27 WebInspector.ObjectPropertiesSection = function(object, title, subtitle, emptyPl
aceholder, ignoreHasOwnProperty, extraProperties, treeElementConstructor) | |
28 { | |
29 this.emptyPlaceholder = (emptyPlaceholder || WebInspector.UIString("No Prope
rties")); | |
30 this.object = object; | |
31 this.ignoreHasOwnProperty = ignoreHasOwnProperty; | |
32 this.extraProperties = extraProperties; | |
33 this.treeElementConstructor = treeElementConstructor || WebInspector.ObjectP
ropertyTreeElement; | |
34 this.editable = true; | |
35 | |
36 WebInspector.PropertiesSection.call(this, title, subtitle); | |
37 } | |
38 | |
39 WebInspector.ObjectPropertiesSection.prototype = { | |
40 onpopulate: function() | |
41 { | |
42 this.update(); | |
43 }, | |
44 | |
45 update: function() | |
46 { | |
47 var self = this; | |
48 var callback = function(properties) { | |
49 if (!properties) | |
50 return; | |
51 self.updateProperties(properties); | |
52 }; | |
53 InjectedScriptAccess.getProperties(this.object, this.ignoreHasOwnPropert
y, callback); | |
54 }, | |
55 | |
56 updateProperties: function(properties, rootTreeElementConstructor, rootPrope
rtyComparer) | |
57 { | |
58 if (!rootTreeElementConstructor) | |
59 rootTreeElementConstructor = this.treeElementConstructor; | |
60 | |
61 if (!rootPropertyComparer) | |
62 rootPropertyComparer = WebInspector.ObjectPropertiesSection.CompareP
roperties; | |
63 | |
64 if (this.extraProperties) | |
65 for (var i = 0; i < this.extraProperties.length; ++i) | |
66 properties.push(this.extraProperties[i]); | |
67 | |
68 properties.sort(rootPropertyComparer); | |
69 | |
70 this.propertiesTreeOutline.removeChildren(); | |
71 | |
72 for (var i = 0; i < properties.length; ++i) | |
73 this.propertiesTreeOutline.appendChild(new rootTreeElementConstructo
r(properties[i])); | |
74 | |
75 if (!this.propertiesTreeOutline.children.length) { | |
76 var title = "<div class=\"info\">" + this.emptyPlaceholder + "</div>
"; | |
77 var infoElement = new TreeElement(title, null, false); | |
78 this.propertiesTreeOutline.appendChild(infoElement); | |
79 } | |
80 } | |
81 } | |
82 | |
83 WebInspector.ObjectPropertiesSection.prototype.__proto__ = WebInspector.Properti
esSection.prototype; | |
84 | |
85 WebInspector.ObjectPropertiesSection.CompareProperties = function(propertyA, pro
pertyB) | |
86 { | |
87 var a = propertyA.name; | |
88 var b = propertyB.name; | |
89 | |
90 // if used elsewhere make sure to | |
91 // - convert a and b to strings (not needed here, properties are all string
s) | |
92 // - check if a == b (not needed here, no two properties can be the same) | |
93 | |
94 var diff = 0; | |
95 var chunk = /^\d+|^\D+/; | |
96 var chunka, chunkb, anum, bnum; | |
97 while (diff === 0) { | |
98 if (!a && b) | |
99 return -1; | |
100 if (!b && a) | |
101 return 1; | |
102 chunka = a.match(chunk)[0]; | |
103 chunkb = b.match(chunk)[0]; | |
104 anum = !isNaN(chunka); | |
105 bnum = !isNaN(chunkb); | |
106 if (anum && !bnum) | |
107 return -1; | |
108 if (bnum && !anum) | |
109 return 1; | |
110 if (anum && bnum) { | |
111 diff = chunka - chunkb; | |
112 if (diff === 0 && chunka.length !== chunkb.length) { | |
113 if (!+chunka && !+chunkb) // chunks are strings of all 0s (speci
al case) | |
114 return chunka.length - chunkb.length; | |
115 else | |
116 return chunkb.length - chunka.length; | |
117 } | |
118 } else if (chunka !== chunkb) | |
119 return (chunka < chunkb) ? -1 : 1; | |
120 a = a.substring(chunka.length); | |
121 b = b.substring(chunkb.length); | |
122 } | |
123 return diff; | |
124 } | |
125 | |
126 WebInspector.ObjectPropertyTreeElement = function(property) | |
127 { | |
128 this.property = property; | |
129 | |
130 // Pass an empty title, the title gets made later in onattach. | |
131 TreeElement.call(this, "", null, false); | |
132 } | |
133 | |
134 WebInspector.ObjectPropertyTreeElement.prototype = { | |
135 onpopulate: function() | |
136 { | |
137 if (this.children.length && !this.shouldRefreshChildren) | |
138 return; | |
139 | |
140 var callback = function(properties) { | |
141 this.removeChildren(); | |
142 if (!properties) | |
143 return; | |
144 | |
145 properties.sort(WebInspector.ObjectPropertiesSection.CompareProperti
es); | |
146 for (var i = 0; i < properties.length; ++i) { | |
147 this.appendChild(new this.treeOutline.section.treeElementConstru
ctor(properties[i])); | |
148 } | |
149 }; | |
150 InjectedScriptAccess.getProperties(this.property.value, false, callback.
bind(this)); | |
151 }, | |
152 | |
153 ondblclick: function(element, event) | |
154 { | |
155 this.startEditing(); | |
156 }, | |
157 | |
158 onattach: function() | |
159 { | |
160 this.update(); | |
161 }, | |
162 | |
163 update: function() | |
164 { | |
165 this.nameElement = document.createElement("span"); | |
166 this.nameElement.className = "name"; | |
167 this.nameElement.textContent = this.property.name; | |
168 | |
169 var separatorElement = document.createElement("span"); | |
170 separatorElement.className = "separator"; | |
171 separatorElement.textContent = ": "; | |
172 | |
173 this.valueElement = document.createElement("span"); | |
174 this.valueElement.className = "value"; | |
175 this.valueElement.textContent = this.property.value.description; | |
176 if (this.property.isGetter) | |
177 this.valueElement.addStyleClass("dimmed"); | |
178 | |
179 this.listItemElement.removeChildren(); | |
180 | |
181 this.listItemElement.appendChild(this.nameElement); | |
182 this.listItemElement.appendChild(separatorElement); | |
183 this.listItemElement.appendChild(this.valueElement); | |
184 this.hasChildren = this.property.value.hasChildren; | |
185 }, | |
186 | |
187 updateSiblings: function() | |
188 { | |
189 if (this.parent.root) | |
190 this.treeOutline.section.update(); | |
191 else | |
192 this.parent.shouldRefreshChildren = true; | |
193 }, | |
194 | |
195 startEditing: function() | |
196 { | |
197 if (WebInspector.isBeingEdited(this.valueElement) || !this.treeOutline.s
ection.editable) | |
198 return; | |
199 | |
200 var context = { expanded: this.expanded }; | |
201 | |
202 // Lie about our children to prevent expanding on double click and to co
llapse subproperties. | |
203 this.hasChildren = false; | |
204 | |
205 this.listItemElement.addStyleClass("editing-sub-part"); | |
206 | |
207 WebInspector.startEditing(this.valueElement, this.editingCommitted.bind(
this), this.editingCancelled.bind(this), context); | |
208 }, | |
209 | |
210 editingEnded: function(context) | |
211 { | |
212 this.listItemElement.scrollLeft = 0; | |
213 this.listItemElement.removeStyleClass("editing-sub-part"); | |
214 if (context.expanded) | |
215 this.expand(); | |
216 }, | |
217 | |
218 editingCancelled: function(element, context) | |
219 { | |
220 this.update(); | |
221 this.editingEnded(context); | |
222 }, | |
223 | |
224 editingCommitted: function(element, userInput, previousContent, context) | |
225 { | |
226 if (userInput === previousContent) | |
227 return this.editingCancelled(element, context); // nothing changed,
so cancel | |
228 | |
229 this.applyExpression(userInput, true); | |
230 | |
231 this.editingEnded(context); | |
232 }, | |
233 | |
234 applyExpression: function(expression, updateInterface) | |
235 { | |
236 expression = expression.trimWhitespace(); | |
237 var expressionLength = expression.length; | |
238 var self = this; | |
239 var callback = function(success) { | |
240 if (!updateInterface) | |
241 return; | |
242 | |
243 if (!success) | |
244 self.update(); | |
245 | |
246 if (!expressionLength) { | |
247 // The property was deleted, so remove this tree element. | |
248 self.parent.removeChild(this); | |
249 } else { | |
250 // Call updateSiblings since their value might be based on the v
alue that just changed. | |
251 self.updateSiblings(); | |
252 } | |
253 }; | |
254 InjectedScriptAccess.setPropertyValue(this.property.parentObjectProxy, t
his.property.name, expression.trimWhitespace(), callback); | |
255 } | |
256 } | |
257 | |
258 WebInspector.ObjectPropertyTreeElement.prototype.__proto__ = TreeElement.prototy
pe; | |
OLD | NEW |