1<!DOCTYPE html> 2<!-- 3Copyright (c) 2013 The Chromium Authors. All rights reserved. 4Use of this source code is governed by a BSD-style license that can be 5found in the LICENSE file. 6--> 7 8<link rel="import" href="/tracing/base/rect.html"> 9<link rel="import" href="/tracing/base/utils.html"> 10<link rel="import" href="/tracing/model/event_set.html"> 11<link rel="import" href="/tracing/model/object_instance.html"> 12<link rel="import" href="/tracing/model/object_snapshot.html"> 13<link rel="import" href="/tracing/ui/analysis/analysis_link.html"> 14<link rel="import" href="/tracing/ui/base/table.html"> 15<link rel="import" href="/tracing/ui/base/ui.html"> 16<link rel="import" href="/tracing/value/numeric.html"> 17<link rel="import" href="/tracing/value/ui/scalar_span.html"> 18 19<polymer-element name="tr-ui-a-generic-object-view" 20 is="HTMLUnknownElement"> 21 <template> 22 <style> 23 :host { 24 display: block; 25 font-family: monospace; 26 } 27 </style> 28 <div id="content"> 29 </div> 30 </template> 31 32 <script> 33 'use strict'; 34 35 function isTable(object) { 36 if (!(object instanceof Array) || 37 (object.length < 2)) return false; 38 for (var colName in object[0]) { 39 if (typeof colName !== 'string') return false; 40 } 41 for (var i = 0; i < object.length; ++i) { 42 if (!(object[i] instanceof Object)) return false; 43 for (var colName in object[i]) { 44 if (i && (object[0][colName] === undefined)) return false; 45 var cellType = typeof object[i][colName]; 46 if (cellType !== 'string' && cellType != 'number') return false; 47 } 48 if (i) { 49 for (var colName in object[0]) { 50 if (object[i][colName] === undefined) return false; 51 } 52 } 53 } 54 return true; 55 } 56 57 Polymer({ 58 ready: function() { 59 this.object_ = undefined; 60 }, 61 62 get object() { 63 return this.object_; 64 }, 65 66 set object(object) { 67 this.object_ = object; 68 this.updateContents_(); 69 }, 70 71 updateContents_: function() { 72 this.$.content.textContent = ''; 73 this.appendElementsForType_('', this.object_, 0, 0, 5, ''); 74 }, 75 76 appendElementsForType_: function( 77 label, object, indent, depth, maxDepth, suffix) { 78 if (depth > maxDepth) { 79 this.appendSimpleText_( 80 label, indent, '<recursion limit reached>', suffix); 81 return; 82 } 83 84 if (object === undefined) { 85 this.appendSimpleText_(label, indent, 'undefined', suffix); 86 return; 87 } 88 89 if (object === null) { 90 this.appendSimpleText_(label, indent, 'null', suffix); 91 return; 92 } 93 94 if (!(object instanceof Object)) { 95 var type = typeof object; 96 if (type == 'string') { 97 var objectReplaced = false; 98 if ((object[0] == '{' && object[object.length - 1] == '}') || 99 (object[0] == '[' && object[object.length - 1] == ']')) { 100 try { 101 object = JSON.parse(object); 102 objectReplaced = true; 103 } catch (e) { 104 } 105 } 106 if (!objectReplaced) { 107 if (object.indexOf('\n') !== -1) { 108 var lines = object.split('\n'); 109 lines.forEach(function(line, i) { 110 var text, ioff, ll, ss; 111 if (i == 0) { 112 text = '"' + line; 113 ioff = 0; 114 ll = label; 115 ss = ''; 116 } else if (i < lines.length - 1) { 117 text = line; 118 ioff = 1; 119 ll = ''; 120 ss = ''; 121 } else { 122 text = line + '"'; 123 ioff = 1; 124 ll = ''; 125 ss = suffix; 126 } 127 128 var el = this.appendSimpleText_( 129 ll, indent + ioff * label.length + ioff, text, ss); 130 el.style.whiteSpace = 'pre'; 131 return el; 132 }, this); 133 return; 134 } else { 135 this.appendSimpleText_( 136 label, indent, '"' + object + '"', suffix); 137 return; 138 } 139 } 140 else { 141 /* Fall through to the flow below */ 142 } 143 } else { 144 return this.appendSimpleText_(label, indent, object, suffix); 145 } 146 } 147 148 if (object instanceof tr.model.ObjectSnapshot) { 149 var link = document.createElement('tr-ui-a-analysis-link'); 150 link.selection = new tr.model.EventSet(object); 151 this.appendElementWithLabel_(label, indent, link, suffix); 152 return; 153 } 154 155 if (object instanceof tr.model.ObjectInstance) { 156 var link = document.createElement('tr-ui-a-analysis-link'); 157 link.selection = new tr.model.EventSet(object); 158 this.appendElementWithLabel_(label, indent, link, suffix); 159 return; 160 } 161 162 if (object instanceof tr.b.Rect) { 163 this.appendSimpleText_(label, indent, object.toString(), suffix); 164 return; 165 } 166 167 if (object instanceof tr.v.ScalarNumeric) { 168 var el = this.ownerDocument.createElement('tr-v-ui-scalar-span'); 169 el.value = object; 170 this.appendElementWithLabel_(label, indent, el, suffix); 171 return; 172 } 173 174 if (object instanceof Array) { 175 this.appendElementsForArray_( 176 label, object, indent, depth, maxDepth, suffix); 177 return; 178 } 179 180 this.appendElementsForObject_( 181 label, object, indent, depth, maxDepth, suffix); 182 }, 183 184 appendElementsForArray_: function( 185 label, object, indent, depth, maxDepth, suffix) { 186 if (object.length == 0) { 187 this.appendSimpleText_(label, indent, '[]', suffix); 188 return; 189 } 190 191 if (isTable(object)) { 192 var table = document.createElement('tr-ui-b-table'); 193 var columns = []; 194 tr.b.iterItems(object[0], function(colName) { 195 columns.push({title: colName, value: function(row) { 196 return row[colName]; 197 }}); 198 }); 199 table.tableColumns = columns; 200 table.tableRows = object; 201 this.appendElementWithLabel_(label, indent, table, suffix); 202 table.rebuild(); 203 return; 204 } 205 206 this.appendElementsForType_( 207 label + '[', 208 object[0], 209 indent, depth + 1, maxDepth, 210 object.length > 1 ? ',' : ']' + suffix); 211 for (var i = 1; i < object.length; i++) { 212 this.appendElementsForType_( 213 '', 214 object[i], 215 indent + label.length + 1, depth + 1, maxDepth, 216 i < object.length - 1 ? ',' : ']' + suffix); 217 } 218 return; 219 }, 220 221 appendElementsForObject_: function( 222 label, object, indent, depth, maxDepth, suffix) { 223 var keys = tr.b.dictionaryKeys(object); 224 if (keys.length == 0) { 225 this.appendSimpleText_(label, indent, '{}', suffix); 226 return; 227 } 228 229 this.appendElementsForType_( 230 label + '{' + keys[0] + ': ', 231 object[keys[0]], 232 indent, depth, maxDepth, 233 keys.length > 1 ? ',' : '}' + suffix); 234 for (var i = 1; i < keys.length; i++) { 235 this.appendElementsForType_( 236 keys[i] + ': ', 237 object[keys[i]], 238 indent + label.length + 1, depth + 1, maxDepth, 239 i < keys.length - 1 ? ',' : '}' + suffix); 240 } 241 }, 242 243 appendElementWithLabel_: function(label, indent, dataElement, suffix) { 244 var row = document.createElement('div'); 245 246 var indentSpan = document.createElement('span'); 247 indentSpan.style.whiteSpace = 'pre'; 248 for (var i = 0; i < indent; i++) 249 indentSpan.textContent += ' '; 250 row.appendChild(indentSpan); 251 252 var labelSpan = document.createElement('span'); 253 labelSpan.textContent = label; 254 row.appendChild(labelSpan); 255 256 row.appendChild(dataElement); 257 var suffixSpan = document.createElement('span'); 258 suffixSpan.textContent = suffix; 259 row.appendChild(suffixSpan); 260 261 row.dataElement = dataElement; 262 this.$.content.appendChild(row); 263 }, 264 265 appendSimpleText_: function(label, indent, text, suffix) { 266 var el = this.ownerDocument.createElement('span'); 267 el.textContent = text; 268 this.appendElementWithLabel_(label, indent, el, suffix); 269 return el; 270 } 271 }); 272 </script> 273</polymer-element> 274 275<polymer-element name="tr-ui-a-generic-object-view-with-label" 276 is="HTMLUnknownElement"> 277 <template> 278 <style> 279 :host { 280 display: block; 281 } 282 </style> 283 </template> 284 285 <script> 286 'use strict'; 287 288 Polymer({ 289 ready: function() { 290 this.labelEl_ = document.createElement('div'); 291 this.genericObjectView_ = 292 document.createElement('tr-ui-a-generic-object-view'); 293 this.shadowRoot.appendChild(this.labelEl_); 294 this.shadowRoot.appendChild(this.genericObjectView_); 295 }, 296 297 get label() { 298 return this.labelEl_.textContent; 299 }, 300 301 set label(label) { 302 this.labelEl_.textContent = label; 303 }, 304 305 get object() { 306 return this.genericObjectView_.object; 307 }, 308 309 set object(object) { 310 this.genericObjectView_.object = object; 311 } 312 }); 313 </script> 314</polymer-element> 315