[ADF-1092] independent styles for data-table (#2084)

* independent styles for datatable

- datatable (and all derived components) no longer depend on MDL css/js

* readme update
This commit is contained in:
Denys Vuika
2017-07-14 15:48:38 +01:00
committed by Eugenio Romano
parent fb4ed0209b
commit f715361f94
9 changed files with 312 additions and 200 deletions

View File

@@ -20,11 +20,11 @@
height:900px;
}
adf-document-list >>> adf-datatable .alfresco-datatable__row--selected .image-table-cell {
adf-document-list >>> adf-datatable tr.is-selected .image-table-cell {
position: relative;
}
adf-document-list >>> adf-datatable .alfresco-datatable__row--selected .image-table-cell::before {
adf-document-list >>> adf-datatable tr.is-selected .image-table-cell::before {
content: "\E876"; /* "done" */
font-family: "Material Icons";
font-size: 24px;

View File

@@ -0,0 +1,28 @@
@mixin no-select {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
@mixin typo-icon() {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
word-wrap: normal;
font-feature-settings: 'liga';
-webkit-font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased;
}
@mixin material-animation-default($duration:0.2s) {
transition-duration: $duration;
transition-timing-function: $animation-curve-default;
}

View File

@@ -1,3 +1,7 @@
@import 'colors';
$ADF: adf;
/* ANIMATION */
$animation-curve-fast-out-slow-in: cubic-bezier(0.4, 0, 0.2, 1) !default;
$animation-curve-default: $animation-curve-fast-out-slow-in !default;

View File

@@ -1,143 +0,0 @@
:host .full-width { width: 100%; }
:host .icon-cell {
font-size: 24px;
cursor: default;
}
:host .image-cell {
width: 24px;
height: 24px;
cursor: default;
}
:host .data-cell {
cursor: default;
}
:host .column-header {
cursor: pointer;
user-select: none;
-webkit-user-select: none; /* Chrome/Safari/Opera */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE/Edge */
-webkit-touch-callout: none; /* iOS Safari */
}
/* Empty folder */
:host .adf-no-content-container {
padding: 0 !important;
}
:host .adf-no-content-container > img {
width: 100%;
}
/* Loading folder */
:host .adf-loading-content-container {
padding: 0 !important;
}
:host .adf-loading-content-container > img {
width: 100%;
}
:host .ellipsis-cell .cell-container {
height: 1em;
}
/* visible content */
:host .ellipsis-cell .cell-value {
display: block;
position: absolute;
max-width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1em; /* for vertical align of text */
}
/* cell stretching content */
:host .ellipsis-cell > div:after {
content: attr(title);
overflow: hidden;
height: 0;
display: block;
}
/* Utils */
:host .non-selectable {
user-select: none;
-webkit-user-select: none; /* Chrome/Safari/Opera */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE/Edge */
-webkit-touch-callout: none; /* iOS Safari */
}
:host .sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0,0,0,0);
border: 0;
}
.hidden {
display: none;
}
/* small desktop */
@media all and (max-width: 1200px) {}
/* tablet */
@media all and (max-width: 1024px) {}
/* mobile phone */
@media all and (max-width: 768px) {
.desktop-only {
display: none;
}
}
@media (max-device-width: 768px){
.desktop-only {
display: none;
}
}
.mdl-data-table-fix-firefox {
border-collapse: unset;
border-spacing: 0;
}
.alfresco-datatable__row:focus {
outline-offset: -1px;
outline-width: 1px;
outline-color: rgb(68,138,255);
outline-style: solid;
}
.alfresco-datatable__row--selected,
.alfresco-datatable__row--selected:hover {
background-color: #e0e0e0;
}
.adf-upload__dragging > td {
border-top: 1px dashed rgb(68,138,255);
border-bottom: 1px dashed rgb(68,138,255);
}
.adf-upload__dragging > td:first-child {
border-left: 1px dashed rgb(68,138,255);
}
.adf-upload__dragging > td:last-child {
border-right: 1px dashed rgb(68,138,255);
}

View File

@@ -1,28 +1,28 @@
<table
*ngIf="data"
class="mdl-data-table mdl-js-data-table full-width mdl-data-table-fix-firefox">
class="full-width adf-data-table">
<thead>
<tr>
<!-- Actions (left) -->
<th *ngIf="actions && actionsPosition === 'left'" class="alfresco-datatable__actions-header">
<th *ngIf="actions && actionsPosition === 'left'" class="actions-column">
<span class="sr-only">Actions</span>
</th>
<!-- Columns -->
<th *ngIf="multiselect">
<md-checkbox [checked]="isSelectAllChecked" (change)="onSelectAllClick($event)"></md-checkbox>
</th>
<th class="mdl-data-table__cell--non-numeric non-selectable {{col.cssClass}}"
<th class="adf-data-table-cell--{{col.type || 'text'}} {{col.cssClass}}"
*ngFor="let col of data.getColumns()"
[class.sortable]="col.sortable"
[attr.data-automation-id]="'auto_id_' + col.key"
[class.column-header]="col.title"
[class.mdl-data-table__header--sorted-ascending]="isColumnSorted(col, 'asc')"
[class.mdl-data-table__header--sorted-descending]="isColumnSorted(col, 'desc')"
[class.adf-data-table__header--sorted-asc]="isColumnSorted(col, 'asc')"
[class.adf-data-table__header--sorted-desc]="isColumnSorted(col, 'desc')"
(click)="onColumnHeaderClick(col)">
<span *ngIf="col.srTitle" class="sr-only">{{col.srTitle}}</span>
<span *ngIf="col.title">{{col.title}}</span>
</th>
<!-- Actions (right) -->
<th *ngIf="actions && actionsPosition === 'right'" class="alfresco-datatable__actions-header">
<th *ngIf="actions && actionsPosition === 'right'" class="actions-column">
<span class="sr-only">Actions</span>
</th>
</tr>
@@ -31,14 +31,13 @@
<ng-container *ngIf="!loading">
<tr *ngFor="let row of data.getRows(); let idx = index" tabindex="0"
class="alfresco-datatable__row"
[class.alfresco-datatable__row--selected]="row.isSelected"
[class.is-selected]="row.isSelected"
[adf-upload]="allowDropFiles && rowAllowsDrop(row)" [adf-upload-data]="row"
[ngStyle]="rowStyle"
[ngClass]="rowStyleClass">
<!-- Actions (left) -->
<td *ngIf="actions && actionsPosition === 'left'" class="alfresco-datatable__actions-cell">
<td *ngIf="actions && actionsPosition === 'left'">
<button md-icon-button [mdMenuTriggerFor]="menu"
[attr.data-automation-id]="'action_menu_' + idx">
<md-icon>more_vert</md-icon>
@@ -58,24 +57,21 @@
<md-checkbox [(ngModel)]="row.isSelected"></md-checkbox>
</td>
<td *ngFor="let col of data.getColumns()"
class="mdl-data-table__cell--non-numeric non-selectable data-cell {{col.cssClass}}"
class="adf-data-table-cell adf-data-table-cell--{{col.type || 'text'}} {{col.cssClass}}"
(click)="onRowClick(row, $event)"
[context-menu]="getContextMenuActions(row, col)"
[context-menu-enabled]="contextMenu">
<div *ngIf="!col.template" class="cell-container">
<ng-container [ngSwitch]="col.type">
<div *ngSwitchCase="'image'" class="cell-value">
<i *ngIf="isIconValue(row, col)" class="material-icons icon-cell">{{asIconValue(row,
col)}}</i>
<i *ngIf="isIconValue(row, col)" class="material-icons">{{ asIconValue(row, col) }}</i>
<img *ngIf="!isIconValue(row, col)"
class="image-cell"
alt="{{ iconAltTextKey(data.getValue(row, col)) | translate }}"
src="{{ data.getValue(row, col) }}"
(error)="onImageLoadingError($event)">
</div>
<div *ngSwitchCase="'icon'" class="cell-value">
<img class="image-cell"
alt="{{ iconAltTextKey(data.getValue(row, col)) | translate }}"
<img alt="{{ iconAltTextKey(data.getValue(row, col)) | translate }}"
src="{{ data.getValue(row, col) }}"
(error)="onImageLoadingError($event)">
</div>
@@ -119,7 +115,7 @@
</tr>
<tr *ngIf="data.getRows().length === 0">
<td class="mdl-data-table__cell--non-numeric adf-no-content-container"
<td class="adf-no-content-container"
[attr.colspan]="1 + data.getColumns().length">
<ng-template *ngIf="noContentTemplate"
ngFor [ngForOf]="[data]"
@@ -130,7 +126,7 @@
</tr>
</ng-container>
<tr *ngIf="loading">
<td class="mdl-data-table__cell--non-numeric adf-loading-content-container"
<td class="adf-loading-content-container"
[attr.colspan]="1 + data.getColumns().length">
<ng-template *ngIf="loadingTemplate"
ngFor [ngForOf]="[data]"

View File

@@ -0,0 +1,257 @@
@import 'theming';
$data-table-font-size: 13px !default;
$data-table-header-font-size: 12px !default;
$data-table-header-sort-icon-size: 16px !default;
$data-table-header-color: rgba(#000, 0.54) !default;
$data-table-header-sorted-color: rgba(#000, 0.87) !default;
$data-table-header-sorted-icon-hover-color: rgba(#000, 0.26) !default;
$data-table-divider-color: rgba(#000, 0.12) !default;
$data-table-hover-color: #eeeeee !default;
$data-table-selection-color: #e0e0e0 !default;
$data-table-dividers: 1px solid $data-table-divider-color !default;
$data-table-row-height: 48px !default;
// $data-table-last-row-height: 56px !default;
// $data-table-header-height: 56px !default;
$data-table-column-spacing: 36px !default;
$data-table-column-padding: $data-table-column-spacing / 2;
// $data-table-card-header-height: 64px !default;
// $data-table-card-title-top: 20px !default;
$data-table-card-padding: 24px !default;
// $data-table-button-padding-right: 16px !default;
$data-table-cell-top: $data-table-card-padding / 2;
.adf-data-table {
position: relative;
border: $data-table-dividers;
border-collapse: collapse;
white-space: nowrap;
font-size: $data-table-font-size;
background-color: unquote("rgb(#{$alfresco-white})");
/* Firefox fixes */
border-collapse: unset;
border-spacing: 0;
thead {
padding-bottom: 3px;
}
tbody {
tr {
position: relative;
height: $data-table-row-height;
@include material-animation-default(0.28s);
transition-property: background-color;
&:hover {
background-color: $data-table-hover-color;
}
&.is-selected, &.is-selected:hover {
background-color: $data-table-selection-color;
}
&:focus {
outline-offset: -1px;
outline-width: 1px;
outline-color: rgb(68,138,255);
outline-style: solid;
}
}
}
td, th {
padding: 0 $data-table-column-padding 12px $data-table-column-padding;
text-align: right;
&:first-of-type {
padding-left: 24px;
}
&:last-of-type {
padding-right: 24px;
}
}
td {
position: relative;
vertical-align: middle;
height: $data-table-row-height;
border-top: $data-table-dividers;
border-bottom: $data-table-dividers;
padding-top: $data-table-cell-top;
box-sizing: border-box;
@include no-select;
cursor: default;
}
th {
@include no-select;
cursor: pointer;
position: relative;
vertical-align: bottom;
text-overflow: ellipsis;
font-size: 14px;
font-weight: bold;
line-height: 24px;
letter-spacing: 0;
height: $data-table-row-height;
font-size: $data-table-header-font-size;
color: $data-table-header-color;
padding-bottom: 8px;
box-sizing: border-box;
&.sortable {
@include no-select;
&:hover {
cursor: pointer;
}
}
&.adf-data-table__header--sorted-asc,
&.adf-data-table__header--sorted-desc {
color: $data-table-header-sorted-color;
&:before {
@include typo-icon;
font-size: $data-table-header-sort-icon-size;
content: "\e5d8";
margin-right: 5px;
vertical-align: sub;
}
&:hover {
cursor: pointer;
&:before {
color: $data-table-header-sorted-icon-hover-color;
}
}
}
&.adf-data-table__header--sorted-desc:before {
content: "\e5db";
}
}
.adf-data-table-cell {
text-align: left;
cursor: default;
&--text {
text-align: left;
}
&--number {
text-align: right;
}
&--image {
text-align: left;
img {
width: 24px;
height: 24px;
}
}
}
.full-width {
width: 100%;
}
/* Empty folder */
.adf-no-content-container {
padding: 0 !important;
& > img {
width: 100%;
}
}
/* Loading folder */
.adf-loading-content-container {
padding: 0 !important;
& > img {
width: 100%;
}
}
.ellipsis-cell {
.cell-container {
height: 1em;
}
/* visible content */
.cell-value {
display: block;
position: absolute;
max-width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
/* for vertical align of text */
line-height: 1em;
}
/* cell stretching content */
& > div:after {
content: attr(title);
overflow: hidden;
height: 0;
display: block;
}
}
}
/* Utils */
/* [Accessibility] For screen reader only */
:host .sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0,0,0,0);
border: 0;
}
.hidden {
display: none;
}
/* small desktop */
@media all and (max-width: 1200px) {}
/* tablet */
@media all and (max-width: 1024px) {}
/* mobile phone */
@media all and (max-width: 768px) {
.desktop-only {
display: none;
}
}
@media (max-device-width: 768px){
.desktop-only {
display: none;
}
}
.adf-upload__dragging {
& > td {
border-top: 1px dashed rgb(68,138,255);
border-bottom: 1px dashed rgb(68,138,255);
&:first-child {
border-left: 1px dashed rgb(68,138,255);
}
&:last-child {
border-right: 1px dashed rgb(68,138,255);
}
}
}

View File

@@ -57,9 +57,6 @@ describe('DataTable', () => {
});
beforeEach(() => {
// reset MDL handler
window['componentHandler'] = null;
eventMock = {
preventDefault: function () {
}
@@ -191,7 +188,7 @@ describe('DataTable', () => {
let headers = element.querySelectorAll('th');
expect(headers.length).toBe(4);
expect(headers[headers.length - 1].classList.contains('alfresco-datatable__actions-header')).toBeTruthy();
expect(headers[headers.length - 1].classList.contains('actions-column')).toBeTruthy();
});
it('should put actions menu to the left', () => {
@@ -206,7 +203,7 @@ describe('DataTable', () => {
let headers = element.querySelectorAll('th');
expect(headers.length).toBe(4);
expect(headers[0].classList.contains('alfresco-datatable__actions-header')).toBeTruthy();
expect(headers[0].classList.contains('actions-column')).toBeTruthy();
});
it('should initialize default adapter', () => {
@@ -414,19 +411,6 @@ describe('DataTable', () => {
});
it('should upgrade MDL components on view checked', () => {
let handler = jasmine.createSpyObj('componentHandler', ['upgradeAllRegistered']);
window['componentHandler'] = handler;
dataTable.ngAfterContentInit();
expect(handler.upgradeAllRegistered).toHaveBeenCalled();
});
it('should upgrade MDL components only when component handler present', () => {
expect(window['componentHandler']).toBeNull();
dataTable.ngAfterContentInit();
});
it('should invert "select all" status', () => {
expect(dataTable.isSelectAllChecked).toBeFalsy();
dataTable.onSelectAllClick(<MdCheckboxChange> { checked: true });

View File

@@ -16,7 +16,7 @@
*/
import {
AfterContentInit, AfterViewInit, Component, ContentChild, DoCheck, ElementRef, EventEmitter, Input,
AfterContentInit, Component, ContentChild, DoCheck, ElementRef, EventEmitter, Input,
IterableDiffers, OnChanges, Optional, Output, SimpleChange, SimpleChanges, TemplateRef
} from '@angular/core';
import { MdCheckboxChange } from '@angular/material';
@@ -31,10 +31,10 @@ declare var componentHandler;
@Component({
selector: 'adf-datatable, alfresco-datatable',
styleUrls: ['./datatable.component.css'],
styleUrls: ['./datatable.component.scss'],
templateUrl: './datatable.component.html'
})
export class DataTableComponent implements AfterContentInit, AfterViewInit, OnChanges, DoCheck {
export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck {
@ContentChild(DataColumnListComponent) columnList: DataColumnListComponent;
@@ -120,20 +120,6 @@ export class DataTableComponent implements AfterContentInit, AfterViewInit, OnCh
ngAfterContentInit() {
this.setTableSchema();
this.setupMaterialComponents();
}
ngAfterViewInit() {
this.setupMaterialComponents();
}
private setupMaterialComponents(): boolean {
// workaround for MDL issues with dynamic components
if (componentHandler) {
componentHandler.upgradeAllRegistered();
return true;
}
return false;
}
ngOnChanges(changes: SimpleChanges) {

View File

@@ -228,11 +228,11 @@ Let's start by assigning an "image-table-cell" class to the thumbnail column:
Now your application can define custom styles to change the content of the column based on some other conditions, like selection state:
```css
adf-document-list >>> adf-datatable .alfresco-datatable__row--selected .image-table-cell {
adf-document-list >>> adf-datatable tr.is-selected .image-table-cell {
position: relative;
}
adf-document-list >>> adf-datatable .alfresco-datatable__row--selected .image-table-cell::before {
adf-document-list >>> adf-datatable tr.is-selected .image-table-cell::before {
content: "\E876"; /* "done" */
font-family: "Material Icons";
font-size: 24px;