mirror of https://github.com/ghostfolio/ghostfolio
committed by
GitHub
8 changed files with 142 additions and 16 deletions
@ -0,0 +1 @@ |
|||||
|
export * from './persist-sort.directive'; |
||||
@ -0,0 +1,70 @@ |
|||||
|
import { Component } from '@angular/core'; |
||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing'; |
||||
|
import { MatSort, MatSortModule } from '@angular/material/sort'; |
||||
|
|
||||
|
import { GfPersistSortDirective } from './persist-sort.directive'; |
||||
|
|
||||
|
@Component({ |
||||
|
imports: [GfPersistSortDirective, MatSortModule], |
||||
|
template: `<table
|
||||
|
gfPersistSort="test" |
||||
|
matSort |
||||
|
matSortActive="name" |
||||
|
matSortDirection="asc" |
||||
|
></table>` |
||||
|
}) |
||||
|
class TestHostComponent {} |
||||
|
|
||||
|
describe('GfPersistSortDirective', () => { |
||||
|
let fixture: ComponentFixture<TestHostComponent>; |
||||
|
|
||||
|
const create = () => { |
||||
|
fixture = TestBed.createComponent(TestHostComponent); |
||||
|
fixture.detectChanges(); |
||||
|
|
||||
|
return fixture.debugElement.children[0].injector.get(MatSort); |
||||
|
}; |
||||
|
|
||||
|
beforeEach(() => { |
||||
|
localStorage.clear(); |
||||
|
TestBed.configureTestingModule({ imports: [TestHostComponent] }); |
||||
|
}); |
||||
|
|
||||
|
it('keeps the default sorting without a stored value', () => { |
||||
|
const sort = create(); |
||||
|
|
||||
|
expect(sort.active).toBe('name'); |
||||
|
expect(sort.direction).toBe('asc'); |
||||
|
}); |
||||
|
|
||||
|
it('stores the sorting on change', () => { |
||||
|
const sort = create(); |
||||
|
|
||||
|
sort.sort({ id: 'value', start: 'desc', disableClear: false }); |
||||
|
|
||||
|
expect(JSON.parse(localStorage.getItem('gf-sort-test') ?? '{}')).toEqual({ |
||||
|
active: 'value', |
||||
|
direction: 'desc' |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
it('restores a stored sorting', () => { |
||||
|
localStorage.setItem( |
||||
|
'gf-sort-test', |
||||
|
JSON.stringify({ active: 'value', direction: 'desc' }) |
||||
|
); |
||||
|
|
||||
|
const sort = create(); |
||||
|
|
||||
|
expect(sort.active).toBe('value'); |
||||
|
expect(sort.direction).toBe('desc'); |
||||
|
}); |
||||
|
|
||||
|
it('ignores an invalid stored sorting', () => { |
||||
|
localStorage.setItem('gf-sort-test', '{"active":"value","direction":"x"}'); |
||||
|
|
||||
|
const sort = create(); |
||||
|
|
||||
|
expect(sort.active).toBe('name'); |
||||
|
}); |
||||
|
}); |
||||
@ -0,0 +1,57 @@ |
|||||
|
import { DestroyRef, Directive, inject, input, OnInit } from '@angular/core'; |
||||
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; |
||||
|
import { MatSort, SortDirection } from '@angular/material/sort'; |
||||
|
|
||||
|
const STORAGE_KEY_PREFIX = 'gf-sort-'; |
||||
|
|
||||
|
/** |
||||
|
* Remembers the sorting of a `matSort` table on the device and restores it |
||||
|
* on the next visit. |
||||
|
*/ |
||||
|
@Directive({ |
||||
|
selector: '[gfPersistSort]' |
||||
|
}) |
||||
|
export class GfPersistSortDirective implements OnInit { |
||||
|
public readonly gfPersistSort = input.required<string>(); |
||||
|
|
||||
|
private readonly destroyRef = inject(DestroyRef); |
||||
|
private readonly matSort = inject(MatSort, { self: true }); |
||||
|
|
||||
|
public ngOnInit() { |
||||
|
const storageKey = `${STORAGE_KEY_PREFIX}${this.gfPersistSort()}`; |
||||
|
const storedSort = this.readStoredSort(storageKey); |
||||
|
|
||||
|
if (storedSort) { |
||||
|
this.matSort.active = storedSort.active; |
||||
|
this.matSort.direction = storedSort.direction; |
||||
|
} |
||||
|
|
||||
|
this.matSort.sortChange |
||||
|
.pipe(takeUntilDestroyed(this.destroyRef)) |
||||
|
.subscribe(({ active, direction }) => { |
||||
|
try { |
||||
|
globalThis.localStorage?.setItem( |
||||
|
storageKey, |
||||
|
JSON.stringify({ active, direction }) |
||||
|
); |
||||
|
} catch {} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private readStoredSort(aStorageKey: string) { |
||||
|
try { |
||||
|
const item = globalThis.localStorage?.getItem(aStorageKey); |
||||
|
const { active, direction } = JSON.parse(item ?? 'null') ?? {}; |
||||
|
|
||||
|
if ( |
||||
|
typeof active === 'string' && |
||||
|
active.length > 0 && |
||||
|
(direction === 'asc' || direction === 'desc') |
||||
|
) { |
||||
|
return { active, direction: direction as SortDirection }; |
||||
|
} |
||||
|
} catch {} |
||||
|
|
||||
|
return undefined; |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue