| 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 |