blob: e6f4a8355b3b9ebb89ddfd23b4873e95e20dd707 [file] [log] [blame]
<!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>