@internetarchive/collection-browser 1.11.1-alpha.2 → 1.12.0
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/collection-browser.d.ts +1 -0
- package/dist/src/collection-browser.js +14 -6
- package/dist/src/collection-browser.js.map +1 -1
- package/dist/src/collection-facets.d.ts +5 -1
- package/dist/src/collection-facets.js +66 -1
- package/dist/src/collection-facets.js.map +1 -1
- package/dist/src/empty-placeholder.d.ts +1 -3
- package/dist/src/empty-placeholder.js +0 -14
- package/dist/src/empty-placeholder.js.map +1 -1
- package/dist/src/utils/analytics-events.d.ts +1 -0
- package/dist/src/utils/analytics-events.js +1 -0
- package/dist/src/utils/analytics-events.js.map +1 -1
- package/dist/test/collection-browser.test.js +12 -0
- package/dist/test/collection-browser.test.js.map +1 -1
- package/dist/test/collection-facets.test.js +50 -0
- package/dist/test/collection-facets.test.js.map +1 -1
- package/dist/test/mocks/mock-search-responses.d.ts +1 -0
- package/dist/test/mocks/mock-search-responses.js +42 -0
- package/dist/test/mocks/mock-search-responses.js.map +1 -1
- package/dist/test/mocks/mock-search-service.js +2 -1
- package/dist/test/mocks/mock-search-service.js.map +1 -1
- package/package.json +1 -1
- package/src/collection-browser.ts +12 -3
- package/src/collection-facets.ts +66 -1
- package/src/empty-placeholder.ts +0 -17
- package/src/utils/analytics-events.ts +1 -0
- package/test/collection-browser.test.ts +17 -0
- package/test/collection-facets.test.ts +66 -0
- package/test/mocks/mock-search-responses.ts +46 -0
- package/test/mocks/mock-search-service.ts +2 -0
package/src/collection-facets.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { customElement, property, state } from 'lit/decorators.js';
|
|
11
11
|
import { map } from 'lit/directives/map.js';
|
|
12
12
|
import { ref } from 'lit/directives/ref.js';
|
|
13
|
+
import { msg } from '@lit/localize';
|
|
13
14
|
import type {
|
|
14
15
|
Aggregation,
|
|
15
16
|
AggregationSortType,
|
|
@@ -88,9 +89,13 @@ export class CollectionFacets extends LitElement {
|
|
|
88
89
|
|
|
89
90
|
@property({ type: String }) query?: string;
|
|
90
91
|
|
|
92
|
+
@property({ type: String }) withinCollection?: string;
|
|
93
|
+
|
|
94
|
+
@property({ type: Array }) parentCollections: string[] = [];
|
|
95
|
+
|
|
91
96
|
@property({ type: Object }) filterMap?: FilterMap;
|
|
92
97
|
|
|
93
|
-
@property({ type: String })
|
|
98
|
+
@property({ type: String }) baseNavigationUrl?: string;
|
|
94
99
|
|
|
95
100
|
@property({ type: String }) collectionPagePath: string = '/details/';
|
|
96
101
|
|
|
@@ -143,6 +148,7 @@ export class CollectionFacets extends LitElement {
|
|
|
143
148
|
</section>
|
|
144
149
|
`
|
|
145
150
|
: nothing}
|
|
151
|
+
${this.collectionPartOfTemplate}
|
|
146
152
|
${this.mergedFacets.map(facetGroup =>
|
|
147
153
|
this.getFacetGroupTemplate(facetGroup)
|
|
148
154
|
)}
|
|
@@ -150,6 +156,51 @@ export class CollectionFacets extends LitElement {
|
|
|
150
156
|
`;
|
|
151
157
|
}
|
|
152
158
|
|
|
159
|
+
private get collectionPartOfTemplate(): TemplateResult | typeof nothing {
|
|
160
|
+
// We only display the "Part Of" section on collection pages
|
|
161
|
+
if (!this.withinCollection || this.parentCollections.length === 0)
|
|
162
|
+
return nothing;
|
|
163
|
+
|
|
164
|
+
const headingId = 'partof-heading';
|
|
165
|
+
return html`
|
|
166
|
+
<section
|
|
167
|
+
class="facet-group partof-collections"
|
|
168
|
+
aria-labelledby=${headingId}
|
|
169
|
+
>
|
|
170
|
+
<div class="facet-group-header">
|
|
171
|
+
<h3 id=${headingId}>${msg('Part Of')}</h3>
|
|
172
|
+
</div>
|
|
173
|
+
<ul>
|
|
174
|
+
${map(this.parentCollections, collxn => {
|
|
175
|
+
const collectionURL = `${this.baseNavigationUrl}${this.collectionPagePath}${collxn}`;
|
|
176
|
+
|
|
177
|
+
return html` <li>
|
|
178
|
+
<a
|
|
179
|
+
href=${collectionURL}
|
|
180
|
+
data-id=${collxn}
|
|
181
|
+
@click=${this.partOfCollectionClicked}
|
|
182
|
+
>
|
|
183
|
+
<async-collection-name
|
|
184
|
+
.collectionNameCache=${this.collectionNameCache}
|
|
185
|
+
.identifier=${collxn}
|
|
186
|
+
placeholder=${collxn}
|
|
187
|
+
></async-collection-name>
|
|
188
|
+
</a>
|
|
189
|
+
</li>`;
|
|
190
|
+
})}
|
|
191
|
+
</ul>
|
|
192
|
+
</section>
|
|
193
|
+
`;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private partOfCollectionClicked(e: Event): void {
|
|
197
|
+
this.analyticsHandler?.sendEvent({
|
|
198
|
+
category: analyticsCategories.default,
|
|
199
|
+
action: analyticsActions.partOfCollectionClicked,
|
|
200
|
+
label: (e.target as HTMLElement).dataset.id,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
153
204
|
/**
|
|
154
205
|
* Opens a modal dialog containing an enlarged version of the date picker.
|
|
155
206
|
*/
|
|
@@ -652,6 +703,14 @@ export class CollectionFacets extends LitElement {
|
|
|
652
703
|
return [
|
|
653
704
|
srOnlyStyle,
|
|
654
705
|
css`
|
|
706
|
+
a:link {
|
|
707
|
+
text-decoration: none;
|
|
708
|
+
color: var(--ia-theme-link-color, #4b64ff);
|
|
709
|
+
}
|
|
710
|
+
a:link:hover {
|
|
711
|
+
text-decoration: underline;
|
|
712
|
+
}
|
|
713
|
+
|
|
655
714
|
#container.loading {
|
|
656
715
|
opacity: 0.5;
|
|
657
716
|
}
|
|
@@ -711,6 +770,12 @@ export class CollectionFacets extends LitElement {
|
|
|
711
770
|
max-height: 2000px;
|
|
712
771
|
}
|
|
713
772
|
|
|
773
|
+
.partof-collections ul {
|
|
774
|
+
list-style-type: none;
|
|
775
|
+
padding: 0;
|
|
776
|
+
font-size: 1.2rem;
|
|
777
|
+
}
|
|
778
|
+
|
|
714
779
|
h3 {
|
|
715
780
|
font-size: 1.4rem;
|
|
716
781
|
font-weight: 200
|
package/src/empty-placeholder.ts
CHANGED
|
@@ -18,7 +18,6 @@ export type PlaceholderType =
|
|
|
18
18
|
| 'empty-collection'
|
|
19
19
|
| 'no-results'
|
|
20
20
|
| 'query-error'
|
|
21
|
-
| 'collection-error'
|
|
22
21
|
| null;
|
|
23
22
|
@customElement('empty-placeholder')
|
|
24
23
|
export class EmptyPlaceholder extends LitElement {
|
|
@@ -48,11 +47,6 @@ export class EmptyPlaceholder extends LitElement {
|
|
|
48
47
|
Tips for constructing search queries.
|
|
49
48
|
</a> `);
|
|
50
49
|
|
|
51
|
-
private static readonly MESSAGE_COLLECTION_ERROR = msg(html` The search engine
|
|
52
|
-
encountered an error fetching details for this collection. If the problem
|
|
53
|
-
persists, please let us know at
|
|
54
|
-
<a href="mailto:info@archive.org">info@archive.org</a>.`);
|
|
55
|
-
|
|
56
50
|
private static readonly QUERY_ERROR_DETAILS_MESSAGE = msg('Error details:');
|
|
57
51
|
|
|
58
52
|
@property({ type: String }) placeholderType: PlaceholderType = null;
|
|
@@ -79,7 +73,6 @@ export class EmptyPlaceholder extends LitElement {
|
|
|
79
73
|
['empty-collection', () => this.emptyCollectionTemplate],
|
|
80
74
|
['no-results', () => this.noResultsTemplate],
|
|
81
75
|
['query-error', () => this.queryErrorTemplate],
|
|
82
|
-
['collection-error', () => this.collectionErrorTemplate],
|
|
83
76
|
])}
|
|
84
77
|
</div>
|
|
85
78
|
`;
|
|
@@ -120,16 +113,6 @@ export class EmptyPlaceholder extends LitElement {
|
|
|
120
113
|
`;
|
|
121
114
|
}
|
|
122
115
|
|
|
123
|
-
private get collectionErrorTemplate(): TemplateResult {
|
|
124
|
-
return html`
|
|
125
|
-
<h2 class="title">${EmptyPlaceholder.MESSAGE_COLLECTION_ERROR}</h2>
|
|
126
|
-
<div>${nullResultIcon}</div>
|
|
127
|
-
<p class="error-details">
|
|
128
|
-
${EmptyPlaceholder.QUERY_ERROR_DETAILS_MESSAGE} ${this.detailMessage}
|
|
129
|
-
</p>
|
|
130
|
-
`;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
116
|
static get styles(): CSSResultGroup {
|
|
134
117
|
return css`
|
|
135
118
|
:host {
|
|
@@ -14,6 +14,7 @@ export enum analyticsActions {
|
|
|
14
14
|
facetDeselected = 'facetDeselected',
|
|
15
15
|
facetNegativeSelected = 'facetNegativeSelected',
|
|
16
16
|
facetNegativeDeselected = 'facetNegativeDeselected',
|
|
17
|
+
partOfCollectionClicked = 'partOfCollectionClicked',
|
|
17
18
|
histogramChanged = 'histogramChanged',
|
|
18
19
|
histogramChangedFromModal = 'histogramChangedFromModal',
|
|
19
20
|
histogramExpanded = 'histogramExpanded',
|
|
@@ -1153,6 +1153,23 @@ describe('Collection Browser', () => {
|
|
|
1153
1153
|
expect(mobileFacets).to.exist;
|
|
1154
1154
|
});
|
|
1155
1155
|
|
|
1156
|
+
it('sets parent collections to prop when searching a collection', async () => {
|
|
1157
|
+
const searchService = new MockSearchService();
|
|
1158
|
+
const el = await fixture<CollectionBrowser>(
|
|
1159
|
+
html`<collection-browser
|
|
1160
|
+
.searchService=${searchService}
|
|
1161
|
+
.withinCollection=${'fake'}
|
|
1162
|
+
></collection-browser>`
|
|
1163
|
+
);
|
|
1164
|
+
|
|
1165
|
+
el.baseQuery = 'parent-collections';
|
|
1166
|
+
await el.updateComplete;
|
|
1167
|
+
await el.initialSearchComplete;
|
|
1168
|
+
await aTimeout(0);
|
|
1169
|
+
|
|
1170
|
+
expect(el.parentCollections).to.deep.equal(['foo', 'bar']);
|
|
1171
|
+
});
|
|
1172
|
+
|
|
1156
1173
|
it('refreshes when certain properties change - with some analytics event sampling', async () => {
|
|
1157
1174
|
const mockAnalyticsHandler = new MockAnalyticsHandler();
|
|
1158
1175
|
const searchService = new MockSearchService();
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
getDefaultSelectedFacets,
|
|
17
17
|
} from '../src/models';
|
|
18
18
|
import { MockAnalyticsHandler } from './mocks/mock-analytics-handler';
|
|
19
|
+
import { MockCollectionNameCache } from './mocks/mock-collection-name-cache';
|
|
19
20
|
|
|
20
21
|
describe('Collection Facets', () => {
|
|
21
22
|
it('has loader', async () => {
|
|
@@ -814,6 +815,41 @@ describe('Collection Facets', () => {
|
|
|
814
815
|
expect(mockAnalyticsHandler.callLabel).to.equal('subject');
|
|
815
816
|
});
|
|
816
817
|
|
|
818
|
+
it('includes Part Of section for collections', async () => {
|
|
819
|
+
const mockCollectionNameCache = new MockCollectionNameCache();
|
|
820
|
+
const el = await fixture<CollectionFacets>(
|
|
821
|
+
html`<collection-facets
|
|
822
|
+
.baseNavigationUrl=${''}
|
|
823
|
+
.withinCollection=${'foo'}
|
|
824
|
+
.parentCollections=${['bar', 'baz']}
|
|
825
|
+
.collectionNameCache=${mockCollectionNameCache}
|
|
826
|
+
></collection-facets>`
|
|
827
|
+
);
|
|
828
|
+
|
|
829
|
+
const partOfSection = el.shadowRoot?.querySelector('.partof-collections');
|
|
830
|
+
expect(partOfSection).to.exist;
|
|
831
|
+
|
|
832
|
+
const partOfLinks = partOfSection?.querySelectorAll('a[href]');
|
|
833
|
+
expect(partOfLinks?.length).to.equal(2);
|
|
834
|
+
|
|
835
|
+
expect(partOfLinks?.[0]?.textContent?.trim()).to.equal('bar-name');
|
|
836
|
+
expect(partOfLinks?.[0]?.getAttribute('href')).to.equal('/details/bar');
|
|
837
|
+
expect(partOfLinks?.[1]?.textContent?.trim()).to.equal('baz-name');
|
|
838
|
+
expect(partOfLinks?.[1]?.getAttribute('href')).to.equal('/details/baz');
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
it('does not include Part Of section outside of collections', async () => {
|
|
842
|
+
// No withinCollection prop
|
|
843
|
+
const el = await fixture<CollectionFacets>(
|
|
844
|
+
html`<collection-facets
|
|
845
|
+
.parentCollections=${['bar', 'baz']}
|
|
846
|
+
></collection-facets>`
|
|
847
|
+
);
|
|
848
|
+
|
|
849
|
+
const partOfSection = el.shadowRoot?.querySelector('.partof-collections');
|
|
850
|
+
expect(partOfSection).not.to.exist;
|
|
851
|
+
});
|
|
852
|
+
|
|
817
853
|
it('fires analytics on expanding date picker', async () => {
|
|
818
854
|
const mockAnalyticsHandler = new MockAnalyticsHandler();
|
|
819
855
|
|
|
@@ -846,4 +882,34 @@ describe('Collection Facets', () => {
|
|
|
846
882
|
expect(mockAnalyticsHandler.callAction).to.equal('histogramExpanded');
|
|
847
883
|
expect(mockAnalyticsHandler.callLabel).to.equal(window.location.href);
|
|
848
884
|
});
|
|
885
|
+
|
|
886
|
+
it('fires analytics on clicking Part Of collection link', async () => {
|
|
887
|
+
const mockCollectionNameCache = new MockCollectionNameCache();
|
|
888
|
+
const mockAnalyticsHandler = new MockAnalyticsHandler();
|
|
889
|
+
|
|
890
|
+
const el = await fixture<CollectionFacets>(
|
|
891
|
+
html`<collection-facets
|
|
892
|
+
.baseNavigationUrl=${''}
|
|
893
|
+
.withinCollection=${'foo'}
|
|
894
|
+
.parentCollections=${['bar']}
|
|
895
|
+
.collectionNameCache=${mockCollectionNameCache}
|
|
896
|
+
.analyticsHandler=${mockAnalyticsHandler}
|
|
897
|
+
></collection-facets>`
|
|
898
|
+
);
|
|
899
|
+
|
|
900
|
+
const partOfLinks = el.shadowRoot?.querySelectorAll(
|
|
901
|
+
'.partof-collections a[href]'
|
|
902
|
+
);
|
|
903
|
+
expect(partOfLinks?.length).to.equal(1);
|
|
904
|
+
|
|
905
|
+
// Click the expand button to open the modal
|
|
906
|
+
const link = partOfLinks?.[0] as HTMLAnchorElement;
|
|
907
|
+
link?.addEventListener('click', e => e.preventDefault());
|
|
908
|
+
link?.click();
|
|
909
|
+
await el.updateComplete;
|
|
910
|
+
|
|
911
|
+
expect(mockAnalyticsHandler.callCategory).to.equal('collection-browser');
|
|
912
|
+
expect(mockAnalyticsHandler.callAction).to.equal('partOfCollectionClicked');
|
|
913
|
+
expect(mockAnalyticsHandler.callLabel).to.equal('bar');
|
|
914
|
+
});
|
|
849
915
|
});
|
|
@@ -728,6 +728,52 @@ export const getMockSuccessWithDefaultFavSort: () => Result<
|
|
|
728
728
|
},
|
|
729
729
|
});
|
|
730
730
|
|
|
731
|
+
export const getMockSuccessWithParentCollections: () => Result<
|
|
732
|
+
SearchResponse,
|
|
733
|
+
SearchServiceError
|
|
734
|
+
> = () => ({
|
|
735
|
+
success: {
|
|
736
|
+
request: {
|
|
737
|
+
kind: 'hits',
|
|
738
|
+
clientParameters: {
|
|
739
|
+
user_query: 'parent-collections',
|
|
740
|
+
sort: [],
|
|
741
|
+
},
|
|
742
|
+
backendRequests: {
|
|
743
|
+
primary: {
|
|
744
|
+
kind: 'hits',
|
|
745
|
+
finalized_parameters: {
|
|
746
|
+
user_query: 'parent-collections',
|
|
747
|
+
sort: [],
|
|
748
|
+
},
|
|
749
|
+
},
|
|
750
|
+
},
|
|
751
|
+
},
|
|
752
|
+
rawResponse: {},
|
|
753
|
+
response: {
|
|
754
|
+
totalResults: 1,
|
|
755
|
+
returnedCount: 1,
|
|
756
|
+
results: [
|
|
757
|
+
new ItemHit({
|
|
758
|
+
fields: {
|
|
759
|
+
identifier: 'foo',
|
|
760
|
+
title: 'Foo',
|
|
761
|
+
},
|
|
762
|
+
}),
|
|
763
|
+
],
|
|
764
|
+
collectionExtraInfo: {
|
|
765
|
+
public_metadata: {
|
|
766
|
+
collection: ['foo', 'bar'],
|
|
767
|
+
},
|
|
768
|
+
},
|
|
769
|
+
},
|
|
770
|
+
responseHeader: {
|
|
771
|
+
succeeded: true,
|
|
772
|
+
query_time: 0,
|
|
773
|
+
},
|
|
774
|
+
},
|
|
775
|
+
});
|
|
776
|
+
|
|
731
777
|
export const getMockErrorResult: () => Result<
|
|
732
778
|
SearchResponse,
|
|
733
779
|
SearchServiceError
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
getMockSuccessWithDefaultSort,
|
|
26
26
|
getMockSuccessWithConciseDefaultSort,
|
|
27
27
|
getMockSuccessWithDefaultFavSort,
|
|
28
|
+
getMockSuccessWithParentCollections,
|
|
28
29
|
} from './mock-search-responses';
|
|
29
30
|
|
|
30
31
|
const responses: Record<
|
|
@@ -45,6 +46,7 @@ const responses: Record<
|
|
|
45
46
|
'default-sort': getMockSuccessWithDefaultSort,
|
|
46
47
|
'default-sort-concise': getMockSuccessWithConciseDefaultSort,
|
|
47
48
|
'fav-sort': getMockSuccessWithDefaultFavSort,
|
|
49
|
+
'parent-collections': getMockSuccessWithParentCollections,
|
|
48
50
|
error: getMockErrorResult,
|
|
49
51
|
malformed: getMockMalformedResult,
|
|
50
52
|
};
|