Extract table
Problem on sortable
This commit is contained in:
@@ -1,37 +0,0 @@
|
||||
/* Thank to https://codyhouse.co/gem/back-to-top/ */
|
||||
|
||||
.btn-top {
|
||||
display: inline-block;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.05);
|
||||
/* image replacement properties */
|
||||
/*overflow: hidden;*/
|
||||
/*text-indent: 100%;*/
|
||||
/*white-space: nowrap;*/
|
||||
/*background: rgba(232, 98, 86, 0.8);*/
|
||||
/*background: #ff9000;*/
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity .3s 0s, visibility 0s .3s;
|
||||
-moz-transition: opacity .3s 0s, visibility 0s .3s;
|
||||
transition: opacity .3s 0s, visibility 0s .3s;
|
||||
}
|
||||
.btn-top.btn-top-is-visible, .no-touch .btn-top:hover {
|
||||
-webkit-transition: opacity .3s 0s, visibility 0s 0s;
|
||||
-moz-transition: opacity .3s 0s, visibility 0s 0s;
|
||||
transition: opacity .3s 0s, visibility 0s 0s;
|
||||
}
|
||||
.btn-top.btn-top-is-visible {
|
||||
/* the button becomes visible */
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.btn-sort {
|
||||
bottom: 20px;
|
||||
right: 70px;
|
||||
}
|
||||
|
||||
@@ -84,38 +84,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="table table-striped" (window:scroll)="onScroll($event)">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Name</th>
|
||||
<th>Artist</th>
|
||||
<th>Album</th>
|
||||
<th>Album Artist</th>
|
||||
<th>Play Count</th>
|
||||
<th>Genre</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let song of songs | sortBy : 'Track Number'">
|
||||
<td>{{song['Track Number'] ? (("0" + song['Track Number']).slice(-2)) : "--"}}</td>
|
||||
<td>{{song.Name}}</td>
|
||||
<td><a [routerLink]="['/artist', song.Artist]">{{song.Artist}}</a></td>
|
||||
<td><a [routerLink]="['/album', song.Album]">{{song.Album}}</a></td>
|
||||
<td>{{song['Album Artist']}}</td>
|
||||
<td>{{song['Play Count']}}</td>
|
||||
<td><a [routerLink]="['/genre', song.Genre]">{{song.Genre}}</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<app-song-table [songs]=songs (atBottom)=loadSongs()></app-song-table>
|
||||
|
||||
<button type="button" *ngIf="moreDataAvailable" class="btn btn-default" aria-label="More" (click)="loadSongs()">
|
||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> More...
|
||||
</button>
|
||||
|
||||
<!-- Go to Top Button-->
|
||||
<button type="button" class="btn btn-warning btn-top" [class.btn-top-is-visible]="atBottom"
|
||||
aria-label="Top" (click)="scrollTop()">
|
||||
<span class="glyphicon glyphicon-menu-up" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -16,8 +16,7 @@ export class AlbumComponent implements OnInit {
|
||||
albumName = '';
|
||||
songs: Array<Song> = [];
|
||||
album: Album = new Album(); // If album not found, will be replaced by 'undefined'
|
||||
moreDataAvailable = false;
|
||||
atBottom = false;
|
||||
moreDataAvailable = true;
|
||||
|
||||
constructor(
|
||||
private elsService: ElsService,
|
||||
@@ -35,6 +34,10 @@ export class AlbumComponent implements OnInit {
|
||||
}
|
||||
|
||||
loadSongs(): void {
|
||||
if (!this.moreDataAvailable) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.elsService.getAlbumSongs(this.albumName, this.songs.length).subscribe(
|
||||
data => {
|
||||
this.moreDataAvailable = data.length === ElsService.DEFAULT_SIZE;
|
||||
@@ -51,30 +54,4 @@ export class AlbumComponent implements OnInit {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
scrollTop(): void {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle scroll:
|
||||
* - load data if at bottom of screen (if needed)
|
||||
* - hide/show "go to top" button
|
||||
*
|
||||
* @param event scroll event
|
||||
*/
|
||||
onScroll(event: any) {
|
||||
if (this.moreDataAvailable &&
|
||||
(window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
|
||||
this.loadSongs();
|
||||
}
|
||||
|
||||
if (window.scrollY > window.innerHeight) {
|
||||
this.atBottom = true;
|
||||
}
|
||||
|
||||
if (window.scrollY === 0) {
|
||||
this.atBottom = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { DashboardComponent } from './dashboard.component';
|
||||
import { AlbumComponent } from './album/album.component';
|
||||
import { ArtistComponent } from './artist/artist.component';
|
||||
import { GenreComponent } from './genre/genre.component';
|
||||
import { SongTableComponent } from './song-table/song-table.component';
|
||||
|
||||
import { ElsService } from './els.service';
|
||||
|
||||
@@ -28,6 +29,7 @@ import { SortByPipe } from './sort-by.pipe';
|
||||
AlbumComponent,
|
||||
ArtistComponent,
|
||||
GenreComponent,
|
||||
SongTableComponent,
|
||||
ConvertMsPipe,
|
||||
ConvertMoreExactPipe,
|
||||
SortByPipe
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -85,64 +85,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="table table-striped" (window:scroll)="onScroll($event)">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Name</th>
|
||||
<th>Album</th>
|
||||
<th>Year</th>
|
||||
<th>Artist</th>
|
||||
<th>Album Artist</th>
|
||||
<th>Play Count</th>
|
||||
<th>Genre</th>
|
||||
<th>Bit Rate</th>
|
||||
<th>Rating</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let song of songs | sortBy : 'Year':'Album':'Track Number'">
|
||||
<td>{{song['Track Number'] ? (("0" + song['Track Number']).slice(-2)) : "--"}}</td>
|
||||
<td>{{song.Name}}</td>
|
||||
<td><a [routerLink]="['/album', song.Album]">{{song.Album}}</a></td>
|
||||
<td>{{song.Year}}</td>
|
||||
<td><a [routerLink]="['/artist', song.Artist]">{{song.Artist}}</a></td>
|
||||
<td>{{song['Album Artist'] ? song['Album Artist'] : "-" }}</td>
|
||||
<td>{{song['Play Count']}}</td>
|
||||
<td><a [routerLink]="['/genre', song.Genre]">{{song.Genre}}</a></td>
|
||||
<td [title]="song['Bit Rate']">
|
||||
<span [class]="'signal signal-' + roundBitRate(song['Bit Rate'])"></span>
|
||||
</td>
|
||||
<td *ngIf="!song['Rating Computed']" [title]="'Rating: ' + song.Rating" class="star">
|
||||
<span *ngIf="song.Rating >= 20" class="glyphicon glyphicon-star"></span>
|
||||
<span *ngIf="song.Rating >= 40" class="glyphicon glyphicon-star"></span>
|
||||
<span *ngIf="song.Rating >= 60" class="glyphicon glyphicon-star"></span>
|
||||
<span *ngIf="song.Rating >= 80" class="glyphicon glyphicon-star"></span>
|
||||
<span *ngIf="song.Rating >= 100" class="glyphicon glyphicon-star"></span>
|
||||
</td>
|
||||
<td *ngIf="song['Rating Computed']" [title]="'Computed Rating: ' + song.Rating" class="star">
|
||||
<span *ngIf="song.Rating >= 20" class="glyphicon glyphicon-star-empty"></span>
|
||||
<span *ngIf="song.Rating >= 40" class="glyphicon glyphicon-star-empty"></span>
|
||||
<span *ngIf="song.Rating >= 60" class="glyphicon glyphicon-star-empty"></span>
|
||||
<span *ngIf="song.Rating >= 80" class="glyphicon glyphicon-star-empty"></span>
|
||||
<span *ngIf="song.Rating >= 100" class="glyphicon glyphicon-star-empty"></span>
|
||||
</td>
|
||||
<td *ngIf="song.Loved" class="loved" ><span class="glyphicon glyphicon-heart heart"></span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<app-song-table [songs]=songs [sortable]=sortable (atBottom)=loadSongs()></app-song-table>
|
||||
|
||||
<button type="button" *ngIf="moreDataAvailable" class="btn btn-default" aria-label="More" (click)="loadSongs()">
|
||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> More...
|
||||
</button>
|
||||
|
||||
<!-- Go to Top Button-->
|
||||
<button type="button" class="btn btn-warning btn-top" [class.btn-top-is-visible]="atBottom"
|
||||
aria-label="Top" (click)="scrollTop()" title="Go back to Top!">
|
||||
<span class="glyphicon glyphicon-menu-up" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary btn-top btn-sort" [class.btn-top-is-visible]="sortable"
|
||||
aria-label="Top" (click)="sort()" title="Sort by Album & Track Number">
|
||||
<span class="glyphicon glyphicon-sort-by-attributes" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -19,8 +19,7 @@ export class ArtistComponent implements OnInit {
|
||||
songs: Array<Song> = [];
|
||||
artist: Artist = new Artist();
|
||||
// To activate button in interface var
|
||||
moreDataAvailable = false;
|
||||
atBottom = false;
|
||||
moreDataAvailable = true;
|
||||
sortable = false;
|
||||
|
||||
lockLoadData = false;
|
||||
@@ -45,6 +44,10 @@ export class ArtistComponent implements OnInit {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.moreDataAvailable) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.lockLoadData = true;
|
||||
this.elsService.getArtistSongs(this.artistName, this.songs.length).subscribe(
|
||||
data => {
|
||||
@@ -65,39 +68,4 @@ export class ArtistComponent implements OnInit {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
scrollTop(): void {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle scroll:
|
||||
* - load data if at bottom of screen (if needed)
|
||||
* - hide/show "go to top" button
|
||||
*
|
||||
* @param event scroll event
|
||||
*/
|
||||
onScroll(event: any) {
|
||||
if (this.moreDataAvailable &&
|
||||
(window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
|
||||
this.loadSongs();
|
||||
}
|
||||
|
||||
if (window.scrollY > window.innerHeight) {
|
||||
this.atBottom = true;
|
||||
}
|
||||
|
||||
if (window.scrollY === 0) {
|
||||
this.atBottom = false;
|
||||
}
|
||||
}
|
||||
|
||||
sort(): void {
|
||||
this.songs = new SortByPipe().transform(this.songs, 'Year', 'Album', 'Track Number', 'Play Count');
|
||||
this.sortable = false;
|
||||
}
|
||||
|
||||
roundBitRate(bitRate: number) {
|
||||
return Math.round(bitRate / 64);
|
||||
}
|
||||
}
|
||||
|
||||
116
dashboard/src/app/song-table/song-table.component.css
Normal file
116
dashboard/src/app/song-table/song-table.component.css
Normal file
File diff suppressed because one or more lines are too long
64
dashboard/src/app/song-table/song-table.component.html
Normal file
64
dashboard/src/app/song-table/song-table.component.html
Normal file
@@ -0,0 +1,64 @@
|
||||
<table class="table table-striped" (window:scroll)="onScroll($event)">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Name</th>
|
||||
<th>Album</th>
|
||||
<th>Year</th>
|
||||
<th>Artist</th>
|
||||
<th>Album Artist</th>
|
||||
<th>Play Count</th>
|
||||
<th>Genre</th>
|
||||
<th>Bit Rate</th>
|
||||
<th>Rating</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let song of songs | sortBy : 'Year':'Album':'Track Number'">
|
||||
<td>{{song['Track Number'] ? (("0" + song['Track Number']).slice(-2)) : "--"}}</td>
|
||||
<td>{{song.Name}}</td>
|
||||
<td>
|
||||
<a [routerLink]="['/album', song.Album]">{{song.Album}}</a>
|
||||
</td>
|
||||
<td>{{song.Year}}</td>
|
||||
<td>
|
||||
<a [routerLink]="['/artist', song.Artist]">{{song.Artist}}</a>
|
||||
</td>
|
||||
<td>{{song['Album Artist'] ? song['Album Artist'] : "-" }}</td>
|
||||
<td>{{song['Play Count']}}</td>
|
||||
<td>
|
||||
<a [routerLink]="['/genre', song.Genre]">{{song.Genre}}</a>
|
||||
</td>
|
||||
<td [title]="song['Bit Rate']">
|
||||
<span [class]="'signal signal-' + roundBitRate(song['Bit Rate'])"></span>
|
||||
</td>
|
||||
<td *ngIf="!song['Rating Computed']" [title]="'Rating: ' + song.Rating" class="star">
|
||||
<span *ngIf="song.Rating >= 20" class="glyphicon glyphicon-star"></span>
|
||||
<span *ngIf="song.Rating >= 40" class="glyphicon glyphicon-star"></span>
|
||||
<span *ngIf="song.Rating >= 60" class="glyphicon glyphicon-star"></span>
|
||||
<span *ngIf="song.Rating >= 80" class="glyphicon glyphicon-star"></span>
|
||||
<span *ngIf="song.Rating >= 100" class="glyphicon glyphicon-star"></span>
|
||||
</td>
|
||||
<td *ngIf="song['Rating Computed']" [title]="'Computed Rating: ' + song.Rating" class="star">
|
||||
<span *ngIf="song.Rating >= 20" class="glyphicon glyphicon-star-empty"></span>
|
||||
<span *ngIf="song.Rating >= 40" class="glyphicon glyphicon-star-empty"></span>
|
||||
<span *ngIf="song.Rating >= 60" class="glyphicon glyphicon-star-empty"></span>
|
||||
<span *ngIf="song.Rating >= 80" class="glyphicon glyphicon-star-empty"></span>
|
||||
<span *ngIf="song.Rating >= 100" class="glyphicon glyphicon-star-empty"></span>
|
||||
</td>
|
||||
<td *ngIf="song.Loved" class="loved">
|
||||
<span class="glyphicon glyphicon-heart heart"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- Go to Top Button-->
|
||||
<button type="button" class="btn btn-warning btn-top" [class.btn-top-is-visible]="bottomReached" aria-label="Top" (click)="scrollTop()"
|
||||
title="Go back to Top!">
|
||||
<span class="glyphicon glyphicon-menu-up" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary btn-top btn-sort" [class.btn-top-is-visible]="sortable" aria-label="Top" (click)="sort()"
|
||||
title="Sort by Album & Track Number">
|
||||
<span class="glyphicon glyphicon-sort-by-attributes" aria-hidden="true"></span>
|
||||
</button>
|
||||
25
dashboard/src/app/song-table/song-table.component.spec.ts
Normal file
25
dashboard/src/app/song-table/song-table.component.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SongTableComponent } from './song-table.component';
|
||||
|
||||
describe('SongTableComponent', () => {
|
||||
let component: SongTableComponent;
|
||||
let fixture: ComponentFixture<SongTableComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ SongTableComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SongTableComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
61
dashboard/src/app/song-table/song-table.component.ts
Normal file
61
dashboard/src/app/song-table/song-table.component.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||
|
||||
import { Song } from './../object/song';
|
||||
import { SortByPipe } from './../sort-by.pipe';
|
||||
|
||||
@Component({
|
||||
selector: 'app-song-table',
|
||||
templateUrl: './song-table.component.html',
|
||||
styleUrls: ['./song-table.component.css']
|
||||
})
|
||||
export class SongTableComponent implements OnChanges {
|
||||
@Input() songs: Array<Song> = [];
|
||||
@Input() sortable: boolean;
|
||||
@Output() atBottom = new EventEmitter();
|
||||
|
||||
// To activate button in interface var
|
||||
moreDataAvailable = false;
|
||||
bottomReached = false;
|
||||
nbSong = 0;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
console.log(changes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle scroll:
|
||||
* - load data if at bottom of screen (if needed)
|
||||
* - hide/show "go to top" button
|
||||
*
|
||||
* @param event scroll event
|
||||
*/
|
||||
onScroll(event: any) {
|
||||
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
|
||||
this.atBottom.emit();
|
||||
}
|
||||
|
||||
// Show/hide 'at top' button
|
||||
if (window.scrollY > window.innerHeight) {
|
||||
this.bottomReached = true;
|
||||
}
|
||||
|
||||
if (window.scrollY === 0) {
|
||||
this.bottomReached = false;
|
||||
}
|
||||
}
|
||||
|
||||
scrollTop(): void {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
roundBitRate(bitRate: number) {
|
||||
return Math.round(bitRate / 64);
|
||||
}
|
||||
|
||||
sort(): void {
|
||||
this.songs = new SortByPipe().transform(this.songs, 'Year', 'Album', 'Track Number', 'Play Count');
|
||||
this.sortable = false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user