Home | History | Annotate | Download | only in net_internals
      1 // Copyright (c) 2012 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 SourceRow = (function() {
      6   'use strict';
      7 
      8   /**
      9    * A SourceRow represents the row corresponding to a single SourceEntry
     10    * displayed by the EventsView.
     11    *
     12    * @constructor
     13    */
     14   function SourceRow(parentView, sourceEntry) {
     15     this.parentView_ = parentView;
     16 
     17     this.sourceEntry_ = sourceEntry;
     18     this.isSelected_ = false;
     19     this.isMatchedByFilter_ = false;
     20 
     21     // Used to set CSS class for display.  Must only be modified by calling
     22     // corresponding set functions.
     23     this.isSelected_ = false;
     24     this.isMouseOver_ = false;
     25 
     26     // Mirror sourceEntry's values, so we only update the DOM when necessary.
     27     this.isError_ = sourceEntry.isError();
     28     this.isInactive_ = sourceEntry.isInactive();
     29     this.description_ = sourceEntry.getDescription();
     30 
     31     this.createRow_();
     32     this.onSourceUpdated();
     33   }
     34 
     35   SourceRow.prototype = {
     36     createRow_: function() {
     37       // Create a row.
     38       var tr = addNode(this.parentView_.tableBody_, 'tr');
     39       tr._id = this.getSourceId();
     40       tr.style.display = 'none';
     41       this.row_ = tr;
     42 
     43       var selectionCol = addNode(tr, 'td');
     44       var checkbox = addNode(selectionCol, 'input');
     45       checkbox.title = this.getSourceId();
     46       selectionCol.style.borderLeft = '0';
     47       checkbox.type = 'checkbox';
     48 
     49       var idCell = addNode(tr, 'td');
     50       idCell.style.textAlign = 'right';
     51 
     52       var typeCell = addNode(tr, 'td');
     53       var descriptionCell = addNode(tr, 'td');
     54       this.descriptionCell_ = descriptionCell;
     55 
     56       // Connect listeners.
     57       checkbox.onchange = this.onCheckboxToggled_.bind(this);
     58 
     59       var onclick = this.onClicked_.bind(this);
     60       idCell.onclick = onclick;
     61       typeCell.onclick = onclick;
     62       descriptionCell.onclick = onclick;
     63 
     64       tr.onmouseover = this.onMouseover_.bind(this);
     65       tr.onmouseout = this.onMouseout_.bind(this);
     66 
     67       // Set the cell values to match this source's data.
     68       if (this.getSourceId() >= 0) {
     69         addTextNode(idCell, this.getSourceId());
     70       } else {
     71         addTextNode(idCell, '-');
     72       }
     73       var sourceTypeString = this.sourceEntry_.getSourceTypeString();
     74       addTextNode(typeCell, sourceTypeString);
     75       this.updateDescription_();
     76 
     77       // Add a CSS classname specific to this source type (so CSS can specify
     78       // different stylings for different types).
     79       var sourceTypeClass = sourceTypeString.toLowerCase().replace(/_/g, '-');
     80       this.row_.classList.add('source-' + sourceTypeClass);
     81 
     82       this.updateClass_();
     83     },
     84 
     85     onSourceUpdated: function() {
     86       if (this.sourceEntry_.isInactive() != this.isInactive_ ||
     87           this.sourceEntry_.isError() != this.isError_) {
     88         this.updateClass_();
     89       }
     90 
     91       if (this.description_ != this.sourceEntry_.getDescription())
     92         this.updateDescription_();
     93 
     94       // Update filters.
     95       var matchesFilter = this.parentView_.currentFilter_(this.sourceEntry_);
     96       this.setIsMatchedByFilter(matchesFilter);
     97     },
     98 
     99     /**
    100      * Changes |row_|'s class based on currently set flags.  Clears any previous
    101      * class set by this method.  This method is needed so that some styles
    102      * override others.
    103      */
    104     updateClass_: function() {
    105       this.isInactive_ = this.sourceEntry_.isInactive();
    106       this.isError_ = this.sourceEntry_.isError();
    107 
    108       // Each element of this list contains a property of |this| and the
    109       // corresponding class name to set if that property is true.  Entries
    110       // earlier in the list take precedence.
    111       var propertyNames = [
    112         ['isSelected_', 'selected'],
    113         ['isMouseOver_', 'mouseover'],
    114         ['isError_', 'error'],
    115         ['isInactive_', 'inactive'],
    116       ];
    117 
    118       // Loop through |propertyNames| in order, checking if each property
    119       // is true.  For the first such property found, if any, add the
    120       // corresponding class to the SourceEntry's row.  Remove classes
    121       // that correspond to any other property.
    122       var noStyleSet = true;
    123       for (var i = 0; i < propertyNames.length; ++i) {
    124         var setStyle = noStyleSet && this[propertyNames[i][0]];
    125         if (setStyle) {
    126           this.row_.classList.add(propertyNames[i][1]);
    127           noStyleSet = false;
    128         } else {
    129           this.row_.classList.remove(propertyNames[i][1]);
    130         }
    131       }
    132     },
    133 
    134     getSourceEntry: function() {
    135       return this.sourceEntry_;
    136     },
    137 
    138     setIsMatchedByFilter: function(isMatchedByFilter) {
    139       if (this.isMatchedByFilter() == isMatchedByFilter)
    140         return;  // No change.
    141 
    142       this.isMatchedByFilter_ = isMatchedByFilter;
    143 
    144       this.setFilterStyles(isMatchedByFilter);
    145 
    146       if (isMatchedByFilter) {
    147         this.parentView_.incrementPostfilterCount(1);
    148       } else {
    149         this.parentView_.incrementPostfilterCount(-1);
    150         // If we are filtering an entry away, make sure it is no longer
    151         // part of the selection.
    152         this.setSelected(false);
    153       }
    154     },
    155 
    156     isMatchedByFilter: function() {
    157       return this.isMatchedByFilter_;
    158     },
    159 
    160     setFilterStyles: function(isMatchedByFilter) {
    161       // Hide rows which have been filtered away.
    162       if (isMatchedByFilter) {
    163         this.row_.style.display = '';
    164       } else {
    165         this.row_.style.display = 'none';
    166       }
    167     },
    168 
    169     isSelected: function() {
    170       return this.isSelected_;
    171     },
    172 
    173     setSelected: function(isSelected) {
    174       if (isSelected == this.isSelected())
    175         return;
    176 
    177       this.isSelected_ = isSelected;
    178 
    179       this.setSelectedStyles(isSelected);
    180       this.parentView_.modifySelectionArray(this.getSourceId(), isSelected);
    181       this.parentView_.onSelectionChanged();
    182     },
    183 
    184     setSelectedStyles: function(isSelected) {
    185       this.isSelected_ = isSelected;
    186       this.getSelectionCheckbox().checked = isSelected;
    187       this.updateClass_();
    188     },
    189 
    190     setMouseoverStyle: function(isMouseOver) {
    191       this.isMouseOver_ = isMouseOver;
    192       this.updateClass_();
    193     },
    194 
    195     onClicked_: function() {
    196       this.parentView_.clearSelection();
    197       this.setSelected(true);
    198       if (this.isSelected())
    199         this.parentView_.scrollToSourceId(this.getSourceId());
    200     },
    201 
    202     onMouseover_: function() {
    203       this.setMouseoverStyle(true);
    204     },
    205 
    206     onMouseout_: function() {
    207       this.setMouseoverStyle(false);
    208     },
    209 
    210     updateDescription_: function() {
    211       this.description_ = this.sourceEntry_.getDescription();
    212       this.descriptionCell_.innerHTML = '';
    213       addTextNode(this.descriptionCell_, this.description_);
    214     },
    215 
    216     onCheckboxToggled_: function() {
    217       this.setSelected(this.getSelectionCheckbox().checked);
    218       if (this.isSelected())
    219         this.parentView_.scrollToSourceId(this.getSourceId());
    220     },
    221 
    222     getSelectionCheckbox: function() {
    223       return this.row_.childNodes[0].firstChild;
    224     },
    225 
    226     getSourceId: function() {
    227       return this.sourceEntry_.getSourceId();
    228     },
    229 
    230     /**
    231      * Returns source ID of the entry whose row is currently above this one's.
    232      * Returns null if no such node exists.
    233      */
    234     getPreviousNodeSourceId: function() {
    235       var prevNode = this.row_.previousSibling;
    236       if (prevNode == null)
    237         return null;
    238       return prevNode._id;
    239     },
    240 
    241     /**
    242      * Returns source ID of the entry whose row is currently below this one's.
    243      * Returns null if no such node exists.
    244      */
    245     getNextNodeSourceId: function() {
    246       var nextNode = this.row_.nextSibling;
    247       if (nextNode == null)
    248         return null;
    249       return nextNode._id;
    250     },
    251 
    252     /**
    253      * Moves current object's row before |entry|'s row.
    254      */
    255     moveBefore: function(entry) {
    256       this.row_.parentNode.insertBefore(this.row_, entry.row_);
    257     },
    258 
    259     /**
    260      * Moves current object's row after |entry|'s row.
    261      */
    262     moveAfter: function(entry) {
    263       this.row_.parentNode.insertBefore(this.row_, entry.row_.nextSibling);
    264     }
    265   };
    266 
    267   return SourceRow;
    268 })();
    269