blob: 137d70ae084680b2e574c7c52a13f2212b1fc963 [file] [log] [blame]
// Copyright (c) 2012 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 SourceRow = (function() {
'use strict';
/**
* A SourceRow represents the row corresponding to a single SourceEntry
* displayed by the EventsView.
*
* @constructor
*/
function SourceRow(parentView, sourceEntry) {
this.parentView_ = parentView;
this.sourceEntry_ = sourceEntry;
this.isSelected_ = false;
this.isMatchedByFilter_ = false;
// Used to set CSS class for display. Must only be modified by calling
// corresponding set functions.
this.isSelected_ = false;
this.isMouseOver_ = false;
// Mirror sourceEntry's values, so we only update the DOM when necessary.
this.isError_ = sourceEntry.isError();
this.isInactive_ = sourceEntry.isInactive();
this.description_ = sourceEntry.getDescription();
this.createRow_();
this.onSourceUpdated();
}
SourceRow.prototype = {
createRow_: function() {
// Create a row.
var tr = addNode(this.parentView_.tableBody_, 'tr');
tr._id = this.getSourceId();
tr.style.display = 'none';
this.row_ = tr;
var selectionCol = addNode(tr, 'td');
var checkbox = addNode(selectionCol, 'input');
checkbox.title = this.getSourceId();
selectionCol.style.borderLeft = '0';
checkbox.type = 'checkbox';
var idCell = addNode(tr, 'td');
idCell.style.textAlign = 'right';
var typeCell = addNode(tr, 'td');
var descriptionCell = addNode(tr, 'td');
this.descriptionCell_ = descriptionCell;
// Connect listeners.
checkbox.onchange = this.onCheckboxToggled_.bind(this);
var onclick = this.onClicked_.bind(this);
idCell.onclick = onclick;
typeCell.onclick = onclick;
descriptionCell.onclick = onclick;
tr.onmouseover = this.onMouseover_.bind(this);
tr.onmouseout = this.onMouseout_.bind(this);
// Set the cell values to match this source's data.
if (this.getSourceId() >= 0) {
addTextNode(idCell, this.getSourceId());
} else {
addTextNode(idCell, '-');
}
var sourceTypeString = this.sourceEntry_.getSourceTypeString();
addTextNode(typeCell, sourceTypeString);
this.updateDescription_();
// Add a CSS classname specific to this source type (so CSS can specify
// different stylings for different types).
var sourceTypeClass = sourceTypeString.toLowerCase().replace(/_/g, '-');
this.row_.classList.add('source-' + sourceTypeClass);
this.updateClass_();
},
onSourceUpdated: function() {
if (this.sourceEntry_.isInactive() != this.isInactive_ ||
this.sourceEntry_.isError() != this.isError_) {
this.updateClass_();
}
if (this.description_ != this.sourceEntry_.getDescription())
this.updateDescription_();
// Update filters.
var matchesFilter = this.parentView_.currentFilter_(this.sourceEntry_);
this.setIsMatchedByFilter(matchesFilter);
},
/**
* Changes |row_|'s class based on currently set flags. Clears any previous
* class set by this method. This method is needed so that some styles
* override others.
*/
updateClass_: function() {
this.isInactive_ = this.sourceEntry_.isInactive();
this.isError_ = this.sourceEntry_.isError();
// Each element of this list contains a property of |this| and the
// corresponding class name to set if that property is true. Entries
// earlier in the list take precedence.
var propertyNames = [
['isSelected_', 'selected'],
['isMouseOver_', 'mouseover'],
['isError_', 'error'],
['isInactive_', 'inactive'],
];
// Loop through |propertyNames| in order, checking if each property
// is true. For the first such property found, if any, add the
// corresponding class to the SourceEntry's row. Remove classes
// that correspond to any other property.
var noStyleSet = true;
for (var i = 0; i < propertyNames.length; ++i) {
var setStyle = noStyleSet && this[propertyNames[i][0]];
if (setStyle) {
this.row_.classList.add(propertyNames[i][1]);
noStyleSet = false;
} else {
this.row_.classList.remove(propertyNames[i][1]);
}
}
},
getSourceEntry: function() {
return this.sourceEntry_;
},
setIsMatchedByFilter: function(isMatchedByFilter) {
if (this.isMatchedByFilter() == isMatchedByFilter)
return; // No change.
this.isMatchedByFilter_ = isMatchedByFilter;
this.setFilterStyles(isMatchedByFilter);
if (isMatchedByFilter) {
this.parentView_.incrementPostfilterCount(1);
} else {
this.parentView_.incrementPostfilterCount(-1);
// If we are filtering an entry away, make sure it is no longer
// part of the selection.
this.setSelected(false);
}
},
isMatchedByFilter: function() {
return this.isMatchedByFilter_;
},
setFilterStyles: function(isMatchedByFilter) {
// Hide rows which have been filtered away.
if (isMatchedByFilter) {
this.row_.style.display = '';
} else {
this.row_.style.display = 'none';
}
},
isSelected: function() {
return this.isSelected_;
},
setSelected: function(isSelected) {
if (isSelected == this.isSelected())
return;
this.isSelected_ = isSelected;
this.setSelectedStyles(isSelected);
this.parentView_.modifySelectionArray(this.getSourceId(), isSelected);
this.parentView_.onSelectionChanged();
},
setSelectedStyles: function(isSelected) {
this.isSelected_ = isSelected;
this.getSelectionCheckbox().checked = isSelected;
this.updateClass_();
},
setMouseoverStyle: function(isMouseOver) {
this.isMouseOver_ = isMouseOver;
this.updateClass_();
},
onClicked_: function() {
this.parentView_.clearSelection();
this.setSelected(true);
if (this.isSelected())
this.parentView_.scrollToSourceId(this.getSourceId());
},
onMouseover_: function() {
this.setMouseoverStyle(true);
},
onMouseout_: function() {
this.setMouseoverStyle(false);
},
updateDescription_: function() {
this.description_ = this.sourceEntry_.getDescription();
this.descriptionCell_.innerHTML = '';
addTextNode(this.descriptionCell_, this.description_);
},
onCheckboxToggled_: function() {
this.setSelected(this.getSelectionCheckbox().checked);
if (this.isSelected())
this.parentView_.scrollToSourceId(this.getSourceId());
},
getSelectionCheckbox: function() {
return this.row_.childNodes[0].firstChild;
},
getSourceId: function() {
return this.sourceEntry_.getSourceId();
},
/**
* Returns source ID of the entry whose row is currently above this one's.
* Returns null if no such node exists.
*/
getPreviousNodeSourceId: function() {
var prevNode = this.row_.previousSibling;
if (prevNode == null)
return null;
return prevNode._id;
},
/**
* Returns source ID of the entry whose row is currently below this one's.
* Returns null if no such node exists.
*/
getNextNodeSourceId: function() {
var nextNode = this.row_.nextSibling;
if (nextNode == null)
return null;
return nextNode._id;
},
/**
* Moves current object's row before |entry|'s row.
*/
moveBefore: function(entry) {
this.row_.parentNode.insertBefore(this.row_, entry.row_);
},
/**
* Moves current object's row after |entry|'s row.
*/
moveAfter: function(entry) {
this.row_.parentNode.insertBefore(this.row_, entry.row_.nextSibling);
}
};
return SourceRow;
})();