| <!DOCTYPE html> |
| <!-- |
| Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| |
| <link rel="import" href="/core/analysis/analysis_link.html"> |
| <link rel="import" href="/base/time.html"> |
| <link rel="import" href="/base/utils.html"> |
| <link rel="import" href="/base/ui.html"> |
| |
| <polymer-element name="tv-c-analysis-generic-object-view" |
| is="HTMLUnknownElement"> |
| <template> |
| <style> |
| :host { |
| display: block; |
| font-family: monospace; |
| } |
| </style> |
| <div id="content"> |
| </div> |
| </template> |
| |
| <script> |
| 'use strict'; |
| |
| function isTable(object) { |
| if (!(object instanceof Array) || |
| (object.length < 2)) return false; |
| for (var colName in object[0]) { |
| if (typeof colName !== 'string') return false; |
| } |
| for (var i = 0; i < object.length; ++i) { |
| if (!(object[i] instanceof Object)) return false; |
| for (var colName in object[i]) { |
| if (i && (object[0][colName] === undefined)) return false; |
| var cellType = typeof object[i][colName]; |
| if (cellType !== 'string' && cellType != 'number') return false; |
| } |
| if (i) { |
| for (var colName in object[0]) { |
| if (object[i][colName] === undefined) return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| Polymer({ |
| ready: function() { |
| this.object_ = undefined; |
| }, |
| |
| get object() { |
| return this.object_; |
| }, |
| |
| set object(object) { |
| this.object_ = object; |
| this.updateContents_(); |
| }, |
| |
| updateContents_: function() { |
| this.$.content.textContent = ''; |
| this.appendElementsForType_('', this.object_, 0, 0, 5, ''); |
| }, |
| |
| appendElementsForType_: function( |
| label, object, indent, depth, maxDepth, suffix) { |
| if (depth > maxDepth) { |
| this.appendSimpleText_( |
| label, indent, '<recursion limit reached>', suffix); |
| return; |
| } |
| |
| if (object === undefined) { |
| this.appendSimpleText_(label, indent, 'undefined', suffix); |
| return; |
| } |
| |
| if (object === null) { |
| this.appendSimpleText_(label, indent, 'null', suffix); |
| return; |
| } |
| |
| if (!(object instanceof Object)) { |
| var type = typeof object; |
| if (type == 'string') { |
| var objectReplaced = false; |
| if ((object[0] == '{' && object[object.length - 1] == '}') || |
| (object[0] == '[' && object[object.length - 1] == ']')) { |
| try { |
| object = JSON.parse(object); |
| objectReplaced = true; |
| } catch (e) { |
| } |
| } |
| if (!objectReplaced) { |
| if (object.indexOf('\n') !== -1) { |
| var lines = object.split('\n'); |
| lines.forEach(function(line, i) { |
| var text, ioff, ll, ss; |
| if (i == 0) { |
| text = '"' + line; |
| ioff = 0; |
| ll = label; |
| ss = ''; |
| } else if (i < lines.length - 1) { |
| text = line; |
| ioff = 1; |
| ll = ''; |
| ss = ''; |
| } else { |
| text = line + '"'; |
| ioff = 1; |
| ll = ''; |
| ss = suffix; |
| } |
| |
| var el = this.appendSimpleText_( |
| ll, indent + ioff * label.length + ioff, text, ss); |
| el.style.whiteSpace = 'pre'; |
| return el; |
| }, this); |
| return; |
| } else { |
| this.appendSimpleText_( |
| label, indent, '"' + object + '"', suffix); |
| return; |
| } |
| } |
| else { |
| /* Fall through to the flow below */ |
| } |
| } else { |
| return this.appendSimpleText_(label, indent, object, suffix); |
| } |
| } |
| |
| if (object instanceof tv.c.trace_model.ObjectSnapshot) { |
| var link = document.createElement('tv-c-analysis-link'); |
| link.selection = new tv.c.Selection(object); |
| this.appendElementWithLabel_(label, indent, link, suffix); |
| return; |
| } |
| |
| if (object instanceof tv.c.trace_model.ObjectInstance) { |
| var link = document.createElement('tv-c-analysis-link'); |
| link.selection = new tv.c.Selection(object); |
| this.appendElementWithLabel_(label, indent, link, suffix); |
| return; |
| } |
| |
| if (object instanceof tv.b.Rect) { |
| this.appendSimpleText_(label, indent, object.toString(), suffix); |
| return; |
| } |
| |
| if (object instanceof tv.b.TimeDuration) { |
| var el = this.ownerDocument.createElement('tv-c-a-time-span'); |
| el.duration = object.duration; |
| this.appendElementWithLabel_(label, indent, el, suffix); |
| return; |
| } |
| |
| if (object instanceof tv.b.TimeStamp) { |
| var el = this.ownerDocument.createElement('tv-c-a-time-stamp'); |
| el.timestamp = object.timestamp; |
| this.appendElementWithLabel_(label, indent, el, suffix); |
| return; |
| } |
| |
| if (object instanceof Array) { |
| this.appendElementsForArray_( |
| label, object, indent, depth, maxDepth, suffix); |
| return; |
| } |
| |
| this.appendElementsForObject_( |
| label, object, indent, depth, maxDepth, suffix); |
| }, |
| |
| appendElementsForArray_: function( |
| label, object, indent, depth, maxDepth, suffix) { |
| if (object.length == 0) { |
| this.appendSimpleText_(label, indent, '[]', suffix); |
| return; |
| } |
| |
| if (isTable(object)) { |
| var table = document.createElement('table'); |
| var tr = document.createElement('tr'); |
| table.appendChild(tr); |
| var columns = []; |
| for (var colName in object[0]) { |
| columns.push(colName); |
| var th = document.createElement('th'); |
| th.textContent = colName; |
| tr.appendChild(th); |
| } |
| object.forEach(function(row) { |
| var tr = document.createElement('tr'); |
| table.appendChild(tr); |
| columns.forEach(function(colName) { |
| var cell = row[colName]; |
| var td = document.createElement('td'); |
| td.textContent = cell; |
| td.style.textAlign = isNaN(parseFloat(cell)) ? 'left' : 'right'; |
| tr.appendChild(td); |
| }); |
| }); |
| this.appendElementWithLabel_(label, indent, table, suffix); |
| return; |
| } |
| |
| this.appendElementsForType_( |
| label + '[', |
| object[0], |
| indent, depth + 1, maxDepth, |
| object.length > 1 ? ',' : ']' + suffix); |
| for (var i = 1; i < object.length; i++) { |
| this.appendElementsForType_( |
| '', |
| object[i], |
| indent + label.length + 1, depth + 1, maxDepth, |
| i < object.length - 1 ? ',' : ']' + suffix); |
| } |
| return; |
| }, |
| |
| appendElementsForObject_: function( |
| label, object, indent, depth, maxDepth, suffix) { |
| var keys = tv.b.dictionaryKeys(object); |
| if (keys.length == 0) { |
| this.appendSimpleText_(label, indent, '{}', suffix); |
| return; |
| } |
| |
| this.appendElementsForType_( |
| label + '{' + keys[0] + ': ', |
| object[keys[0]], |
| indent, depth, maxDepth, |
| keys.length > 1 ? ',' : '}' + suffix); |
| for (var i = 1; i < keys.length; i++) { |
| this.appendElementsForType_( |
| keys[i] + ': ', |
| object[keys[i]], |
| indent + label.length + 1, depth + 1, maxDepth, |
| i < keys.length - 1 ? ',' : '}' + suffix); |
| } |
| }, |
| |
| appendElementWithLabel_: function(label, indent, dataElement, suffix) { |
| var row = document.createElement('div'); |
| |
| var indentSpan = document.createElement('span'); |
| indentSpan.style.whiteSpace = 'pre'; |
| for (var i = 0; i < indent; i++) |
| indentSpan.textContent += ' '; |
| row.appendChild(indentSpan); |
| |
| var labelSpan = document.createElement('span'); |
| labelSpan.textContent = label; |
| row.appendChild(labelSpan); |
| |
| row.appendChild(dataElement); |
| var suffixSpan = document.createElement('span'); |
| suffixSpan.textContent = suffix; |
| row.appendChild(suffixSpan); |
| |
| row.dataElement = dataElement; |
| this.$.content.appendChild(row); |
| }, |
| |
| appendSimpleText_: function(label, indent, text, suffix) { |
| var el = this.ownerDocument.createElement('span'); |
| el.textContent = text; |
| this.appendElementWithLabel_(label, indent, el, suffix); |
| return el; |
| } |
| }); |
| </script> |
| </polymer-element> |
| |
| <polymer-element name="tv-c-analysis-generic-object-view-with-label" |
| is="HTMLUnknownElement"> |
| <template> |
| <style> |
| :host { |
| display: block; |
| } |
| </style> |
| </template> |
| |
| <script> |
| 'use strict'; |
| |
| Polymer({ |
| ready: function() { |
| this.labelEl_ = document.createElement('div'); |
| this.genericObjectView_ = |
| document.createElement('tv-c-analysis-generic-object-view'); |
| this.shadowRoot.appendChild(this.labelEl_); |
| this.shadowRoot.appendChild(this.genericObjectView_); |
| }, |
| |
| get label() { |
| return this.labelEl_.textContent; |
| }, |
| |
| set label(label) { |
| this.labelEl_.textContent = label; |
| }, |
| |
| get object() { |
| return this.genericObjectView_.object; |
| }, |
| |
| set object(object) { |
| this.genericObjectView_.object = object; |
| } |
| }); |
| </script> |
| </polymer-element> |