Home | History | Annotate | Download | only in about_sys
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 var localStrings;
      6 
      7 // Contents of lines that act as delimiters for multi-line values.
      8 var DELIM_START = '---------- START ----------';
      9 var DELIM_END = '---------- END ----------';
     10 
     11 // Limit file size to 10 MiB to prevent hanging on accidental upload.
     12 var MAX_FILE_SIZE = 10485760;
     13 
     14 function getValueDivForButton(button) {
     15   return $(button.id.substr(0, button.id.length - 4));
     16 }
     17 
     18 function getButtonForValueDiv(valueDiv) {
     19   return $(valueDiv.id + '-btn');
     20 }
     21 
     22 function handleDragOver(e) {
     23   e.dataTransfer.dropEffect = 'copy';
     24   e.preventDefault();
     25 }
     26 
     27 function handleDrop(e) {
     28   var file = e.dataTransfer.files[0];
     29   if (file) {
     30     e.preventDefault();
     31     importLog(file);
     32   }
     33 }
     34 
     35 function showError(fileName) {
     36   $('status').textContent = localStrings.getStringF('parseError', fileName);
     37 }
     38 
     39 /**
     40  * Toggles whether an item is collapsed or expanded.
     41  */
     42 function changeCollapsedStatus() {
     43   var valueDiv = getValueDivForButton(this);
     44   if (valueDiv.parentNode.className == 'number-collapsed') {
     45     valueDiv.parentNode.className = 'number-expanded';
     46     this.textContent = localStrings.getString('collapseBtn');
     47   } else {
     48     valueDiv.parentNode.className = 'number-collapsed';
     49     this.textContent = localStrings.getString('expandBtn');
     50   }
     51 }
     52 
     53 /**
     54  * Collapses all log items.
     55  */
     56 function collapseAll() {
     57   var valueDivs = document.getElementsByClassName('stat-value');
     58   for (var i = 0; i < valueDivs.length; i++) {
     59     var button = getButtonForValueDiv(valueDivs[i]);
     60     if (button && button.className != 'button-hidden') {
     61       button.textContent = localStrings.getString('expandBtn');
     62       valueDivs[i].parentNode.className = 'number-collapsed';
     63     }
     64   }
     65 }
     66 
     67 /**
     68  * Expands all log items.
     69  */
     70 function expandAll() {
     71   var valueDivs = document.getElementsByClassName('stat-value');
     72   for (var i = 0; i < valueDivs.length; i++) {
     73     var button = getButtonForValueDiv(valueDivs[i]);
     74     if (button && button.className != 'button-hidden') {
     75       button.textContent = localStrings.getString('collapseBtn');
     76       valueDivs[i].parentNode.className = 'number-expanded';
     77     }
     78   }
     79 }
     80 
     81 /**
     82  * Collapse only those log items with multi-line values.
     83  */
     84 function collapseMultiLineStrings() {
     85   var valueDivs = document.getElementsByClassName('stat-value');
     86   var nameDivs = document.getElementsByClassName('stat-name');
     87   for (var i = 0; i < valueDivs.length; i++) {
     88     var button = getButtonForValueDiv(valueDivs[i]);
     89     button.onclick = changeCollapsedStatus;
     90     if (valueDivs[i].scrollHeight > (nameDivs[i].scrollHeight * 2)) {
     91       button.className = '';
     92       button.textContent = localStrings.getString('expandBtn');
     93       valueDivs[i].parentNode.className = 'number-collapsed';
     94     } else {
     95       button.className = 'button-hidden';
     96       valueDivs[i].parentNode.className = 'number';
     97     }
     98   }
     99 }
    100 
    101 /**
    102  * Read in a log asynchronously, calling parseSystemLog if successful.
    103  * @param {File} file The file to read.
    104  */
    105 function importLog(file) {
    106   if (file && file.size <= MAX_FILE_SIZE) {
    107     var reader = new FileReader();
    108     reader.onload = function() {
    109       if (parseSystemLog(this.result)) {
    110         // Reset table title and status
    111         $('tableTitle').textContent =
    112               localStrings.getStringF('logFileTableTitle', file.name);
    113         $('status').textContent = '';
    114       } else {
    115         showError(file.name);
    116       }
    117     };
    118     reader.readAsText(file);
    119   } else if (file) {
    120     showError(file.name);
    121   }
    122 }
    123 
    124 /**
    125  * Convert text-based log into list of name-value pairs.
    126  * @param {string} text The raw text of a log.
    127  * @return {boolean} True if the log was parsed successfully.
    128  */
    129 function parseSystemLog(text) {
    130   var details = [];
    131   var lines = text.split('\n');
    132   for (var i = 0, len = lines.length; i < len; i++) {
    133     // Skip empty lines.
    134     if (!lines[i])
    135       continue;
    136 
    137     var delimiter = lines[i].indexOf('=');
    138     if (delimiter <= 0) {
    139       if (i == lines.length - 1)
    140          break;
    141       // If '=' is missing here, format is wrong.
    142       return false;
    143     }
    144 
    145     var name = lines[i].substring(0, delimiter);
    146     var value = '';
    147     // Set value if non-empty
    148     if (lines[i].length > delimiter + 1)
    149       value = lines[i].substring(delimiter + 1);
    150 
    151     // Delimiters are based on kMultilineIndicatorString, kMultilineStartString,
    152     // and kMultilineEndString in components/feedback/feedback_data.cc.
    153     // If these change, we should check for both the old and new versions.
    154     if (value == '<multiline>') {
    155       // Skip start delimiter.
    156       if (i == len - 1 ||
    157           lines[++i].indexOf(DELIM_START) == -1)
    158         return false;
    159 
    160       ++i;
    161       value = '';
    162       // Append lines between start and end delimiters.
    163       while (i < len && lines[i] != DELIM_END)
    164         value += lines[i++] + '\n';
    165 
    166       // Remove trailing newline.
    167       if (value)
    168         value = value.substr(0, value.length - 1);
    169     }
    170     details.push({'statName': name, 'statValue': value});
    171   }
    172 
    173   templateData['details'] = details;
    174   i18nTemplate.process(document, templateData);
    175   jstProcess(new JsEvalContext(templateData), $('t'));
    176 
    177   collapseMultiLineStrings();
    178   return true;
    179 }
    180 
    181 document.addEventListener('DOMContentLoaded', function() {
    182   localStrings = new LocalStrings();
    183 
    184   $('collapseAll').onclick = collapseAll;
    185   $('expandAll').onclick = expandAll;
    186 
    187   var tp = $('t');
    188   tp.addEventListener('dragover', handleDragOver, false);
    189   tp.addEventListener('drop', handleDrop, false);
    190 
    191   collapseMultiLineStrings();
    192 });
    193