// Copyright 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.
var localStrings;
// Contents of lines that act as delimiters for multi-line values.
var DELIM_START = '---------- START ----------';
var DELIM_END = '---------- END ----------';
// Limit file size to 10 MiB to prevent hanging on accidental upload.
var MAX_FILE_SIZE = 10485760;
function getValueDivForButton(button) {
return $(button.id.substr(0, button.id.length - 4));
}
function getButtonForValueDiv(valueDiv) {
return $(valueDiv.id + '-btn');
}
function handleDragOver(e) {
e.dataTransfer.dropEffect = 'copy';
e.preventDefault();
}
function showError(fileName) {
$('status').textContent = localStrings.getStringF('parseError', fileName);
}
/**
* Toggles whether an item is collapsed or expanded.
*/
function changeCollapsedStatus() {
var valueDiv = getValueDivForButton(this);
if (valueDiv.parentNode.className == 'number-collapsed') {
valueDiv.parentNode.className = 'number-expanded';
this.textContent = localStrings.getString('collapseBtn');
} else {
valueDiv.parentNode.className = 'number-collapsed';
this.textContent = localStrings.getString('expandBtn');
}
}
/**
* Collapses all log items.
*/
function collapseAll() {
var valueDivs = document.getElementsByClassName('stat-value');
for (var i = 0; i < valueDivs.length; i++) {
var button = getButtonForValueDiv(valueDivs[i]);
if (button && button.className != 'button-hidden') {
button.textContent = localStrings.getString('expandBtn');
valueDivs[i].parentNode.className = 'number-collapsed';
}
}
}
/**
* Expands all log items.
*/
function expandAll() {
var valueDivs = document.getElementsByClassName('stat-value');
for (var i = 0; i < valueDivs.length; i++) {
var button = getButtonForValueDiv(valueDivs[i]);
if (button && button.className != 'button-hidden') {
button.textContent = localStrings.getString('collapseBtn');
valueDivs[i].parentNode.className = 'number-expanded';
}
}
}
/**
* Collapse only those log items with multi-line values.
*/
function collapseMultiLineStrings() {
var valueDivs = document.getElementsByClassName('stat-value');
for (var i = 0; i < valueDivs.length; i++) {
var button = getButtonForValueDiv(valueDivs[i]);
button.onclick = changeCollapsedStatus;
if (valueDivs[i].textContent.split('\n').length > 1) {
button.className = '';
button.textContent = localStrings.getString('expandBtn');
valueDivs[i].parentNode.className = 'number-collapsed';
} else {
button.className = 'button-hidden';
valueDivs[i].parentNode.className = 'number';
}
}
}
/**
* Read in a log asynchronously, calling parseSystemLog if successful.
* @param {Event} e The drop event from dropping a file dragged onto the page.
*/
function importLog(e) {
var file = e.dataTransfer.files[0];
if (file && file.size <= MAX_FILE_SIZE) {
var reader = new FileReader();
reader.onload = function() {
if (parseSystemLog(this.result)) {
// Reset table title and status
$('tableTitle').textContent =
localStrings.getStringF('logFileTableTitle', file.name);
$('status').textContent = '';
} else {
showError(file.name);
}
};
reader.readAsText(file);
} else if (file) {
showError(file.name);
}
e.preventDefault();
}
/**
* Convert text-based log into list of name-value pairs.
* @param {string} text The raw text of a log.
* @return {boolean} True if the log was parsed successfully.
*/
function parseSystemLog(text) {
var details = [];
var lines = text.split('\n');
for (var i = 0, len = lines.length; i < len; i++) {
// Skip empty lines.
if (!lines[i])
continue;
var delimiter = lines[i].indexOf('=');
if (delimiter <= 0) {
if (i == lines.length - 1)
break;
// If '=' is missing here, format is wrong.
return false;
}
var name = lines[i].substring(0, delimiter);
var value = '';
// Set value if non-empty
if (lines[i].length > delimiter + 1)
value = lines[i].substring(delimiter + 1);
// Delimiters are based on kMultilineIndicatorString, kMultilineStartString,
// and kMultilineEndString in chrome/browser/feedback/feedback_data.cc.
// If these change, we should check for both the old and new versions.
if (value == '<multiline>') {
// Skip start delimiter.
if (i == len - 1 ||
lines[++i].indexOf(DELIM_START) == -1)
return false;
++i;
value = '';
// Append lines between start and end delimiters.
while (i < len && lines[i] != DELIM_END)
value += lines[i++] + '\n';
// Remove trailing newline.
if (value)
value = value.substr(0, value.length - 1);
}
details.push({'statName': name, 'statValue': value});
}
templateData['details'] = details;
i18nTemplate.process(document, templateData);
jstProcess(new JsEvalContext(templateData), $('t'));
collapseMultiLineStrings();
return true;
}
document.addEventListener('DOMContentLoaded', function() {
localStrings = new LocalStrings();
$('collapseAll').onclick = collapseAll;
$('expandAll').onclick = expandAll;
var tp = $('t');
tp.addEventListener('dragover', handleDragOver, false);
tp.addEventListener('drop', importLog, false);
collapseMultiLineStrings();
});