| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 /** | |
| 5 * @unrestricted | |
| 6 */ | |
| 7 Components.RemoteObjectPreviewFormatter = class { | |
| 8 /** | |
| 9 * @param {!Protocol.Runtime.PropertyPreview} a | |
| 10 * @param {!Protocol.Runtime.PropertyPreview} b | |
| 11 * @return {number} | |
| 12 */ | |
| 13 static _objectPropertyComparator(a, b) { | |
| 14 if (a.type !== 'function' && b.type === 'function') | |
| 15 return -1; | |
| 16 if (a.type === 'function' && b.type !== 'function') | |
| 17 return 1; | |
| 18 return 0; | |
| 19 } | |
| 20 | |
| 21 /** | |
| 22 * @param {!Element} parentElement | |
| 23 * @param {!Protocol.Runtime.ObjectPreview} preview | |
| 24 * @param {boolean} isEntry | |
| 25 */ | |
| 26 appendObjectPreview(parentElement, preview, isEntry) { | |
| 27 const previewExperimentEnabled = Runtime.experiments.isEnabled('objectPrevie
ws'); | |
| 28 var description = preview.description; | |
| 29 if (preview.type !== 'object' || preview.subtype === 'null' || (previewExper
imentEnabled && isEntry)) { | |
| 30 parentElement.appendChild(this.renderPropertyPreview(preview.type, preview
.subtype, description)); | |
| 31 return; | |
| 32 } | |
| 33 const isArrayOrTypedArray = preview.subtype === 'array' || preview.subtype =
== 'typedarray'; | |
| 34 if (description) { | |
| 35 if (previewExperimentEnabled) { | |
| 36 // Hide the description for plain objects and plain arrays. | |
| 37 const plainObjectDescription = 'Object'; | |
| 38 const size = SDK.RemoteObject.arrayLength(preview) || SDK.RemoteObject.m
apOrSetEntriesCount(preview); | |
| 39 var text = preview.subtype === 'typedarray' ? SDK.RemoteObject.arrayName
FromDescription(description) : ''; | |
| 40 if (isArrayOrTypedArray) | |
| 41 text += size > 1 ? ('(' + size + ')') : ''; | |
| 42 else | |
| 43 text = description === plainObjectDescription ? '' : description; | |
| 44 if (text.length > 0) | |
| 45 parentElement.createChild('span', 'object-description').textContent =
text + ' '; | |
| 46 } else if (preview.subtype !== 'array') { | |
| 47 parentElement.createTextChildren(description, ' '); | |
| 48 } | |
| 49 } | |
| 50 | |
| 51 parentElement.createTextChild(isArrayOrTypedArray ? '[' : '{'); | |
| 52 if (preview.entries) | |
| 53 this._appendEntriesPreview(parentElement, preview); | |
| 54 else if (isArrayOrTypedArray) | |
| 55 this._appendArrayPropertiesPreview(parentElement, preview); | |
| 56 else | |
| 57 this._appendObjectPropertiesPreview(parentElement, preview); | |
| 58 if (preview.overflow) | |
| 59 parentElement.createChild('span').textContent = '\u2026'; | |
| 60 parentElement.createTextChild(isArrayOrTypedArray ? ']' : '}'); | |
| 61 } | |
| 62 | |
| 63 /** | |
| 64 * @param {string} description | |
| 65 * @return {string} | |
| 66 */ | |
| 67 _abbreviateFullQualifiedClassName(description) { | |
| 68 var abbreviatedDescription = description.split('.'); | |
| 69 for (var i = 0; i < abbreviatedDescription.length - 1; ++i) | |
| 70 abbreviatedDescription[i] = abbreviatedDescription[i].trimMiddle(3); | |
| 71 return abbreviatedDescription.join('.'); | |
| 72 } | |
| 73 | |
| 74 /** | |
| 75 * @param {!Element} parentElement | |
| 76 * @param {!Protocol.Runtime.ObjectPreview} preview | |
| 77 */ | |
| 78 _appendObjectPropertiesPreview(parentElement, preview) { | |
| 79 var properties = preview.properties.filter(p => p.type !== 'accessor') | |
| 80 .stableSort(Components.RemoteObjectPreviewFormatter._ob
jectPropertyComparator); | |
| 81 for (var i = 0; i < properties.length; ++i) { | |
| 82 if (i > 0) | |
| 83 parentElement.createTextChild(', '); | |
| 84 | |
| 85 var property = properties[i]; | |
| 86 parentElement.appendChild(this._renderDisplayName(property.name)); | |
| 87 parentElement.createTextChild(': '); | |
| 88 parentElement.appendChild(this._renderPropertyPreviewOrAccessor([property]
)); | |
| 89 } | |
| 90 } | |
| 91 | |
| 92 /** | |
| 93 * @param {!Element} parentElement | |
| 94 * @param {!Protocol.Runtime.ObjectPreview} preview | |
| 95 */ | |
| 96 _appendArrayPropertiesPreview(parentElement, preview) { | |
| 97 var arrayLength = SDK.RemoteObject.arrayLength(preview); | |
| 98 var indexProperties = preview.properties.filter(p => toArrayIndex(p.name) !=
= -1).stableSort(arrayEntryComparator); | |
| 99 var otherProperties = preview.properties.filter(p => toArrayIndex(p.name) ==
= -1) | |
| 100 .stableSort(Components.RemoteObjectPreviewFormatte
r._objectPropertyComparator); | |
| 101 | |
| 102 /** | |
| 103 * @param {!Protocol.Runtime.PropertyPreview} a | |
| 104 * @param {!Protocol.Runtime.PropertyPreview} b | |
| 105 * @return {number} | |
| 106 */ | |
| 107 function arrayEntryComparator(a, b) { | |
| 108 return toArrayIndex(a.name) - toArrayIndex(b.name); | |
| 109 } | |
| 110 | |
| 111 /** | |
| 112 * @param {string} name | |
| 113 * @return {number} | |
| 114 */ | |
| 115 function toArrayIndex(name) { | |
| 116 var index = name >>> 0; | |
| 117 if (String(index) === name && index < arrayLength) | |
| 118 return index; | |
| 119 return -1; | |
| 120 } | |
| 121 | |
| 122 // Gaps can be shown when all properties are guaranteed to be in the preview
. | |
| 123 var canShowGaps = !preview.overflow; | |
| 124 var lastNonEmptyArrayIndex = -1; | |
| 125 var elementsAdded = false; | |
| 126 for (var i = 0; i < indexProperties.length; ++i) { | |
| 127 if (elementsAdded) | |
| 128 parentElement.createTextChild(', '); | |
| 129 | |
| 130 var property = indexProperties[i]; | |
| 131 var index = toArrayIndex(property.name); | |
| 132 if (canShowGaps && index - lastNonEmptyArrayIndex > 1) { | |
| 133 appendUndefined(index); | |
| 134 parentElement.createTextChild(', '); | |
| 135 } | |
| 136 if (!canShowGaps && i !== index) { | |
| 137 parentElement.appendChild(this._renderDisplayName(property.name)); | |
| 138 parentElement.createTextChild(': '); | |
| 139 } | |
| 140 parentElement.appendChild(this._renderPropertyPreviewOrAccessor([property]
)); | |
| 141 lastNonEmptyArrayIndex = index; | |
| 142 elementsAdded = true; | |
| 143 } | |
| 144 | |
| 145 if (canShowGaps && arrayLength - lastNonEmptyArrayIndex > 1) { | |
| 146 if (elementsAdded) | |
| 147 parentElement.createTextChild(', '); | |
| 148 appendUndefined(arrayLength); | |
| 149 } | |
| 150 | |
| 151 for (var i = 0; i < otherProperties.length; ++i) { | |
| 152 if (elementsAdded) | |
| 153 parentElement.createTextChild(', '); | |
| 154 | |
| 155 var property = otherProperties[i]; | |
| 156 parentElement.appendChild(this._renderDisplayName(property.name)); | |
| 157 parentElement.createTextChild(': '); | |
| 158 parentElement.appendChild(this._renderPropertyPreviewOrAccessor([property]
)); | |
| 159 elementsAdded = true; | |
| 160 } | |
| 161 | |
| 162 /** | |
| 163 * @param {number} index | |
| 164 */ | |
| 165 function appendUndefined(index) { | |
| 166 var span = parentElement.createChild('span', 'object-value-undefined'); | |
| 167 span.textContent = Common.UIString('undefined × %d', index - lastNonEmptyA
rrayIndex - 1); | |
| 168 elementsAdded = true; | |
| 169 } | |
| 170 } | |
| 171 | |
| 172 /** | |
| 173 * @param {!Element} parentElement | |
| 174 * @param {!Protocol.Runtime.ObjectPreview} preview | |
| 175 */ | |
| 176 _appendEntriesPreview(parentElement, preview) { | |
| 177 for (var i = 0; i < preview.entries.length; ++i) { | |
| 178 if (i > 0) | |
| 179 parentElement.createTextChild(', '); | |
| 180 | |
| 181 var entry = preview.entries[i]; | |
| 182 if (entry.key) { | |
| 183 this.appendObjectPreview(parentElement, entry.key, true /* isEntry */); | |
| 184 parentElement.createTextChild(' => '); | |
| 185 } | |
| 186 this.appendObjectPreview(parentElement, entry.value, true /* isEntry */); | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 /** | |
| 191 * @param {string} name | |
| 192 * @return {!Element} | |
| 193 */ | |
| 194 _renderDisplayName(name) { | |
| 195 var result = createElementWithClass('span', 'name'); | |
| 196 var needsQuotes = /^\s|\s$|^$|\n/.test(name); | |
| 197 result.textContent = needsQuotes ? '"' + name.replace(/\n/g, '\u21B5') + '"'
: name; | |
| 198 return result; | |
| 199 } | |
| 200 | |
| 201 /** | |
| 202 * @param {!Array.<!Protocol.Runtime.PropertyPreview>} propertyPath | |
| 203 * @return {!Element} | |
| 204 */ | |
| 205 _renderPropertyPreviewOrAccessor(propertyPath) { | |
| 206 var property = propertyPath.peekLast(); | |
| 207 return this.renderPropertyPreview(property.type, /** @type {string} */ (prop
erty.subtype), property.value); | |
| 208 } | |
| 209 | |
| 210 /** | |
| 211 * @param {string} type | |
| 212 * @param {string=} subtype | |
| 213 * @param {string=} description | |
| 214 * @return {!Element} | |
| 215 */ | |
| 216 renderPropertyPreview(type, subtype, description) { | |
| 217 var span = createElementWithClass('span', 'object-value-' + (subtype || type
)); | |
| 218 description = description || ''; | |
| 219 | |
| 220 if (type === 'accessor') { | |
| 221 span.textContent = '(...)'; | |
| 222 span.title = Common.UIString('The property is computed with a getter'); | |
| 223 return span; | |
| 224 } | |
| 225 | |
| 226 if (type === 'function') { | |
| 227 span.textContent = 'function'; | |
| 228 return span; | |
| 229 } | |
| 230 | |
| 231 if (type === 'object' && subtype === 'node' && description) { | |
| 232 Components.DOMPresentationUtils.createSpansForNodeTitle(span, description)
; | |
| 233 return span; | |
| 234 } | |
| 235 | |
| 236 if (type === 'string') { | |
| 237 span.createTextChildren('"', description.replace(/\n/g, '\u21B5'), '"'); | |
| 238 return span; | |
| 239 } | |
| 240 | |
| 241 if (type === 'object' && !subtype) { | |
| 242 span.textContent = this._abbreviateFullQualifiedClassName(description); | |
| 243 span.title = description; | |
| 244 return span; | |
| 245 } | |
| 246 | |
| 247 span.textContent = description; | |
| 248 return span; | |
| 249 } | |
| 250 }; | |
| OLD | NEW |