State.ts 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import Collection from './Collection';
  2. import EventEmitter from '@dom111/typed-event-emitter/EventEmitter';
  3. import { t } from 'i18next';
  4. import { on } from '@dom111/element';
  5. export class State extends EventEmitter<{
  6. 'collection-updated': [];
  7. updated: [boolean?];
  8. }> {
  9. #collection: Collection;
  10. #location: Location;
  11. #history: History;
  12. #document: Document;
  13. #window: Window;
  14. #collectionUpdatedListener = (): void => this.emit('collection-updated');
  15. constructor(document: Document, window: Window) {
  16. super();
  17. this.#document = document;
  18. this.#window = window;
  19. this.#location = window.location;
  20. this.#history = window.history;
  21. this.bindEvents();
  22. this.setTitle(this.getPath());
  23. }
  24. private bindEvents(): void {
  25. on(window, 'popstate', () => this.update());
  26. }
  27. getCollection(): Collection {
  28. return this.#collection;
  29. }
  30. getPath(): string {
  31. return this.#location.pathname;
  32. }
  33. getTitleForPath(path: string): string {
  34. return t('title', {
  35. interpolation: {
  36. escapeValue: false,
  37. },
  38. path: decodeURIComponent(path),
  39. });
  40. }
  41. isDirectory(): boolean {
  42. return this.getPath().endsWith('/');
  43. }
  44. setCollection(collection: Collection): void {
  45. if (this.#collection) {
  46. this.#collection.off('updated', this.#collectionUpdatedListener);
  47. }
  48. this.#collection = collection;
  49. collection.on('updated', this.#collectionUpdatedListener);
  50. }
  51. setPath(path: string): void {
  52. if (this.#location.pathname !== path) {
  53. this.showPath(path);
  54. this.emit('updated');
  55. }
  56. }
  57. private setTitle(path: string): void {
  58. const title = this.getTitleForPath(path);
  59. if (this.#document.title !== title) {
  60. this.#document.title = title;
  61. }
  62. }
  63. showPath(path: string): void {
  64. if (this.#location.pathname !== path) {
  65. this.#history.pushState({ path }, this.getTitleForPath(path), path);
  66. this.setTitle(path);
  67. }
  68. }
  69. update(bypassCache: boolean = false): void {
  70. this.emit('updated', bypassCache);
  71. }
  72. }
  73. export default State;