@internetarchive/collection-browser 0.0.1-alpha.21 → 0.0.1-alpha.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/demo/app-root.ts +10 -0
- package/dist/demo/app-root.d.ts +2 -0
- package/dist/demo/app-root.js +8 -0
- package/dist/demo/app-root.js.map +1 -1
- package/dist/src/async-collection-name.d.ts +11 -0
- package/dist/src/async-collection-name.js +38 -0
- package/dist/src/async-collection-name.js.map +1 -0
- package/dist/src/collection-browser.d.ts +4 -2
- package/dist/src/collection-browser.js +36 -13
- package/dist/src/collection-browser.js.map +1 -1
- package/dist/src/collection-facets.d.ts +3 -0
- package/dist/src/collection-facets.js +18 -1
- package/dist/src/collection-facets.js.map +1 -1
- package/dist/src/collection-name-cache.d.ts +18 -0
- package/dist/src/collection-name-cache.js +89 -0
- package/dist/src/collection-name-cache.js.map +1 -0
- package/dist/src/models.d.ts +3 -0
- package/dist/src/models.js.map +1 -1
- package/dist/src/tiles/grid/item-tile.d.ts +3 -0
- package/dist/src/tiles/grid/item-tile.js +13 -3
- package/dist/src/tiles/grid/item-tile.js.map +1 -1
- package/dist/src/tiles/list/tile-list.d.ts +5 -0
- package/dist/src/tiles/list/tile-list.js +73 -70
- package/dist/src/tiles/list/tile-list.js.map +1 -1
- package/dist/src/tiles/tile-dispatcher.d.ts +3 -0
- package/dist/src/tiles/tile-dispatcher.js +10 -1
- package/dist/src/tiles/tile-dispatcher.js.map +1 -1
- package/dist/test/collection-name-cache.test.d.ts +1 -0
- package/dist/test/collection-name-cache.test.js +158 -0
- package/dist/test/collection-name-cache.test.js.map +1 -0
- package/dist/test/mocks/mock-search-response.d.ts +5 -0
- package/dist/test/mocks/mock-search-response.js +62 -0
- package/dist/test/mocks/mock-search-response.js.map +1 -0
- package/dist/test/mocks/mock-search-service.d.ts +13 -0
- package/dist/test/mocks/mock-search-service.js +20 -0
- package/dist/test/mocks/mock-search-service.js.map +1 -0
- package/package.json +4 -1
- package/src/collection-browser.ts +32 -3
- package/src/collection-facets.ts +21 -1
- package/src/models.ts +3 -0
- package/src/tiles/grid/item-tile.ts +14 -3
- package/src/tiles/list/tile-list.ts +84 -66
- package/src/tiles/tile-dispatcher.ts +11 -0
- package/dist/src/assets/img/icons/arrow-right.d.ts +0 -2
- package/dist/src/assets/img/icons/arrow-right.js +0 -4
- package/dist/src/assets/img/icons/arrow-right.js.map +0 -1
- package/dist/src/data-manager.d.ts +0 -68
- package/dist/src/data-manager.js +0 -266
- package/dist/src/data-manager.js.map +0 -1
- package/dist/src/url-manager.d.ts +0 -0
- package/dist/src/url-manager.js +0 -2
- package/dist/src/url-manager.js.map +0 -1
- package/dist/src/your-webcomponent.d.ts +0 -8
- package/dist/src/your-webcomponent.js +0 -38
- package/dist/src/your-webcomponent.js.map +0 -1
- package/dist/test/your-webcomponent.test.d.ts +0 -1
- package/dist/test/your-webcomponent.test.js +0 -23
- package/dist/test/your-webcomponent.test.js.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* eslint-disable lit/no-invalid-html */
|
|
2
2
|
import { css, html, LitElement, nothing } from 'lit';
|
|
3
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
3
4
|
import { join } from 'lit/directives/join.js';
|
|
4
5
|
import { map } from 'lit/directives/map.js';
|
|
5
6
|
import { customElement, property } from 'lit/decorators.js';
|
|
@@ -30,9 +31,9 @@ export class TileList extends LitElement {
|
|
|
30
31
|
${this.iconLeftTemplate}
|
|
31
32
|
</div>
|
|
32
33
|
<div id="list-line-right">
|
|
33
|
-
<div id="title">${
|
|
34
|
+
<div id="title">${this.titleTemplate}</div>
|
|
34
35
|
${this.itemLineTemplate} ${this.creatorTemplate}
|
|
35
|
-
<div id="date">
|
|
36
|
+
<div id="date" class="metadata">
|
|
36
37
|
<span class="label">Published:</span> ${formatDate(
|
|
37
38
|
this.date,
|
|
38
39
|
this.formatSize
|
|
@@ -48,6 +49,7 @@ export class TileList extends LitElement {
|
|
|
48
49
|
`;
|
|
49
50
|
}
|
|
50
51
|
|
|
52
|
+
// Display templates
|
|
51
53
|
private get imgTemplate() {
|
|
52
54
|
if (!this.model?.identifier) {
|
|
53
55
|
return nothing;
|
|
@@ -75,12 +77,29 @@ export class TileList extends LitElement {
|
|
|
75
77
|
`;
|
|
76
78
|
}
|
|
77
79
|
|
|
80
|
+
private get titleTemplate() {
|
|
81
|
+
if (!this.model?.title) {
|
|
82
|
+
return nothing;
|
|
83
|
+
}
|
|
84
|
+
return html` ${this.detailsLink(this.model.identifier, this.model.title)} `;
|
|
85
|
+
}
|
|
86
|
+
|
|
78
87
|
private get itemLineTemplate() {
|
|
79
88
|
const source = this.sourceTemplate;
|
|
80
|
-
|
|
89
|
+
const volume = this.volumeTemplate;
|
|
90
|
+
const issue = this.issueTemplate;
|
|
91
|
+
if (!source && !volume && !issue) {
|
|
81
92
|
return nothing;
|
|
82
93
|
}
|
|
83
|
-
return html` <div id="item-line">${source}</div> `;
|
|
94
|
+
return html` <div id="item-line">${source} ${volume} ${issue}</div> `;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private get volumeTemplate() {
|
|
98
|
+
return this.metadataTemplate(this.model?.volume, 'Volume');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private get issueTemplate() {
|
|
102
|
+
return this.metadataTemplate(this.model?.issue, 'Issue');
|
|
84
103
|
}
|
|
85
104
|
|
|
86
105
|
private get sourceTemplate() {
|
|
@@ -89,65 +108,53 @@ export class TileList extends LitElement {
|
|
|
89
108
|
}
|
|
90
109
|
return html`
|
|
91
110
|
<div id="source">
|
|
92
|
-
|
|
111
|
+
${this.labelTemplate('Source')}
|
|
93
112
|
${this.searchLink('source', this.model.source)}
|
|
94
113
|
</div>
|
|
95
114
|
`;
|
|
96
115
|
}
|
|
97
116
|
|
|
98
117
|
private get creatorTemplate() {
|
|
99
|
-
if (!this.model?.
|
|
118
|
+
if (!this.model?.creators || this.model.creators.length === 0) {
|
|
100
119
|
return nothing;
|
|
101
120
|
}
|
|
102
121
|
return html`
|
|
103
|
-
<div id="creator">
|
|
104
|
-
|
|
105
|
-
${
|
|
122
|
+
<div id="creator" class="metadata">
|
|
123
|
+
${this.labelTemplate('By')}
|
|
124
|
+
${join(
|
|
125
|
+
map(this.model.creators, id => this.searchLink('creator', id)),
|
|
126
|
+
html`, `
|
|
127
|
+
)}
|
|
106
128
|
</div>
|
|
107
129
|
`;
|
|
108
130
|
}
|
|
109
131
|
|
|
110
132
|
private get viewsTemplate() {
|
|
111
|
-
return
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
</div>
|
|
116
|
-
`;
|
|
133
|
+
return this.metadataTemplate(
|
|
134
|
+
`${formatCount(this.model?.viewCount ?? 0, this.formatSize)}`,
|
|
135
|
+
'Views'
|
|
136
|
+
);
|
|
117
137
|
}
|
|
118
138
|
|
|
119
139
|
private get ratingTemplate() {
|
|
120
|
-
|
|
121
|
-
return nothing;
|
|
122
|
-
}
|
|
123
|
-
return html`
|
|
124
|
-
<div id="reviews">
|
|
125
|
-
<span class="label">Avg Rating: </span>
|
|
126
|
-
${this.model?.averageRating}
|
|
127
|
-
</div>
|
|
128
|
-
`;
|
|
140
|
+
return this.metadataTemplate(this.model?.averageRating, 'Avg Rating');
|
|
129
141
|
}
|
|
130
142
|
|
|
131
143
|
private get reviewsTemplate() {
|
|
132
|
-
|
|
133
|
-
return nothing;
|
|
134
|
-
}
|
|
135
|
-
return html`
|
|
136
|
-
<div id="reviews">
|
|
137
|
-
<span class="label">Reviews: </span>
|
|
138
|
-
${this.model?.commentCount}
|
|
139
|
-
</div>
|
|
140
|
-
`;
|
|
144
|
+
return this.metadataTemplate(this.model?.commentCount, 'Reviews');
|
|
141
145
|
}
|
|
142
146
|
|
|
143
147
|
private get topicsTemplate() {
|
|
144
|
-
if (!this.model?.subjects
|
|
148
|
+
if (!this.model?.subjects || this.model.subjects.length === 0) {
|
|
145
149
|
return nothing;
|
|
146
150
|
}
|
|
147
151
|
return html`
|
|
148
|
-
<div id="topics">
|
|
149
|
-
|
|
150
|
-
${
|
|
152
|
+
<div id="topics" class="metadata">
|
|
153
|
+
${this.labelTemplate('Topics')}
|
|
154
|
+
${join(
|
|
155
|
+
map(this.model.subjects, id => this.searchLink('subject', id)),
|
|
156
|
+
html`, `
|
|
157
|
+
)}
|
|
151
158
|
</div>
|
|
152
159
|
`;
|
|
153
160
|
}
|
|
@@ -157,8 +164,8 @@ export class TileList extends LitElement {
|
|
|
157
164
|
return nothing;
|
|
158
165
|
}
|
|
159
166
|
return html`
|
|
160
|
-
<div id="collections">
|
|
161
|
-
|
|
167
|
+
<div id="collections" class="metadata">
|
|
168
|
+
${this.labelTemplate('Collections')}
|
|
162
169
|
${join(
|
|
163
170
|
map(this.model.collections, id => this.detailsLink(id)),
|
|
164
171
|
html`, `
|
|
@@ -168,11 +175,27 @@ export class TileList extends LitElement {
|
|
|
168
175
|
}
|
|
169
176
|
|
|
170
177
|
private get descriptionTemplate() {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
178
|
+
return this.metadataTemplate(
|
|
179
|
+
DOMPurify.sanitize(this.model?.description ?? ''),
|
|
180
|
+
'',
|
|
181
|
+
'description'
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Utility functions
|
|
186
|
+
private metadataTemplate(text: any, label = '', id?: string) {
|
|
187
|
+
if (!text) return nothing;
|
|
188
|
+
return html`
|
|
189
|
+
<div id=${ifDefined(id)} class="metadata">
|
|
190
|
+
${this.labelTemplate(label)} ${text}
|
|
191
|
+
</div>
|
|
192
|
+
`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
private labelTemplate(label: string) {
|
|
196
|
+
return html`${label
|
|
197
|
+
? html`<span class="label">${label}: </span>`
|
|
198
|
+
: nothing}`;
|
|
176
199
|
}
|
|
177
200
|
|
|
178
201
|
private searchLink(field: string, searchTerm: string) {
|
|
@@ -180,21 +203,20 @@ export class TileList extends LitElement {
|
|
|
180
203
|
return nothing;
|
|
181
204
|
}
|
|
182
205
|
const query = encodeURIComponent(`${field}:"${searchTerm}"`);
|
|
183
|
-
//
|
|
184
|
-
return html`
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
</a>
|
|
188
|
-
`;
|
|
206
|
+
// No whitespace after closing tag
|
|
207
|
+
return html` <a href="${this.baseNavigationUrl}/search.php?query=${query}">
|
|
208
|
+
${DOMPurify.sanitize(searchTerm)}</a
|
|
209
|
+
>`;
|
|
189
210
|
}
|
|
190
211
|
|
|
191
|
-
private detailsLink(identifier: string) {
|
|
212
|
+
private detailsLink(identifier: string, text?: string) {
|
|
192
213
|
if (!identifier) {
|
|
193
214
|
return nothing;
|
|
194
215
|
}
|
|
216
|
+
const linkText = text ?? identifier;
|
|
195
217
|
// No whitespace after closing tag
|
|
196
218
|
return html` <a href="${this.baseNavigationUrl}/details/${identifier}"
|
|
197
|
-
>${DOMPurify.sanitize(
|
|
219
|
+
>${DOMPurify.sanitize(linkText)}</a
|
|
198
220
|
>`;
|
|
199
221
|
}
|
|
200
222
|
|
|
@@ -234,6 +256,10 @@ export class TileList extends LitElement {
|
|
|
234
256
|
font-size: 14px;
|
|
235
257
|
}
|
|
236
258
|
|
|
259
|
+
div a {
|
|
260
|
+
text-decoration: none;
|
|
261
|
+
}
|
|
262
|
+
|
|
237
263
|
.label {
|
|
238
264
|
font-weight: bold;
|
|
239
265
|
}
|
|
@@ -291,18 +317,16 @@ export class TileList extends LitElement {
|
|
|
291
317
|
text-decoration: none;
|
|
292
318
|
font-size: 22px;
|
|
293
319
|
font-weight: bold;
|
|
294
|
-
|
|
320
|
+
/* align top of text with image */
|
|
321
|
+
line-height: 25px;
|
|
322
|
+
margin-top: -4px;
|
|
323
|
+
padding-bottom: 2px;
|
|
295
324
|
}
|
|
296
325
|
|
|
297
|
-
|
|
298
|
-
#date,
|
|
299
|
-
#collections,
|
|
300
|
-
#topics,
|
|
301
|
-
#item-line {
|
|
326
|
+
.metadata {
|
|
302
327
|
line-height: 20px;
|
|
303
328
|
}
|
|
304
329
|
|
|
305
|
-
#title,
|
|
306
330
|
#creator,
|
|
307
331
|
#topic,
|
|
308
332
|
#source {
|
|
@@ -310,11 +334,6 @@ export class TileList extends LitElement {
|
|
|
310
334
|
overflow: hidden;
|
|
311
335
|
}
|
|
312
336
|
|
|
313
|
-
#title,
|
|
314
|
-
#creator {
|
|
315
|
-
white-space: nowrap;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
337
|
#icon {
|
|
319
338
|
padding-top: 5px;
|
|
320
339
|
}
|
|
@@ -344,7 +363,7 @@ export class TileList extends LitElement {
|
|
|
344
363
|
column-gap: 5px;
|
|
345
364
|
}
|
|
346
365
|
|
|
347
|
-
|
|
366
|
+
div a:hover {
|
|
348
367
|
text-decoration: underline;
|
|
349
368
|
}
|
|
350
369
|
|
|
@@ -353,7 +372,6 @@ export class TileList extends LitElement {
|
|
|
353
372
|
display: flex;
|
|
354
373
|
flex-direction: row;
|
|
355
374
|
gap: 10px;
|
|
356
|
-
line-height: 20px;
|
|
357
375
|
}
|
|
358
376
|
`;
|
|
359
377
|
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
SharedResizeObserverResizeHandlerInterface,
|
|
7
7
|
} from '@internetarchive/shared-resize-observer';
|
|
8
8
|
import { SortParam } from '@internetarchive/search-service';
|
|
9
|
+
import type { CollectionNameCacheInterface } from '@internetarchive/collection-name-cache';
|
|
9
10
|
import type { CollectionDisplayMode, TileModel } from '../models';
|
|
10
11
|
import './grid/collection-tile';
|
|
11
12
|
import './grid/item-tile';
|
|
@@ -35,6 +36,9 @@ export class TileDispatcher
|
|
|
35
36
|
|
|
36
37
|
@property({ type: Object }) sortParam?: SortParam;
|
|
37
38
|
|
|
39
|
+
@property({ type: Object })
|
|
40
|
+
collectionNameCache?: CollectionNameCacheInterface;
|
|
41
|
+
|
|
38
42
|
@query('#container') private container!: HTMLDivElement;
|
|
39
43
|
|
|
40
44
|
render() {
|
|
@@ -64,6 +68,12 @@ export class TileDispatcher
|
|
|
64
68
|
${this.showDeleteButton
|
|
65
69
|
? html`<button id="delete-button">X</button>`
|
|
66
70
|
: nothing}
|
|
71
|
+
${this.displayMode === 'list-detail' ? this.tile : this.linkTileTemplate}
|
|
72
|
+
`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private get linkTileTemplate() {
|
|
76
|
+
return html`
|
|
67
77
|
<a
|
|
68
78
|
href="${this.baseNavigationUrl}/details/${this.model?.identifier}"
|
|
69
79
|
title=${ifDefined(this.model?.title)}
|
|
@@ -135,6 +145,7 @@ export class TileDispatcher
|
|
|
135
145
|
.baseNavigationUrl=${baseNavigationUrl}
|
|
136
146
|
.currentWidth=${currentWidth}
|
|
137
147
|
.currentHeight=${currentHeight}
|
|
148
|
+
.collectionNameCache=${this.collectionNameCache}
|
|
138
149
|
></item-tile>`;
|
|
139
150
|
}
|
|
140
151
|
case 'list-compact':
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { svg } from 'lit';
|
|
2
|
-
export default svg `<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path d="m79.8883285 50.0035012.1116715-.1085359-43.1159942-46.61088155c-2.401537-2.18938917-4.6902018-3.28408375-6.8659943-3.28408375s-4.1642651.63837733-5.9654178 1.91513199c-1.8011528 1.27675467-3.1520173 2.97248092-4.0525937 5.08717877l39.4020173 42.99768924-39.4020173 42.9976892c.9005764 2.1146979 2.2514409 3.8104241 4.0525937 5.0871788 1.8011527 1.2767547 3.7896253 1.915132 5.9654178 1.915132 2.1013449 0 4.3900096-1.0573489 6.8659943-3.1720468l43.1159942-46.7194174z"/></svg>
|
|
3
|
-
`;
|
|
4
|
-
//# sourceMappingURL=arrow-right.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"arrow-right.js","sourceRoot":"","sources":["../../../../../src/assets/img/icons/arrow-right.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,eAAe,GAAG,CAAA;CACjB,CAAA","sourcesContent":["import { svg } from 'lit';\n\nexport default svg`<svg viewBox=\"0 0 100 100\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"m79.8883285 50.0035012.1116715-.1085359-43.1159942-46.61088155c-2.401537-2.18938917-4.6902018-3.28408375-6.8659943-3.28408375s-4.1642651.63837733-5.9654178 1.91513199c-1.8011528 1.27675467-3.1520173 2.97248092-4.0525937 5.08717877l39.4020173 42.99768924-39.4020173 42.9976892c.9005764 2.1146979 2.2514409 3.8104241 4.0525937 5.0871788 1.8011527 1.2767547 3.7896253 1.915132 5.9654178 1.915132 2.1013449 0 4.3900096-1.0573489 6.8659943-3.1720468l43.1159942-46.7194174z\"/></svg>\n`\n"]}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { Aggregation, SortParam, SearchServiceInterface } from '@internetarchive/search-service';
|
|
2
|
-
import { SelectedFacets } from './models';
|
|
3
|
-
import type { TileModel } from './models';
|
|
4
|
-
export interface DataManagerInterface {
|
|
5
|
-
fetchFullYearHistogram(): Promise<Aggregation | undefined>;
|
|
6
|
-
fetchFacets(): Promise<Record<string, Aggregation> | undefined>;
|
|
7
|
-
}
|
|
8
|
-
export declare class DataManager implements DataManagerInterface {
|
|
9
|
-
searchService: SearchServiceInterface;
|
|
10
|
-
dataSource: Record<string, TileModel[]>;
|
|
11
|
-
titleQuery?: string;
|
|
12
|
-
creatorQuery?: string;
|
|
13
|
-
baseQuery?: string;
|
|
14
|
-
sortParam: SortParam | null;
|
|
15
|
-
dateRangeQueryClause?: string;
|
|
16
|
-
pageSize: number;
|
|
17
|
-
selectedFacets: SelectedFacets;
|
|
18
|
-
endOfDataReached: boolean;
|
|
19
|
-
private pageFetchesInProgress;
|
|
20
|
-
/**
|
|
21
|
-
* The query key is a string that uniquely identifies the current query
|
|
22
|
-
* without the date range.
|
|
23
|
-
*
|
|
24
|
-
* If this doesn't change, we don't need to re-fetch the histogram date range
|
|
25
|
-
*/
|
|
26
|
-
private get fullQueryNoDateKey();
|
|
27
|
-
/**
|
|
28
|
-
* If we haven't changed the query, we don't need to fetch the full year histogram
|
|
29
|
-
*
|
|
30
|
-
* @private
|
|
31
|
-
* @type {string}
|
|
32
|
-
* @memberof CollectionBrowser
|
|
33
|
-
*/
|
|
34
|
-
private previousFullQueryNoDate?;
|
|
35
|
-
/**
|
|
36
|
-
* This method is similar to fetching the facets above,
|
|
37
|
-
* but only fetching the year histogram. There is a subtle difference
|
|
38
|
-
* in how you have to fetch the year histogram where you can't use the
|
|
39
|
-
* advanced JSON syntax like the other aggregations. It's a special
|
|
40
|
-
* case that @ximm put it place.
|
|
41
|
-
*/
|
|
42
|
-
fetchFullYearHistogram(): Promise<Aggregation | undefined>;
|
|
43
|
-
fetchFacets(): Promise<Record<string, Aggregation> | undefined>;
|
|
44
|
-
/**
|
|
45
|
-
* Generates a query string for the given facets
|
|
46
|
-
*
|
|
47
|
-
* Example: `mediatype:("collection" OR "audio" OR -"etree") AND year:("2000" OR "2001")`
|
|
48
|
-
*/
|
|
49
|
-
private get facetQuery();
|
|
50
|
-
private get sortFilterQueries();
|
|
51
|
-
private get fullQueryWithoutDate();
|
|
52
|
-
private get fullQuery();
|
|
53
|
-
/**
|
|
54
|
-
* The query key is a string that uniquely identifies the current query
|
|
55
|
-
*
|
|
56
|
-
* This lets us keep track of queries so we don't persist data that's
|
|
57
|
-
* no longer relevant.
|
|
58
|
-
*/
|
|
59
|
-
private get pageFetchQueryKey();
|
|
60
|
-
fetchPage(pageNumber: number): Promise<void>;
|
|
61
|
-
/**
|
|
62
|
-
* Update the datasource from the fetch response
|
|
63
|
-
*
|
|
64
|
-
* @param pageNumber
|
|
65
|
-
* @param docs
|
|
66
|
-
*/
|
|
67
|
-
private updateDataSource;
|
|
68
|
-
}
|
package/dist/src/data-manager.js
DELETED
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
import { SearchParams, SearchService, AggregateSearchParams, } from '@internetarchive/search-service';
|
|
2
|
-
export class DataManager {
|
|
3
|
-
constructor() {
|
|
4
|
-
this.searchService = SearchService.default;
|
|
5
|
-
this.dataSource = {};
|
|
6
|
-
this.sortParam = null;
|
|
7
|
-
this.pageSize = 50;
|
|
8
|
-
this.selectedFacets = {
|
|
9
|
-
subject: {},
|
|
10
|
-
creator: {},
|
|
11
|
-
mediatype: {},
|
|
12
|
-
language: {},
|
|
13
|
-
collection: {},
|
|
14
|
-
year: {},
|
|
15
|
-
};
|
|
16
|
-
this.endOfDataReached = false;
|
|
17
|
-
// this maps the query to the pages being fetched for that query
|
|
18
|
-
this.pageFetchesInProgress = {};
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* The query key is a string that uniquely identifies the current query
|
|
22
|
-
* without the date range.
|
|
23
|
-
*
|
|
24
|
-
* If this doesn't change, we don't need to re-fetch the histogram date range
|
|
25
|
-
*/
|
|
26
|
-
get fullQueryNoDateKey() {
|
|
27
|
-
var _a;
|
|
28
|
-
return `${this.fullQueryWithoutDate}-${(_a = this.sortParam) === null || _a === void 0 ? void 0 : _a.asString}`;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* This method is similar to fetching the facets above,
|
|
32
|
-
* but only fetching the year histogram. There is a subtle difference
|
|
33
|
-
* in how you have to fetch the year histogram where you can't use the
|
|
34
|
-
* advanced JSON syntax like the other aggregations. It's a special
|
|
35
|
-
* case that @ximm put it place.
|
|
36
|
-
*/
|
|
37
|
-
async fetchFullYearHistogram() {
|
|
38
|
-
var _a, _b, _c, _d;
|
|
39
|
-
const { fullQueryNoDateKey } = this;
|
|
40
|
-
if (!this.fullQueryWithoutDate ||
|
|
41
|
-
fullQueryNoDateKey === this.previousFullQueryNoDate)
|
|
42
|
-
return undefined;
|
|
43
|
-
this.previousFullQueryNoDate = fullQueryNoDateKey;
|
|
44
|
-
const aggregations = new AggregateSearchParams({
|
|
45
|
-
simpleParams: ['year'],
|
|
46
|
-
});
|
|
47
|
-
const params = new SearchParams({
|
|
48
|
-
query: this.fullQueryWithoutDate,
|
|
49
|
-
fields: ['identifier'],
|
|
50
|
-
aggregations,
|
|
51
|
-
rows: 1,
|
|
52
|
-
});
|
|
53
|
-
// this.fullYearAggregationLoading = true;
|
|
54
|
-
const results = await ((_a = this.searchService) === null || _a === void 0 ? void 0 : _a.search(params));
|
|
55
|
-
// this.fullYearAggregationLoading = false;
|
|
56
|
-
// this.fullYearsHistogramAggregation =
|
|
57
|
-
return (_d = (_c = (_b = results === null || results === void 0 ? void 0 : results.success) === null || _b === void 0 ? void 0 : _b.response) === null || _c === void 0 ? void 0 : _c.aggregations) === null || _d === void 0 ? void 0 : _d.year_histogram;
|
|
58
|
-
}
|
|
59
|
-
async fetchFacets() {
|
|
60
|
-
var _a, _b;
|
|
61
|
-
if (!this.fullQuery)
|
|
62
|
-
return undefined;
|
|
63
|
-
const aggregations = new AggregateSearchParams({
|
|
64
|
-
advancedParams: [
|
|
65
|
-
{
|
|
66
|
-
field: 'subjectSorter',
|
|
67
|
-
size: 6,
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
field: 'mediatypeSorter',
|
|
71
|
-
size: 6,
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
field: 'languageSorter',
|
|
75
|
-
size: 6,
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
field: 'creatorSorter',
|
|
79
|
-
size: 6,
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
field: 'collection',
|
|
83
|
-
size: 12,
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
field: 'year',
|
|
87
|
-
size: 50,
|
|
88
|
-
},
|
|
89
|
-
],
|
|
90
|
-
});
|
|
91
|
-
const params = new SearchParams({
|
|
92
|
-
query: this.fullQuery,
|
|
93
|
-
fields: ['identifier'],
|
|
94
|
-
aggregations,
|
|
95
|
-
rows: 1,
|
|
96
|
-
});
|
|
97
|
-
// this.facetsLoading = true;
|
|
98
|
-
const results = await ((_a = this.searchService) === null || _a === void 0 ? void 0 : _a.search(params));
|
|
99
|
-
// this.facetsLoading = false;
|
|
100
|
-
return (_b = results === null || results === void 0 ? void 0 : results.success) === null || _b === void 0 ? void 0 : _b.response.aggregations;
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Generates a query string for the given facets
|
|
104
|
-
*
|
|
105
|
-
* Example: `mediatype:("collection" OR "audio" OR -"etree") AND year:("2000" OR "2001")`
|
|
106
|
-
*/
|
|
107
|
-
get facetQuery() {
|
|
108
|
-
const facetQuery = [];
|
|
109
|
-
for (const [facetName, facetValues] of Object.entries(this.selectedFacets)) {
|
|
110
|
-
const facetEntries = Object.entries(facetValues);
|
|
111
|
-
// eslint-disable-next-line no-continue
|
|
112
|
-
if (facetEntries.length === 0)
|
|
113
|
-
continue;
|
|
114
|
-
const facetValuesArray = [];
|
|
115
|
-
for (const [key, facetState] of facetEntries) {
|
|
116
|
-
facetValuesArray.push(`${facetState === 'hidden' ? '-' : ''}"${key}"`);
|
|
117
|
-
}
|
|
118
|
-
const valueQuery = facetValuesArray.join(` OR `);
|
|
119
|
-
facetQuery.push(`${facetName}:(${valueQuery})`);
|
|
120
|
-
}
|
|
121
|
-
return facetQuery.length > 0 ? `(${facetQuery.join(' AND ')})` : undefined;
|
|
122
|
-
}
|
|
123
|
-
get sortFilterQueries() {
|
|
124
|
-
const queries = [this.titleQuery, this.creatorQuery];
|
|
125
|
-
return queries.filter(q => q).join(' AND ');
|
|
126
|
-
}
|
|
127
|
-
get fullQueryWithoutDate() {
|
|
128
|
-
if (!this.baseQuery)
|
|
129
|
-
return undefined;
|
|
130
|
-
let fullQuery = this.baseQuery;
|
|
131
|
-
const { facetQuery, sortFilterQueries } = this;
|
|
132
|
-
if (facetQuery) {
|
|
133
|
-
fullQuery += ` AND ${facetQuery}`;
|
|
134
|
-
}
|
|
135
|
-
if (sortFilterQueries) {
|
|
136
|
-
fullQuery += ` AND ${sortFilterQueries}`;
|
|
137
|
-
}
|
|
138
|
-
return fullQuery;
|
|
139
|
-
}
|
|
140
|
-
get fullQuery() {
|
|
141
|
-
let { fullQueryWithoutDate } = this;
|
|
142
|
-
const { dateRangeQueryClause } = this;
|
|
143
|
-
if (dateRangeQueryClause) {
|
|
144
|
-
fullQueryWithoutDate += ` AND ${dateRangeQueryClause}`;
|
|
145
|
-
}
|
|
146
|
-
return fullQueryWithoutDate;
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* The query key is a string that uniquely identifies the current query
|
|
150
|
-
*
|
|
151
|
-
* This lets us keep track of queries so we don't persist data that's
|
|
152
|
-
* no longer relevant.
|
|
153
|
-
*/
|
|
154
|
-
get pageFetchQueryKey() {
|
|
155
|
-
var _a;
|
|
156
|
-
return `${this.fullQuery}-${(_a = this.sortParam) === null || _a === void 0 ? void 0 : _a.asString}`;
|
|
157
|
-
}
|
|
158
|
-
async fetchPage(pageNumber) {
|
|
159
|
-
var _a, _b, _c, _d;
|
|
160
|
-
if (!this.fullQuery)
|
|
161
|
-
return;
|
|
162
|
-
// if we already have data, don't fetch again
|
|
163
|
-
if (this.dataSource[pageNumber])
|
|
164
|
-
return;
|
|
165
|
-
if (this.endOfDataReached)
|
|
166
|
-
return;
|
|
167
|
-
// if a fetch is already in progress for this query and page, don't fetch again
|
|
168
|
-
const { pageFetchQueryKey } = this;
|
|
169
|
-
const pageFetches = (_a = this.pageFetchesInProgress[pageFetchQueryKey]) !== null && _a !== void 0 ? _a : new Set();
|
|
170
|
-
if (pageFetches.has(pageNumber))
|
|
171
|
-
return;
|
|
172
|
-
pageFetches.add(pageNumber);
|
|
173
|
-
this.pageFetchesInProgress[pageFetchQueryKey] = pageFetches;
|
|
174
|
-
const sortParams = this.sortParam ? [this.sortParam] : [];
|
|
175
|
-
const params = new SearchParams({
|
|
176
|
-
query: this.fullQuery,
|
|
177
|
-
fields: [
|
|
178
|
-
'identifier',
|
|
179
|
-
'title',
|
|
180
|
-
'mediatype',
|
|
181
|
-
'downloads',
|
|
182
|
-
'avg_rating',
|
|
183
|
-
'num_favorites',
|
|
184
|
-
'num_reviews',
|
|
185
|
-
'item_count',
|
|
186
|
-
'description',
|
|
187
|
-
'date',
|
|
188
|
-
'addeddate',
|
|
189
|
-
'publicdate',
|
|
190
|
-
'reviewdate',
|
|
191
|
-
'creator',
|
|
192
|
-
'collections_raw',
|
|
193
|
-
],
|
|
194
|
-
page: pageNumber,
|
|
195
|
-
rows: this.pageSize,
|
|
196
|
-
sort: sortParams,
|
|
197
|
-
});
|
|
198
|
-
const results = await ((_b = this.searchService) === null || _b === void 0 ? void 0 : _b.search(params));
|
|
199
|
-
const success = results === null || results === void 0 ? void 0 : results.success;
|
|
200
|
-
if (!success)
|
|
201
|
-
return;
|
|
202
|
-
// this.totalResults = success.response.numFound;
|
|
203
|
-
// this is checking to see if the query has changed since the data was fetched
|
|
204
|
-
// if so, we just want to discard the data since there should be a new query
|
|
205
|
-
// right behind it
|
|
206
|
-
const searchQuery = success.responseHeader.params.qin;
|
|
207
|
-
const searchSort = success.responseHeader.params.sort;
|
|
208
|
-
const queryChangedSinceFetch = searchQuery !== this.fullQuery || searchSort !== ((_c = this.sortParam) === null || _c === void 0 ? void 0 : _c.asString);
|
|
209
|
-
if (queryChangedSinceFetch)
|
|
210
|
-
return;
|
|
211
|
-
const { docs } = success.response;
|
|
212
|
-
if (docs && docs.length > 0) {
|
|
213
|
-
this.updateDataSource(pageNumber, docs);
|
|
214
|
-
}
|
|
215
|
-
if (docs.length < this.pageSize) {
|
|
216
|
-
this.endOfDataReached = true;
|
|
217
|
-
// this updates the infinite scroller to show the actual size
|
|
218
|
-
// this.infiniteScroller.itemCount = this.actualTileCount;
|
|
219
|
-
}
|
|
220
|
-
(_d = this.pageFetchesInProgress[pageFetchQueryKey]) === null || _d === void 0 ? void 0 : _d.delete(pageNumber);
|
|
221
|
-
// this.searchResultsLoading = false;
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* Update the datasource from the fetch response
|
|
225
|
-
*
|
|
226
|
-
* @param pageNumber
|
|
227
|
-
* @param docs
|
|
228
|
-
*/
|
|
229
|
-
updateDataSource(pageNumber, docs) {
|
|
230
|
-
// copy our existing datasource so when we set it below, it gets set
|
|
231
|
-
// instead of modifying the existing dataSource since object changes
|
|
232
|
-
// don't trigger a re-render
|
|
233
|
-
const datasource = { ...this.dataSource };
|
|
234
|
-
const tiles = [];
|
|
235
|
-
docs === null || docs === void 0 ? void 0 : docs.forEach(doc => {
|
|
236
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
|
|
237
|
-
if (!doc.identifier)
|
|
238
|
-
return;
|
|
239
|
-
tiles.push({
|
|
240
|
-
identifier: doc.identifier,
|
|
241
|
-
title: (_b = (_a = doc.title) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '',
|
|
242
|
-
mediatype: (_d = (_c = doc.mediatype) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : 'data',
|
|
243
|
-
viewCount: (_f = (_e = doc.downloads) === null || _e === void 0 ? void 0 : _e.value) !== null && _f !== void 0 ? _f : 0,
|
|
244
|
-
favCount: (_h = (_g = doc.num_favorites) === null || _g === void 0 ? void 0 : _g.value) !== null && _h !== void 0 ? _h : 0,
|
|
245
|
-
commentCount: (_k = (_j = doc.num_reviews) === null || _j === void 0 ? void 0 : _j.value) !== null && _k !== void 0 ? _k : 0,
|
|
246
|
-
itemCount: (_m = (_l = doc.item_count) === null || _l === void 0 ? void 0 : _l.value) !== null && _m !== void 0 ? _m : 0,
|
|
247
|
-
description: (_o = doc.description) === null || _o === void 0 ? void 0 : _o.value,
|
|
248
|
-
dateAdded: (_p = doc.addeddate) === null || _p === void 0 ? void 0 : _p.value,
|
|
249
|
-
dateArchived: (_q = doc.publicdate) === null || _q === void 0 ? void 0 : _q.value,
|
|
250
|
-
dateReviewed: (_r = doc.reviewdate) === null || _r === void 0 ? void 0 : _r.value,
|
|
251
|
-
datePublished: (_s = doc.date) === null || _s === void 0 ? void 0 : _s.value,
|
|
252
|
-
creator: (_t = doc.creator) === null || _t === void 0 ? void 0 : _t.value,
|
|
253
|
-
averageRating: (_u = doc.avg_rating) === null || _u === void 0 ? void 0 : _u.value,
|
|
254
|
-
collections: (_w = (_v = doc.collections_raw) === null || _v === void 0 ? void 0 : _v.values) !== null && _w !== void 0 ? _w : [],
|
|
255
|
-
});
|
|
256
|
-
});
|
|
257
|
-
datasource[pageNumber] = tiles;
|
|
258
|
-
this.dataSource = datasource;
|
|
259
|
-
// const visiblePages = this.currentVisiblePageNumbers;
|
|
260
|
-
// const needsReload = visiblePages.includes(pageNumber);
|
|
261
|
-
// if (needsReload) {
|
|
262
|
-
// this.infiniteScroller.reload();
|
|
263
|
-
// }
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
//# sourceMappingURL=data-manager.js.map
|