| <!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="/tracing/base/rect.html"> |
| <link rel="import" href="/tracing/base/utils.html"> |
| <link rel="import" href="/tracing/model/event_set.html"> |
| <link rel="import" href="/tracing/model/object_instance.html"> |
| <link rel="import" href="/tracing/model/object_snapshot.html"> |
| <link rel="import" href="/tracing/ui/analysis/analysis_link.html"> |
| <link rel="import" href="/tracing/ui/base/table.html"> |
| <link rel="import" href="/tracing/ui/base/ui.html"> |
| <link rel="import" href="/tracing/value/numeric.html"> |
| <link rel="import" href="/tracing/value/ui/scalar_span.html"> |
| |
| <dom-module id='tr-ui-a-generic-object-view'> |
| <template> |
| <style> |
| :host { |
| display: block; |
| font-family: monospace; |
| } |
| </style> |
| <div id="content"> |
| </div> |
| </template> |
| </dom-module> |
| <script> |
| 'use strict'; |
| |
| var URL_REGEX = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/; // eslint-disable-line max-len |
| |
| 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({ |
| is: 'tr-ui-a-generic-object-view', |
| |
| ready: function() { |
| this.object_ = undefined; |
| }, |
| |
| get object() { |
| return this.object_; |
| }, |
| |
| set object(object) { |
| this.object_ = object; |
| this.updateContents_(); |
| }, |
| |
| updateContents_: function() { |
| Polymer.dom(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 if (object.match(URL_REGEX)) { |
| var link = document.createElement('a'); |
| link.href = object; |
| link.textContent = object; |
| this.appendElementWithLabel_(label, indent, link, suffix); |
| 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 tr.model.ObjectSnapshot) { |
| var link = document.createElement('tr-ui-a-analysis-link'); |
| link.selection = new tr.model.EventSet(object); |
| this.appendElementWithLabel_(label, indent, link, suffix); |
| return; |
| } |
| |
| if (object instanceof tr.model.ObjectInstance) { |
| var link = document.createElement('tr-ui-a-analysis-link'); |
| link.selection = new tr.model.EventSet(object); |
| this.appendElementWithLabel_(label, indent, link, suffix); |
| return; |
| } |
| |
| if (object instanceof tr.b.Rect) { |
| this.appendSimpleText_(label, indent, object.toString(), suffix); |
| return; |
| } |
| |
| if (object instanceof tr.v.ScalarNumeric) { |
| var el = this.ownerDocument.createElement('tr-v-ui-scalar-span'); |
| el.value = object; |
| 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('tr-ui-b-table'); |
| var columns = []; |
| tr.b.iterItems(object[0], function(colName) { |
| var allStrings = true; |
| var allNumbers = true; |
| for (var i = 0; i < object.length; ++i) { |
| if (typeof(object[i][colName]) !== 'string') |
| allStrings = false; |
| |
| if (typeof(object[i][colName]) !== 'number') |
| allNumbers = false; |
| |
| if (!allStrings && !allNumbers) |
| break; |
| } |
| |
| var column = {title: colName}; |
| column.value = function(row) { |
| return row[colName]; |
| }; |
| |
| if (allStrings) { |
| column.cmp = function(x, y) { |
| return x[colName].localeCompare(y[colName]); |
| }; |
| } else if (allNumbers) { |
| column.cmp = function(x, y) { |
| return x[colName] - y[colName]; |
| }; |
| } |
| columns.push(column); |
| }); |
| table.tableColumns = columns; |
| table.tableRows = object; |
| this.appendElementWithLabel_(label, indent, table, suffix); |
| table.rebuild(); |
| 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 = tr.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++) |
| Polymer.dom(indentSpan).textContent += ' '; |
| Polymer.dom(row).appendChild(indentSpan); |
| |
| var labelSpan = document.createElement('span'); |
| Polymer.dom(labelSpan).textContent = label; |
| Polymer.dom(row).appendChild(labelSpan); |
| |
| Polymer.dom(row).appendChild(dataElement); |
| var suffixSpan = document.createElement('span'); |
| Polymer.dom(suffixSpan).textContent = suffix; |
| Polymer.dom(row).appendChild(suffixSpan); |
| |
| row.dataElement = dataElement; |
| Polymer.dom(this.$.content).appendChild(row); |
| }, |
| |
| appendSimpleText_: function(label, indent, text, suffix) { |
| var el = this.ownerDocument.createElement('span'); |
| Polymer.dom(el).textContent = text; |
| this.appendElementWithLabel_(label, indent, el, suffix); |
| return el; |
| } |
| }); |
| </script> |
| |
| <dom-module id='tr-ui-a-generic-object-view-with-label'> |
| <template> |
| <style> |
| :host { |
| display: block; |
| } |
| </style> |
| </template> |
| </dom-module> |
| <script> |
| 'use strict'; |
| |
| Polymer({ |
| is: 'tr-ui-a-generic-object-view-with-label', |
| |
| ready: function() { |
| this.labelEl_ = document.createElement('div'); |
| this.genericObjectView_ = |
| document.createElement('tr-ui-a-generic-object-view'); |
| Polymer.dom(this.root).appendChild(this.labelEl_); |
| Polymer.dom(this.root).appendChild(this.genericObjectView_); |
| }, |
| |
| get label() { |
| return Polymer.dom(this.labelEl_).textContent; |
| }, |
| |
| set label(label) { |
| Polymer.dom(this.labelEl_).textContent = label; |
| }, |
| |
| get object() { |
| return this.genericObjectView_.object; |
| }, |
| |
| set object(object) { |
| this.genericObjectView_.object = object; |
| } |
| }); |
| </script> |