mirror of
https://github.com/nasa/openmct.git
synced 2025-01-18 18:57:01 +00:00
[Table] #798 Simplified markup, moved styles to external stylesheet
This commit is contained in:
parent
c591ade479
commit
23a8c305c1
@ -161,6 +161,12 @@ define([
|
||||
"key": "table-options-edit",
|
||||
"templateUrl": "templates/table-options-edit.html"
|
||||
}
|
||||
],
|
||||
"stylesheets": [
|
||||
{
|
||||
"stylesheetUrl": "css/table.css",
|
||||
"priority": "mandatory"
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
50
platform/features/table/res/sass/table.scss
Normal file
50
platform/features/table/res/sass/table.scss
Normal file
@ -0,0 +1,50 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
.sizing-table {
|
||||
min-width: 100%;
|
||||
z-index: -1;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
|
||||
//Add some padding to allow for decorations such as limits indicator
|
||||
td {
|
||||
padding-right: 15px;
|
||||
padding-left: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
.mct-table {
|
||||
table-layout: fixed;
|
||||
th {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
tbody {
|
||||
tr {
|
||||
position: absolute;
|
||||
}
|
||||
td {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +1,25 @@
|
||||
<div class="l-view-section scrolling"
|
||||
ng-style="overrideRowPositioning ?
|
||||
{'overflow': 'auto'} :
|
||||
{'overflow': 'scroll'}"
|
||||
>
|
||||
<table class="filterable"
|
||||
ng-style="overrideRowPositioning && {
|
||||
<div class="l-view-section scrolling" style="overflow: auto;">
|
||||
<table class="sizing-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td ng-repeat="header in displayHeaders">{{header}}</td>
|
||||
</tr>
|
||||
<tr><td ng-repeat="header in displayHeaders" >
|
||||
{{sizingRow[header].text}}
|
||||
</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="filterable mct-table"
|
||||
ng-style="{
|
||||
height: totalHeight + 'px',
|
||||
'table-layout': overrideRowPositioning ? 'fixed' : 'auto',
|
||||
'max-width': totalWidth
|
||||
}">
|
||||
}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th ng-repeat="header in displayHeaders"
|
||||
ng-style="overrideRowPositioning && {
|
||||
ng-style="{
|
||||
width: columnWidths[$index] + 'px',
|
||||
'max-width': columnWidths[$index] + 'px',
|
||||
overflow: 'none',
|
||||
'box-sizing': 'border-box'
|
||||
}"
|
||||
ng-class="[
|
||||
enableSort ? 'sortable' : '',
|
||||
@ -29,11 +32,9 @@
|
||||
</tr>
|
||||
<tr ng-if="enableFilter" class="s-filters">
|
||||
<th ng-repeat="header in displayHeaders"
|
||||
ng-style="overrideRowPositioning && {
|
||||
ng-style="{
|
||||
width: columnWidths[$index] + 'px',
|
||||
'max-width': columnWidths[$index] + 'px',
|
||||
overflow: 'none',
|
||||
'box-sizing': 'border-box'
|
||||
}">
|
||||
<input type="text"
|
||||
ng-model="filters[header]"/>
|
||||
@ -41,21 +42,15 @@
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody ng-style="overrideRowPositioning ? '' : {
|
||||
'opacity': '0.0'
|
||||
}">
|
||||
<tbody>
|
||||
<tr ng-repeat="visibleRow in visibleRows track by visibleRow.rowIndex"
|
||||
ng-style="overrideRowPositioning && {
|
||||
position: 'absolute',
|
||||
ng-style="{
|
||||
top: visibleRow.offsetY + 'px',
|
||||
}">
|
||||
<td ng-repeat="header in displayHeaders"
|
||||
ng-style="overrideRowPositioning && {
|
||||
ng-style=" {
|
||||
width: columnWidths[$index] + 'px',
|
||||
'white-space': 'nowrap',
|
||||
'max-width': columnWidths[$index] + 'px',
|
||||
overflow: 'hidden',
|
||||
'box-sizing': 'border-box'
|
||||
}"
|
||||
class="{{visibleRow.contents[header].cssClass}}">
|
||||
{{ visibleRow.contents[header].text }}
|
||||
|
@ -23,10 +23,13 @@ define(
|
||||
this.maxDisplayRows = 50;
|
||||
|
||||
this.scrollable = element.find('div');
|
||||
this.thead = element.find('thead');
|
||||
this.tbody = element.find('tbody');
|
||||
this.$scope.sizingRow = {};
|
||||
|
||||
this.scrollable.on('scroll', this.onScroll.bind(this));
|
||||
|
||||
$scope.visibleRows = [];
|
||||
$scope.overrideRowPositioning = false;
|
||||
|
||||
/**
|
||||
* Set default values for optional parameters on a given scope
|
||||
@ -100,14 +103,31 @@ define(
|
||||
* @private
|
||||
*/
|
||||
MCTTableController.prototype.newRow = function (event, rowIndex) {
|
||||
var row = this.$scope.rows[rowIndex];
|
||||
//Add row to the filtered, sorted list of all rows
|
||||
if (this.filterRows([row]).length > 0) {
|
||||
this.insertSorted(this.$scope.displayRows, row);
|
||||
var self = this,
|
||||
row = this.$scope.rows[rowIndex],
|
||||
largestRow;
|
||||
|
||||
function sizeAndScroll () {
|
||||
self.setElementSizes();
|
||||
self.scrollToBottom();
|
||||
}
|
||||
|
||||
this.$timeout(this.setElementSizes.bind(this))
|
||||
.then(this.scrollToBottom.bind(this));
|
||||
//Does the row pass the current filter?
|
||||
if (this.filterRows([row]).length === 1) {
|
||||
this.insertSorted(this.$scope.displayRows, row);
|
||||
|
||||
//Calculate largest row
|
||||
largestRow = this.buildLargestRow([this.$scope.sizingRow, row]);
|
||||
|
||||
// Has it changed? If so, set the the 'sizing' row which
|
||||
// determines column widths
|
||||
if (JSON.stringify(largestRow) !== JSON.stringify(this.$scope.sizingRow)){
|
||||
this.$scope.sizingRow = largestRow;
|
||||
this.$timeout(sizeAndScroll);
|
||||
} else {
|
||||
sizeAndScroll();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -249,13 +269,12 @@ define(
|
||||
* for individual rows.
|
||||
*/
|
||||
MCTTableController.prototype.setElementSizes = function () {
|
||||
var self = this,
|
||||
thead = this.element.find('thead'),
|
||||
tbody = this.element.find('tbody'),
|
||||
var thead = this.thead,
|
||||
tbody = this.tbody,
|
||||
firstRow = tbody.find('tr'),
|
||||
column = firstRow.find('td'),
|
||||
headerHeight = thead.prop('offsetHeight'),
|
||||
rowHeight = 20,
|
||||
rowHeight = firstRow.prop('offsetHeight'),
|
||||
columnWidth,
|
||||
tableWidth = 0,
|
||||
overallHeight = headerHeight + (rowHeight *
|
||||
@ -279,8 +298,6 @@ define(
|
||||
} else {
|
||||
this.$scope.totalWidth = 'none';
|
||||
}
|
||||
|
||||
this.$scope.overrideRowPositioning = true;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -400,43 +417,32 @@ define(
|
||||
* pre-calculate optimal column sizes without having to render
|
||||
* every row.
|
||||
*/
|
||||
MCTTableController.prototype.findLargestRow = function (rows) {
|
||||
var largestRow = rows.reduce(function (largestRow, row) {
|
||||
MCTTableController.prototype.buildLargestRow = function (rows) {
|
||||
var largestRow = rows.reduce(function (prevLargest, row) {
|
||||
Object.keys(row).forEach(function (key) {
|
||||
var currentColumn = row[key].text,
|
||||
var currentColumn,
|
||||
currentColumnLength,
|
||||
largestColumn,
|
||||
largestColumnLength;
|
||||
if (!row[key]){
|
||||
//do nothing, no value for this column;
|
||||
} else {
|
||||
currentColumn = (row[key]).text;
|
||||
currentColumnLength =
|
||||
(currentColumn && currentColumn.length) ?
|
||||
currentColumn.length :
|
||||
currentColumn,
|
||||
largestColumn = largestRow[key].text,
|
||||
largestColumnLength =
|
||||
(largestColumn && largestColumn.length) ?
|
||||
largestColumn.length :
|
||||
largestColumn;
|
||||
currentColumn;
|
||||
largestColumn = prevLargest[key] ? prevLargest[key].text : "";
|
||||
largestColumnLength = largestColumn.length;
|
||||
|
||||
if (currentColumnLength > largestColumnLength) {
|
||||
largestRow[key] = JSON.parse(JSON.stringify(row[key]));
|
||||
if (currentColumnLength > largestColumnLength) {
|
||||
prevLargest[key] = JSON.parse(JSON.stringify(row[key]));
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
return largestRow;
|
||||
return prevLargest;
|
||||
}, JSON.parse(JSON.stringify(rows[0] || {})));
|
||||
|
||||
largestRow = JSON.parse(JSON.stringify(largestRow));
|
||||
|
||||
// Pad with characters to accomodate variable-width fonts,
|
||||
// and remove characters that would allow word-wrapping.
|
||||
Object.keys(largestRow).forEach(function (key) {
|
||||
var padCharacters,
|
||||
i;
|
||||
|
||||
largestRow[key].text = String(largestRow[key].text);
|
||||
padCharacters = largestRow[key].text.length / 10;
|
||||
for (i = 0; i < padCharacters; i++) {
|
||||
largestRow[key].text = largestRow[key].text + 'W';
|
||||
}
|
||||
largestRow[key].text = largestRow[key].text
|
||||
.replace(/[ \-_]/g, 'W');
|
||||
});
|
||||
return largestRow;
|
||||
};
|
||||
|
||||
@ -447,20 +453,13 @@ define(
|
||||
* @private
|
||||
*/
|
||||
MCTTableController.prototype.resize = function (){
|
||||
var largestRow = this.findLargestRow(this.$scope.displayRows),
|
||||
self = this;
|
||||
this.$scope.visibleRows = [
|
||||
{
|
||||
rowIndex: 0,
|
||||
offsetY: undefined,
|
||||
contents: largestRow
|
||||
}
|
||||
];
|
||||
var self = this;
|
||||
|
||||
this.$scope.sizingRow = this.buildLargestRow(this.$scope.displayRows);
|
||||
|
||||
//Wait a timeout to allow digest of previous change to visible
|
||||
// rows to happen.
|
||||
this.$timeout(function () {
|
||||
//Remove temporary padding row used for setting column widths
|
||||
self.$scope.visibleRows = [];
|
||||
self.setElementSizes();
|
||||
});
|
||||
@ -489,8 +488,6 @@ define(
|
||||
//Reset visible rows because new row data available.
|
||||
this.$scope.visibleRows = [];
|
||||
|
||||
this.$scope.overrideRowPositioning = false;
|
||||
|
||||
//Nothing to show because no columns visible
|
||||
if (!this.$scope.displayHeaders) {
|
||||
return;
|
||||
|
@ -58,15 +58,18 @@ define(
|
||||
|
||||
mockElement = jasmine.createSpyObj('element', [
|
||||
'find',
|
||||
'prop',
|
||||
'on'
|
||||
]);
|
||||
mockElement.find.andReturn(mockElement);
|
||||
mockElement.prop.andReturn(0);
|
||||
|
||||
mockScope.displayHeaders = true;
|
||||
mockTimeout = jasmine.createSpy('$timeout');
|
||||
mockTimeout.andReturn(promise(undefined));
|
||||
|
||||
controller = new MCTTableController(mockScope, mockTimeout, mockElement);
|
||||
spyOn(controller, 'setVisibleRows');
|
||||
});
|
||||
|
||||
it('Reacts to changes to filters, headers, and rows', function() {
|
||||
@ -138,8 +141,6 @@ define(
|
||||
var removeRowFunc = mockScope.$on.calls[mockScope.$on.calls.length-1].args[1];
|
||||
controller.updateRows(testRows);
|
||||
expect(mockScope.displayRows.length).toBe(3);
|
||||
spyOn(controller, 'setVisibleRows');
|
||||
//controller.setVisibleRows.andReturn(undefined);
|
||||
removeRowFunc(undefined, 2);
|
||||
expect(mockScope.displayRows.length).toBe(2);
|
||||
expect(controller.setVisibleRows).toHaveBeenCalled();
|
||||
@ -266,6 +267,25 @@ define(
|
||||
expect(mockScope.displayRows[4].col2.text).toEqual('ggg');
|
||||
});
|
||||
|
||||
it('Resizes columns if length of any columns in new' +
|
||||
' row exceeds corresponding existing column', function() {
|
||||
var row7 = {
|
||||
'col1': {'text': 'row6 col1'},
|
||||
'col2': {'text': 'some longer string'},
|
||||
'col3': {'text': 'row6 col3'}
|
||||
};
|
||||
|
||||
mockScope.sortColumn = undefined;
|
||||
mockScope.sortDirection = undefined;
|
||||
mockScope.filters = {};
|
||||
|
||||
mockScope.displayRows = testRows.slice(0);
|
||||
|
||||
mockScope.rows.push(row7);
|
||||
controller.newRow(undefined, mockScope.rows.length-1);
|
||||
expect(controller.$scope.sizingRow.col2).toEqual({text: 'some longer string'});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user