@internetarchive/collection-browser 0.2.14-a1 → 0.2.14-alpha1
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/dist/src/app-root.d.ts +1 -0
- package/dist/src/app-root.js +28 -2
- package/dist/src/app-root.js.map +1 -1
- package/dist/src/assets/img/icons/arrow-left.d.ts +2 -0
- package/dist/src/assets/img/icons/arrow-left.js +10 -0
- package/dist/src/assets/img/icons/arrow-left.js.map +1 -0
- package/dist/src/assets/img/icons/arrow-right.d.ts +2 -0
- package/dist/src/assets/img/icons/arrow-right.js +10 -0
- package/dist/src/assets/img/icons/arrow-right.js.map +1 -0
- package/dist/src/collection-browser.d.ts +2 -0
- package/dist/src/collection-browser.js +7 -0
- package/dist/src/collection-browser.js.map +1 -1
- package/dist/src/collection-facets/more-facets-content.d.ts +50 -0
- package/dist/src/collection-facets/more-facets-content.js +354 -0
- package/dist/src/collection-facets/more-facets-content.js.map +1 -0
- package/dist/src/collection-facets/more-facets-pagination.d.ts +27 -0
- package/dist/src/collection-facets/more-facets-pagination.js +193 -0
- package/dist/src/collection-facets/more-facets-pagination.js.map +1 -0
- package/dist/src/collection-facets.d.ts +19 -2
- package/dist/src/collection-facets.js +102 -0
- package/dist/src/collection-facets.js.map +1 -1
- package/dist/test/collection-facets/more-facets-content.test.d.ts +1 -0
- package/dist/test/collection-facets/more-facets-content.test.js +75 -0
- package/dist/test/collection-facets/more-facets-content.test.js.map +1 -0
- package/dist/test/collection-facets/more-facets-pagination.test.d.ts +1 -0
- package/dist/test/collection-facets/more-facets-pagination.test.js +38 -0
- package/dist/test/collection-facets/more-facets-pagination.test.js.map +1 -0
- package/dist/test/mocks/mock-search-responses.js +13 -0
- package/dist/test/mocks/mock-search-responses.js.map +1 -1
- package/package.json +3 -1
- package/src/app-root.ts +28 -2
- package/src/assets/img/icons/arrow-left.ts +10 -0
- package/src/assets/img/icons/arrow-right.ts +10 -0
- package/src/collection-browser.ts +6 -0
- package/src/collection-facets/more-facets-content.ts +371 -0
- package/src/collection-facets/more-facets-pagination.ts +201 -0
- package/src/collection-facets.ts +117 -1
- package/test/collection-facets/more-facets-content.test.ts +113 -0
- package/test/collection-facets/more-facets-pagination.test.ts +70 -0
- package/test/mocks/mock-search-responses.ts +13 -0
package/src/app-root.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { html, css, LitElement, PropertyValues } from 'lit';
|
|
|
4
4
|
import { customElement, query, state } from 'lit/decorators.js';
|
|
5
5
|
import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
|
|
6
6
|
import { CollectionNameCache } from '@internetarchive/collection-name-cache';
|
|
7
|
+
import type { ModalManagerInterface } from '@internetarchive/modal-manager';
|
|
7
8
|
import type { CollectionBrowser } from '../src/collection-browser';
|
|
8
9
|
import '../src/collection-browser';
|
|
9
10
|
|
|
@@ -40,6 +41,8 @@ export class AppRoot extends LitElement {
|
|
|
40
41
|
|
|
41
42
|
@query('collection-browser') private collectionBrowser!: CollectionBrowser;
|
|
42
43
|
|
|
44
|
+
@query('modal-manager') private modalManager!: ModalManagerInterface;
|
|
45
|
+
|
|
43
46
|
private searchPressed(e: Event) {
|
|
44
47
|
e.preventDefault();
|
|
45
48
|
this.searchQuery = this.baseQueryField.value;
|
|
@@ -171,11 +174,13 @@ export class AppRoot extends LitElement {
|
|
|
171
174
|
.collectionNameCache=${this.collectionNameCache}
|
|
172
175
|
.showHistogramDatePicker=${true}
|
|
173
176
|
.loggedIn=${this.loggedIn}
|
|
177
|
+
.modalManager=${this.modalManager}
|
|
174
178
|
@visiblePageChanged=${this.visiblePageChanged}
|
|
175
179
|
@baseQueryChanged=${this.baseQueryChanged}
|
|
176
180
|
>
|
|
177
181
|
</collection-browser>
|
|
178
182
|
</div>
|
|
183
|
+
<modal-manager></modal-manager>
|
|
179
184
|
`;
|
|
180
185
|
}
|
|
181
186
|
|
|
@@ -257,13 +262,34 @@ export class AppRoot extends LitElement {
|
|
|
257
262
|
display: block;
|
|
258
263
|
}
|
|
259
264
|
|
|
265
|
+
/* add the following styles to ensure proper modal visibility */
|
|
266
|
+
body.modal-manager-open {
|
|
267
|
+
overflow: hidden;
|
|
268
|
+
}
|
|
269
|
+
modal-manager {
|
|
270
|
+
display: none;
|
|
271
|
+
}
|
|
272
|
+
modal-manager[mode='open'] {
|
|
273
|
+
display: block;
|
|
274
|
+
}
|
|
275
|
+
modal-manager.more-search-facets {
|
|
276
|
+
--modalWidth: 85rem;
|
|
277
|
+
--modalBorder: 2px solid #194880;
|
|
278
|
+
--modalTitleLineHeight: 4rem;
|
|
279
|
+
--modalTitleFontSize: 1.8rem;
|
|
280
|
+
--modalCornerRadius: 0;
|
|
281
|
+
--modalBottomPadding: 0;
|
|
282
|
+
--modalScrollOffset: 0;
|
|
283
|
+
--modalCornerRadius: 0.5rem;
|
|
284
|
+
}
|
|
285
|
+
|
|
260
286
|
input,
|
|
261
287
|
button {
|
|
262
288
|
font-size: 1.6rem;
|
|
263
289
|
}
|
|
264
290
|
|
|
265
291
|
collection-browser {
|
|
266
|
-
margin-top:
|
|
292
|
+
margin-top: 20rem;
|
|
267
293
|
}
|
|
268
294
|
|
|
269
295
|
#base-query-field {
|
|
@@ -274,7 +300,7 @@ export class AppRoot extends LitElement {
|
|
|
274
300
|
position: fixed;
|
|
275
301
|
top: 0;
|
|
276
302
|
left: 0;
|
|
277
|
-
z-index:
|
|
303
|
+
z-index: 1;
|
|
278
304
|
-webkit-backdrop-filter: blur(10px);
|
|
279
305
|
backdrop-filter: blur(10px);
|
|
280
306
|
padding: 0.5rem 1rem;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { svg } from 'lit';
|
|
2
|
+
|
|
3
|
+
export default svg`
|
|
4
|
+
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
|
5
|
+
<path
|
|
6
|
+
d="m20.1116715 50.0035012-.1116715-.1085359 43.1159942-46.61088155c2.401537-2.18938917 4.6902018-3.28408375 6.8659943-3.28408375s4.1642651.63837733 5.9654178 1.91513199c1.8011528 1.27675467 3.1520173 2.97248092 4.0525937 5.08717877l-39.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.1720468l-43.1159942-46.7194174z"
|
|
7
|
+
/>
|
|
8
|
+
<title>Go left icon</title>
|
|
9
|
+
</svg>
|
|
10
|
+
`;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { svg } from 'lit';
|
|
2
|
+
|
|
3
|
+
export default svg`
|
|
4
|
+
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
|
5
|
+
<path
|
|
6
|
+
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"
|
|
7
|
+
/>
|
|
8
|
+
<title>Go right icon</title>
|
|
9
|
+
</svg>
|
|
10
|
+
`;
|
|
@@ -27,6 +27,7 @@ import type {
|
|
|
27
27
|
} from '@internetarchive/shared-resize-observer';
|
|
28
28
|
import '@internetarchive/infinite-scroller';
|
|
29
29
|
import type { CollectionNameCacheInterface } from '@internetarchive/collection-name-cache';
|
|
30
|
+
import type { ModalManagerInterface } from '@internetarchive/modal-manager';
|
|
30
31
|
import './tiles/tile-dispatcher';
|
|
31
32
|
import './tiles/collection-browser-loading-tile';
|
|
32
33
|
import './sort-filter-bar/sort-filter-bar';
|
|
@@ -115,6 +116,8 @@ export class CollectionBrowser
|
|
|
115
116
|
|
|
116
117
|
@property({ type: Boolean }) loggedIn = false;
|
|
117
118
|
|
|
119
|
+
@property({ type: Object }) modalManager?: ModalManagerInterface = undefined;
|
|
120
|
+
|
|
118
121
|
/**
|
|
119
122
|
* If item management UI active
|
|
120
123
|
*/
|
|
@@ -425,6 +428,7 @@ export class CollectionBrowser
|
|
|
425
428
|
<collection-facets
|
|
426
429
|
@facetsChanged=${this.facetsChanged}
|
|
427
430
|
@histogramDateRangeUpdated=${this.histogramDateRangeUpdated}
|
|
431
|
+
.searchService=${this.searchService}
|
|
428
432
|
.aggregations=${this.aggregations}
|
|
429
433
|
.fullYearsHistogramAggregation=${this.fullYearsHistogramAggregation}
|
|
430
434
|
.minSelectedDate=${this.minSelectedDate}
|
|
@@ -433,6 +437,8 @@ export class CollectionBrowser
|
|
|
433
437
|
.collectionNameCache=${this.collectionNameCache}
|
|
434
438
|
.languageCodeHandler=${this.languageCodeHandler}
|
|
435
439
|
.showHistogramDatePicker=${this.showHistogramDatePicker}
|
|
440
|
+
.fullQuery=${this.fullQuery}
|
|
441
|
+
.modalManager=${this.modalManager}
|
|
436
442
|
?collapsableFacets=${this.mobileView}
|
|
437
443
|
?facetsLoading=${this.facetDataLoading}
|
|
438
444
|
?fullYearAggregationLoading=${this.fullYearAggregationLoading}
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/* eslint-disable dot-notation */
|
|
2
|
+
import {
|
|
3
|
+
css,
|
|
4
|
+
CSSResultGroup,
|
|
5
|
+
html,
|
|
6
|
+
LitElement,
|
|
7
|
+
nothing,
|
|
8
|
+
PropertyValues,
|
|
9
|
+
} from 'lit';
|
|
10
|
+
import { customElement, property, state } from 'lit/decorators.js';
|
|
11
|
+
import type {
|
|
12
|
+
Aggregation,
|
|
13
|
+
Bucket,
|
|
14
|
+
SearchServiceInterface,
|
|
15
|
+
SearchParams,
|
|
16
|
+
} from '@internetarchive/search-service';
|
|
17
|
+
import type { CollectionNameCacheInterface } from '@internetarchive/collection-name-cache';
|
|
18
|
+
import { SelectedFacets, defaultSelectedFacets } from '../models';
|
|
19
|
+
import type { LanguageCodeHandlerInterface } from '../language-code-handler/language-code-handler';
|
|
20
|
+
import '@internetarchive/ia-activity-indicator/ia-activity-indicator';
|
|
21
|
+
import './more-facets-pagination';
|
|
22
|
+
|
|
23
|
+
@customElement('more-facets-content')
|
|
24
|
+
export class MoreFacetsContent extends LitElement {
|
|
25
|
+
@property({ type: String }) facetKey?: string;
|
|
26
|
+
|
|
27
|
+
@property({ type: String }) facetAggregationKey?: string;
|
|
28
|
+
|
|
29
|
+
@property({ type: String }) fullQuery?: string;
|
|
30
|
+
|
|
31
|
+
@property({ type: Object }) modalManager?: any;
|
|
32
|
+
|
|
33
|
+
@property({ type: Object }) searchService?: SearchServiceInterface;
|
|
34
|
+
|
|
35
|
+
@property({ type: Object })
|
|
36
|
+
collectionNameCache?: CollectionNameCacheInterface;
|
|
37
|
+
|
|
38
|
+
@property({ type: Object })
|
|
39
|
+
languageCodeHandler?: LanguageCodeHandlerInterface;
|
|
40
|
+
|
|
41
|
+
@property({ type: Object }) selectedFacets?: SelectedFacets;
|
|
42
|
+
|
|
43
|
+
@state() aggregations?: Record<string, Aggregation>;
|
|
44
|
+
|
|
45
|
+
@state() castedBuckets?: Bucket[] = [];
|
|
46
|
+
|
|
47
|
+
@state() pageNumber = 1;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Facets are loading on popup
|
|
51
|
+
*/
|
|
52
|
+
@state() facetsLoading = true;
|
|
53
|
+
|
|
54
|
+
@state() paginationSize = 0;
|
|
55
|
+
|
|
56
|
+
private facetsPerPage = 60; // Q. how many items we want to have on popup view
|
|
57
|
+
|
|
58
|
+
updated(changed: PropertyValues) {
|
|
59
|
+
if (changed.has('facetKey')) {
|
|
60
|
+
this.facetsLoading = true;
|
|
61
|
+
this.pageNumber = 1;
|
|
62
|
+
|
|
63
|
+
this.updateSpecificFacets();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get specific facets data from search-service API based of currently query params
|
|
69
|
+
* - this.aggregations - hold result of search service and being used for further processing.
|
|
70
|
+
*/
|
|
71
|
+
async updateSpecificFacets(): Promise<void> {
|
|
72
|
+
const aggregations = {
|
|
73
|
+
advancedParams: [
|
|
74
|
+
{
|
|
75
|
+
field: this.facetAggregationKey as string,
|
|
76
|
+
size: 1000000, // todo - do we want to have all the records at once?
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const params: SearchParams = {
|
|
82
|
+
query: this.fullQuery as string,
|
|
83
|
+
fields: ['identifier'],
|
|
84
|
+
aggregations,
|
|
85
|
+
rows: 1, // todo - do we want server-side pagination with offset/page/limit flag?
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const results = await this.searchService?.search(params);
|
|
89
|
+
this.aggregations = results?.success?.response.aggregations as any;
|
|
90
|
+
|
|
91
|
+
// filter facets data to be rendered in modal-manager
|
|
92
|
+
await this.filterFacets();
|
|
93
|
+
this.facetsLoading = false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Filter facets data stored in this.aggregations, eg.
|
|
98
|
+
* - we don't want to entertain year_histogram data since we using new date-picker
|
|
99
|
+
* - name of collections needs to be load inside cache using this.collectionNameCache
|
|
100
|
+
*
|
|
101
|
+
* this.castedBuckets - hold filtered facets data which will be render in modal
|
|
102
|
+
*/
|
|
103
|
+
async filterFacets(): Promise<void> {
|
|
104
|
+
Object.entries(this.aggregations ?? []).forEach(([key, buckets]) => {
|
|
105
|
+
if (key === 'year_histogram') return;
|
|
106
|
+
|
|
107
|
+
this.castedBuckets = buckets['buckets'] as Bucket[];
|
|
108
|
+
|
|
109
|
+
if (this.facetKey === 'collection') {
|
|
110
|
+
// for collections, we need to asynchronously load the collection name
|
|
111
|
+
// so we use the `async-collection-name` widget and for the rest, we have a static value to use
|
|
112
|
+
const collectionIds = this.castedBuckets?.map(option => option.key);
|
|
113
|
+
const collectionIdsArray = Array.from(
|
|
114
|
+
new Set(collectionIds)
|
|
115
|
+
) as string[];
|
|
116
|
+
this.collectionNameCache?.preloadIdentifiers(collectionIdsArray);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const { length } = Object.keys(this.castedBuckets as []);
|
|
121
|
+
this.paginationSize = Math.ceil(length / this.facetsPerPage);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private pageNumberClicked(e: CustomEvent<{ page: string }>) {
|
|
125
|
+
const page = e?.detail?.page;
|
|
126
|
+
if (page) {
|
|
127
|
+
this.pageNumber = Number(page);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private get getMoreFacetsTemplate() {
|
|
132
|
+
this.facetsLoading = false;
|
|
133
|
+
|
|
134
|
+
// render only items which will be visible as per this.facetsPerPage
|
|
135
|
+
const currentPageContent = this.castedBuckets?.slice(
|
|
136
|
+
(this.pageNumber - 1) * this.facetsPerPage,
|
|
137
|
+
this.pageNumber * this.facetsPerPage
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
return html`<ul class="facet-list">
|
|
141
|
+
${currentPageContent?.map(facet => {
|
|
142
|
+
let displayText = facet.key;
|
|
143
|
+
|
|
144
|
+
if (this.facetKey === 'language') {
|
|
145
|
+
displayText =
|
|
146
|
+
this.languageCodeHandler?.getLanguageNameFromCodeString(
|
|
147
|
+
displayText as string
|
|
148
|
+
) ?? displayText;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return html`
|
|
152
|
+
<li class="facet-row">
|
|
153
|
+
<label class="facet-info-display" title=${facet.key}>
|
|
154
|
+
<input
|
|
155
|
+
type="checkbox"
|
|
156
|
+
class="selected-facets"
|
|
157
|
+
.value="${facet.key}"
|
|
158
|
+
data-facet="${this.facetKey}"
|
|
159
|
+
@click=${(e: Event) => {
|
|
160
|
+
this.facetClicked(e);
|
|
161
|
+
}}
|
|
162
|
+
/>
|
|
163
|
+
<div class="facet-title">
|
|
164
|
+
${this.facetKey !== 'collection'
|
|
165
|
+
? html`${displayText}`
|
|
166
|
+
: html`<async-collection-name
|
|
167
|
+
.collectionNameCache=${this.collectionNameCache}
|
|
168
|
+
.identifier=${displayText}
|
|
169
|
+
placeholder="-"
|
|
170
|
+
></async-collection-name>`}
|
|
171
|
+
</div>
|
|
172
|
+
<div class="facet-count">${facet.doc_count}</div>
|
|
173
|
+
</label>
|
|
174
|
+
</li>
|
|
175
|
+
`;
|
|
176
|
+
})}
|
|
177
|
+
</ul>`;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private facetClicked(e: Event) {
|
|
181
|
+
const { selectedFacets } = this;
|
|
182
|
+
|
|
183
|
+
const target = e.target as HTMLInputElement;
|
|
184
|
+
const { checked, value } = target;
|
|
185
|
+
|
|
186
|
+
let newFacets: SelectedFacets;
|
|
187
|
+
if (selectedFacets) {
|
|
188
|
+
newFacets = {
|
|
189
|
+
...selectedFacets,
|
|
190
|
+
};
|
|
191
|
+
} else {
|
|
192
|
+
newFacets = defaultSelectedFacets;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (checked) {
|
|
196
|
+
newFacets[this.facetKey as keyof typeof newFacets][value] = 'selected';
|
|
197
|
+
} else {
|
|
198
|
+
delete newFacets[this.facetKey as keyof typeof newFacets][value];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
this.selectedFacets = newFacets;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
private get loaderTemplate() {
|
|
205
|
+
return this.facetsLoading
|
|
206
|
+
? html`<div class="facets-loader">
|
|
207
|
+
<ia-activity-indicator .mode="processing"></ia-activity-indicator>
|
|
208
|
+
</div>`
|
|
209
|
+
: '';
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// render pagination if more then 1 page
|
|
213
|
+
private get facetsPaginationTemplate() {
|
|
214
|
+
return this.paginationSize > 1
|
|
215
|
+
? html`<more-facets-pagination
|
|
216
|
+
.size=${this.paginationSize}
|
|
217
|
+
@pageNumberClicked=${this.pageNumberClicked}
|
|
218
|
+
></more-facets-pagination>`
|
|
219
|
+
: nothing;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private get facetsContentTemplate() {
|
|
223
|
+
return html`
|
|
224
|
+
<div class="facets-content">${this.getMoreFacetsTemplate}</div>
|
|
225
|
+
${this.paginationSize > 0
|
|
226
|
+
? html`${this.facetsPaginationTemplate}
|
|
227
|
+
<div class="footer">
|
|
228
|
+
<button
|
|
229
|
+
class="btn btn-cancel"
|
|
230
|
+
type="button"
|
|
231
|
+
@click=${this.cancelClick}
|
|
232
|
+
>
|
|
233
|
+
Cancel
|
|
234
|
+
</button>
|
|
235
|
+
<button
|
|
236
|
+
class="btn btn-submit"
|
|
237
|
+
type="button"
|
|
238
|
+
@click=${this.applySearchFacetsClicked}
|
|
239
|
+
>
|
|
240
|
+
Apply filters
|
|
241
|
+
</button>
|
|
242
|
+
</div>`
|
|
243
|
+
: html`No result found. please try again later.`}
|
|
244
|
+
`;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
render() {
|
|
248
|
+
return html`
|
|
249
|
+
<div id="more-facets-page">
|
|
250
|
+
<form>
|
|
251
|
+
${this.facetsLoading
|
|
252
|
+
? this.loaderTemplate
|
|
253
|
+
: this.facetsContentTemplate}
|
|
254
|
+
</form>
|
|
255
|
+
</div>
|
|
256
|
+
`;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
private applySearchFacetsClicked() {
|
|
260
|
+
const event = new CustomEvent<SelectedFacets>('facetsChanged', {
|
|
261
|
+
detail: this.selectedFacets,
|
|
262
|
+
bubbles: true,
|
|
263
|
+
composed: true,
|
|
264
|
+
});
|
|
265
|
+
this.dispatchEvent(event);
|
|
266
|
+
this.modalManager?.closeModal();
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
private cancelClick() {
|
|
270
|
+
this.modalManager?.closeModal();
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
static get styles(): CSSResultGroup {
|
|
274
|
+
return css`
|
|
275
|
+
#more-facets-page {
|
|
276
|
+
margin-bottom: 2rem;
|
|
277
|
+
}
|
|
278
|
+
.modal-content {
|
|
279
|
+
background-color: #fefefe;
|
|
280
|
+
margin: auto;
|
|
281
|
+
padding: 0;
|
|
282
|
+
border: 1px solid #888;
|
|
283
|
+
width: 80%;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.facets-content {
|
|
287
|
+
-webkit-column-width: 25rem;
|
|
288
|
+
-moz-column-width: 25rem;
|
|
289
|
+
column-width: 25rem;
|
|
290
|
+
font-size: 1.2rem;
|
|
291
|
+
padding: 0 10px;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
ul.facet-list {
|
|
295
|
+
list-style: none;
|
|
296
|
+
margin: 0;
|
|
297
|
+
padding: 0;
|
|
298
|
+
}
|
|
299
|
+
ul.facet-list li {
|
|
300
|
+
margin-bottom: 2px;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.facet-row {
|
|
304
|
+
text-align: left;
|
|
305
|
+
}
|
|
306
|
+
.facet-row {
|
|
307
|
+
align-items: start;
|
|
308
|
+
font-weight: 500;
|
|
309
|
+
font-size: 1.2rem;
|
|
310
|
+
}
|
|
311
|
+
.facet-row input {
|
|
312
|
+
margin: 1px 5px 1px 0;
|
|
313
|
+
}
|
|
314
|
+
.facet-info-display {
|
|
315
|
+
display: flex;
|
|
316
|
+
flex: 1;
|
|
317
|
+
cursor: pointer;
|
|
318
|
+
}
|
|
319
|
+
.facet-title {
|
|
320
|
+
flex: 1;
|
|
321
|
+
}
|
|
322
|
+
.facet-count {
|
|
323
|
+
margin-left: 5px;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.page-number {
|
|
327
|
+
background: none;
|
|
328
|
+
border: 0;
|
|
329
|
+
cursor: pointer;
|
|
330
|
+
border-radius: 100%;
|
|
331
|
+
width: 25px;
|
|
332
|
+
height: 25px;
|
|
333
|
+
margin: 10px;
|
|
334
|
+
font-size: 1.4rem;
|
|
335
|
+
vertical-align: middle;
|
|
336
|
+
}
|
|
337
|
+
.current-page {
|
|
338
|
+
background: black;
|
|
339
|
+
color: white;
|
|
340
|
+
}
|
|
341
|
+
.facets-loader {
|
|
342
|
+
text-align: center;
|
|
343
|
+
margin-bottom: 2rem;
|
|
344
|
+
height: 7rem;
|
|
345
|
+
width: 7rem;
|
|
346
|
+
display: inline-block;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.btn {
|
|
350
|
+
border: none;
|
|
351
|
+
padding: 10px;
|
|
352
|
+
margin-bottom: 10px;
|
|
353
|
+
width: auto;
|
|
354
|
+
border-radius: 0.4rem;
|
|
355
|
+
cursor: pointer;
|
|
356
|
+
}
|
|
357
|
+
.btn-cancel {
|
|
358
|
+
background-color: #000;
|
|
359
|
+
color: white;
|
|
360
|
+
}
|
|
361
|
+
.btn-submit {
|
|
362
|
+
background-color: #194880;
|
|
363
|
+
color: white;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.footer {
|
|
367
|
+
margin-top: 10px;
|
|
368
|
+
}
|
|
369
|
+
`;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { css, CSSResultGroup, html, LitElement, nothing } from 'lit';
|
|
2
|
+
import { customElement, property, state } from 'lit/decorators.js';
|
|
3
|
+
import arrowLeftIcon from '../assets/img/icons/arrow-left';
|
|
4
|
+
import arrowRightIcon from '../assets/img/icons/arrow-right';
|
|
5
|
+
|
|
6
|
+
@customElement('more-facets-pagination')
|
|
7
|
+
export class MoreFacetsPagination extends LitElement {
|
|
8
|
+
/**
|
|
9
|
+
* Total number of pages
|
|
10
|
+
*/
|
|
11
|
+
@property({ type: Number }) size?: any | undefined;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Number of pages can be moved in back/forward
|
|
15
|
+
*/
|
|
16
|
+
@property({ type: Number }) step = 2;
|
|
17
|
+
|
|
18
|
+
@state() pages?: number[] = [];
|
|
19
|
+
|
|
20
|
+
@state() currentPage = 1;
|
|
21
|
+
|
|
22
|
+
firstUpdated() {
|
|
23
|
+
this.observePageCount();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
observePageCount() {
|
|
27
|
+
this.pages = [];
|
|
28
|
+
let startPage = this.currentPage - this.step;
|
|
29
|
+
let endPage = this.currentPage + this.step;
|
|
30
|
+
|
|
31
|
+
if (startPage <= 0) {
|
|
32
|
+
endPage += -startPage + 1;
|
|
33
|
+
startPage = 1;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (endPage >= this.size) {
|
|
37
|
+
startPage = Math.max(startPage - (endPage - this.size), 1);
|
|
38
|
+
endPage = this.size;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// create first page node
|
|
42
|
+
this.createFirstNode(startPage);
|
|
43
|
+
|
|
44
|
+
// create middle pages node
|
|
45
|
+
this.createMiddelNode(startPage, endPage);
|
|
46
|
+
|
|
47
|
+
// create last page node
|
|
48
|
+
this.createLastNode(endPage);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private createFirstNode(startPage: number) {
|
|
52
|
+
if (startPage > 1) {
|
|
53
|
+
this.pages?.push(1);
|
|
54
|
+
this.pages?.push(0); // let's asssume 0 is for ellipsis template
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private createMiddelNode(startPage: number, endPage: number) {
|
|
59
|
+
for (let page = startPage; page <= endPage; page += 1) {
|
|
60
|
+
this.pages?.push(page);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private createLastNode(endPage: number) {
|
|
65
|
+
if (endPage < this.size) {
|
|
66
|
+
this.pages?.push(0); // let's asssume 0 is for ellipsis template
|
|
67
|
+
this.pages?.push(this.size);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private get getEllipsisTemplate() {
|
|
72
|
+
return html`<i>...</i>`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private emitPageClick() {
|
|
76
|
+
this.dispatchEvent(
|
|
77
|
+
new CustomEvent('pageNumberClicked', {
|
|
78
|
+
detail: { page: this.currentPage },
|
|
79
|
+
})
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private onRewind() {
|
|
84
|
+
this.currentPage -= 1;
|
|
85
|
+
if (this.currentPage < 1) {
|
|
86
|
+
this.currentPage = 1;
|
|
87
|
+
}
|
|
88
|
+
this.observePageCount();
|
|
89
|
+
this.emitPageClick();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private onForward() {
|
|
93
|
+
this.currentPage += 1;
|
|
94
|
+
if (this.currentPage > this.size) {
|
|
95
|
+
this.currentPage = this.size;
|
|
96
|
+
}
|
|
97
|
+
this.observePageCount();
|
|
98
|
+
this.emitPageClick();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private onChange(page: number) {
|
|
102
|
+
this.currentPage = page;
|
|
103
|
+
this.observePageCount();
|
|
104
|
+
this.emitPageClick();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private getPageTemplate(page: number) {
|
|
108
|
+
return html`
|
|
109
|
+
<button
|
|
110
|
+
@click="${() => this.onChange(page)}"
|
|
111
|
+
class="${this.currentPage === page ? 'current' : nothing}"
|
|
112
|
+
>
|
|
113
|
+
${page}
|
|
114
|
+
</button>
|
|
115
|
+
`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private get getPagesTemplate() {
|
|
119
|
+
return html`
|
|
120
|
+
${this.pages?.map(
|
|
121
|
+
page =>
|
|
122
|
+
html`${page !== 0
|
|
123
|
+
? this.getPageTemplate(page)
|
|
124
|
+
: this.getEllipsisTemplate}`
|
|
125
|
+
)}
|
|
126
|
+
`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
render() {
|
|
130
|
+
return html`
|
|
131
|
+
<div class="facets-pagination">
|
|
132
|
+
<button class="arrow-icon" @click=${this.onRewind}>
|
|
133
|
+
<span class="sr-only">Rewind pagination:</span>
|
|
134
|
+
${arrowLeftIcon}
|
|
135
|
+
</button>
|
|
136
|
+
<div class="page-numbers">${this.getPagesTemplate}</div>
|
|
137
|
+
<button class="arrow-icon" @click=${this.onForward}>
|
|
138
|
+
<span class="sr-only">Forward pagination:</span>
|
|
139
|
+
${arrowRightIcon}
|
|
140
|
+
</button>
|
|
141
|
+
</div>
|
|
142
|
+
`;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
static get styles(): CSSResultGroup {
|
|
146
|
+
return css`
|
|
147
|
+
.facets-pagination {
|
|
148
|
+
user-select: none;
|
|
149
|
+
margin-top: 10px;
|
|
150
|
+
background-color: rgb(239, 239, 239);
|
|
151
|
+
text-align: center;
|
|
152
|
+
font-size: 3.2rem;
|
|
153
|
+
}
|
|
154
|
+
.facets-pagination button {
|
|
155
|
+
border: none;
|
|
156
|
+
background: none;
|
|
157
|
+
}
|
|
158
|
+
.facets-pagination .arrow-icon {
|
|
159
|
+
width: 2.5rem;
|
|
160
|
+
vertical-align: initial;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.facets-pagination button,
|
|
164
|
+
.facets-pagination i {
|
|
165
|
+
background: none;
|
|
166
|
+
border: 0;
|
|
167
|
+
cursor: pointer;
|
|
168
|
+
border-radius: 100%;
|
|
169
|
+
margin: 10px;
|
|
170
|
+
padding: 5px;
|
|
171
|
+
font-size: 1.4rem;
|
|
172
|
+
vertical-align: middle;
|
|
173
|
+
display: inline-block;
|
|
174
|
+
min-width: 2.5rem;
|
|
175
|
+
}
|
|
176
|
+
.facets-pagination i {
|
|
177
|
+
cursor: auto;
|
|
178
|
+
display: inline;
|
|
179
|
+
}
|
|
180
|
+
.facets-pagination button.current {
|
|
181
|
+
background: black;
|
|
182
|
+
color: white;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.page-numbers {
|
|
186
|
+
display: inline-block;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.sr-only {
|
|
190
|
+
position: absolute;
|
|
191
|
+
width: 1px;
|
|
192
|
+
height: 1px;
|
|
193
|
+
padding: 0;
|
|
194
|
+
margin: -1px;
|
|
195
|
+
overflow: hidden;
|
|
196
|
+
clip: rect(0, 0, 0, 0);
|
|
197
|
+
border: 0;
|
|
198
|
+
}
|
|
199
|
+
`;
|
|
200
|
+
}
|
|
201
|
+
}
|