This repository has been archived by the owner on Jun 17, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
ContentImpl.ts
97 lines (76 loc) · 3.32 KB
/
ContentImpl.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// Copyright 2021 Peter Beverloo & AnimeCon. All rights reserved.
// Use of this source code is governed by a MIT license that can be
// found in the LICENSE file.
import { ApiRequestManager, ApiRequestObserver } from './ApiRequestManager';
import { DateTime } from './DateTime';
import type { Content, ContentPage } from './Content';
import type { IContentResponse } from '../api/IContent';
import type { Invalidatable } from './Invalidatable';
/**
* Message to include with the exception thrown when data is being accessed before the content
* has been initialized properly.
*/
const kExceptionMessage = 'The Content object has not been successfully initialized yet.';
/**
* Implementation of the Content interface, which provides the portal access to content pages that
* should be exposed to our visitors.
*/
export class ContentImpl implements ApiRequestObserver<'IContent'>, Content {
private requestManager: ApiRequestManager<'IContent'>;
private content?: Map<string, ContentPage>;
private observer?: Invalidatable;
constructor(observer?: Invalidatable) {
this.requestManager = new ApiRequestManager('IContent', this);
this.observer = observer;
}
/**
* Initializes the content by issuing an API call request, and returns when that request has
* been completed successfully. The initial content may be sourced from the local cache.
*/
async initialize(): Promise<boolean> {
return this.requestManager.issue();
}
// ---------------------------------------------------------------------------------------------
// ApiRequestObserver interface implementation
// ---------------------------------------------------------------------------------------------
onFailedResponse(error: Error) { /* handled in the App */ }
onSuccessResponse(response: IContentResponse) {
this.content = new Map();
for (const page of response.pages) {
this.content.set(page.pathname, {
...page,
// Store the |modified| time as a DateTime instance, valid for UNIX timestamps.
modified: DateTime.fromUnix(page.modified)
});
}
if (this.observer)
this.observer.invalidate();
}
// ---------------------------------------------------------------------------------------------
// Content implementation:
// ---------------------------------------------------------------------------------------------
has(pathname: string): boolean {
if (!this.content)
throw new Error(kExceptionMessage);
return this.content.has(pathname);
}
get(pathname: string): ContentPage | undefined {
if (!this.content)
throw new Error(kExceptionMessage);
return this.content.get(pathname);
}
getPrefixed(prefix: string): ContentPage[] {
if (!this.content)
throw new Error(kExceptionMessage);
const pages: ContentPage[] = [];
for (const [ pathname, page ] of this.content.entries()) {
if (pathname.startsWith(prefix))
pages.push(page);
}
return pages.sort((lhs, rhs) => {
if (lhs.pathname.length === rhs.pathname.length)
return 0;
return lhs.pathname.length > rhs.pathname.length ? -1 : 1;
});
}
}