@internetarchive/collection-browser 2.7.2-alpha.0 → 2.7.2-alpha.2
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-facets/smart-facets/heuristics/wikidata-heuristic.d.ts +1 -1
- package/dist/src/collection-facets/smart-facets/heuristics/wikidata-heuristic.js +10 -5
- package/dist/src/collection-facets/smart-facets/heuristics/wikidata-heuristic.js.map +1 -1
- package/dist/src/collection-facets/smart-facets/smart-facet-dropdown.d.ts +4 -4
- package/dist/src/collection-facets/smart-facets/smart-facet-dropdown.js +41 -25
- package/dist/src/collection-facets/smart-facets/smart-facet-dropdown.js.map +1 -1
- package/dist/src/collection-facets/smart-facets/smart-facet-equals.d.ts +2 -0
- package/dist/src/collection-facets/smart-facets/smart-facet-equals.js +15 -0
- package/dist/src/collection-facets/smart-facets/smart-facet-equals.js.map +1 -0
- package/dist/src/collection-facets/smart-facets/smart-facet-heuristics.d.ts +9 -0
- package/dist/src/collection-facets/smart-facets/smart-facet-heuristics.js +20 -4
- package/dist/src/collection-facets/smart-facets/smart-facet-heuristics.js.map +1 -1
- package/package.json +2 -2
- package/src/collection-facets/smart-facets/heuristics/wikidata-heuristic.ts +9 -4
- package/src/collection-facets/smart-facets/smart-facet-dropdown.ts +41 -21
- package/src/collection-facets/smart-facets/smart-facet-equals.ts +16 -0
- package/src/collection-facets/smart-facets/smart-facet-heuristics.ts +23 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SmartQueryHeuristic, SmartFacet } from '../models';
|
|
2
|
-
export declare class
|
|
2
|
+
export declare class WikidataHeuristic implements SmartQueryHeuristic {
|
|
3
3
|
private static readonly ENTITIES;
|
|
4
4
|
getRecommendedFacets(query: string): Promise<SmartFacet[]>;
|
|
5
5
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// If wikidata
|
|
1
|
+
// If wikidata describes the top query result as X, recommend facet Y, e.g.:
|
|
2
2
|
// X Y
|
|
3
3
|
// written work mt:texts
|
|
4
4
|
// film mt:movies
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
// filmmaker mt:movies and creator:<query>
|
|
7
7
|
// photographer mt:image and creator:<query>
|
|
8
8
|
// visual artist mt:image and creator:<query>
|
|
9
|
-
|
|
9
|
+
// etc.
|
|
10
|
+
export class WikidataHeuristic {
|
|
10
11
|
async getRecommendedFacets(query) {
|
|
11
12
|
var _a;
|
|
12
13
|
const recommendations = [];
|
|
@@ -14,8 +15,9 @@ export class WikidataEntityHeuristic {
|
|
|
14
15
|
const urlQuery = encodeURIComponent(query);
|
|
15
16
|
const wikidataResponse = await fetch(`https://www.wikidata.org/w/api.php?action=wbsearchentities&search=${urlQuery}&format=json&language=en&uselang=en&origin=*&type=item&limit=5`);
|
|
16
17
|
const searchResults = await wikidataResponse.json();
|
|
17
|
-
for (const [keyword, facets] of Object.entries(
|
|
18
|
-
|
|
18
|
+
for (const [keyword, facets] of Object.entries(WikidataHeuristic.ENTITIES)) {
|
|
19
|
+
const keywordRegex = new RegExp('\\b' + keyword + '\\b');
|
|
20
|
+
if (keywordRegex.test((_a = searchResults.search[0]) === null || _a === void 0 ? void 0 : _a.description)) {
|
|
19
21
|
const entityName = searchResults.search[0].label;
|
|
20
22
|
recommendations.push(...facets.map(sf => {
|
|
21
23
|
var _a;
|
|
@@ -43,8 +45,11 @@ export class WikidataEntityHeuristic {
|
|
|
43
45
|
}
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
|
-
|
|
48
|
+
WikidataHeuristic.ENTITIES = {
|
|
49
|
+
'written work': [{ facets: [{ facetType: 'mediatype', bucketKey: 'texts' }] }],
|
|
47
50
|
literature: [{ facets: [{ facetType: 'mediatype', bucketKey: 'texts' }] }],
|
|
51
|
+
book: [{ facets: [{ facetType: 'mediatype', bucketKey: 'texts' }] }],
|
|
52
|
+
novel: [{ facets: [{ facetType: 'mediatype', bucketKey: 'texts' }] }],
|
|
48
53
|
filmmaker: [
|
|
49
54
|
{
|
|
50
55
|
label: 'Films by __QUERY',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wikidata-heuristic.js","sourceRoot":"","sources":["../../../../../src/collection-facets/smart-facets/heuristics/wikidata-heuristic.ts"],"names":[],"mappings":"AAMA,
|
|
1
|
+
{"version":3,"file":"wikidata-heuristic.js","sourceRoot":"","sources":["../../../../../src/collection-facets/smart-facets/heuristics/wikidata-heuristic.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n SmartQueryHeuristic,\n KeywordFacetMap,\n SmartFacet,\n} from '../models';\n\n// If wikidata describes the top query result as X, recommend facet Y, e.g.:\n// X Y\n// written work mt:texts\n// film mt:movies\n// author mt:texts and creator:<query>\n// filmmaker mt:movies and creator:<query>\n// photographer mt:image and creator:<query>\n// visual artist mt:image and creator:<query>\n// etc.\nexport class WikidataHeuristic implements SmartQueryHeuristic {\n private static readonly ENTITIES: KeywordFacetMap = {\n 'written work': [{ facets: [{ facetType: 'mediatype', bucketKey: 'texts' }] }],\n literature: [{ facets: [{ facetType: 'mediatype', bucketKey: 'texts' }] }],\n book: [{ facets: [{ facetType: 'mediatype', bucketKey: 'texts' }] }],\n novel: [{ facets: [{ facetType: 'mediatype', bucketKey: 'texts' }] }],\n filmmaker: [\n {\n label: 'Films by __QUERY',\n facets: [\n { facetType: 'mediatype', bucketKey: 'movies' },\n { facetType: 'creator', bucketKey: '__QUERY' },\n ],\n },\n ],\n author: [\n {\n label: 'Writing by __QUERY',\n facets: [\n { facetType: 'mediatype', bucketKey: 'texts' },\n { facetType: 'creator', bucketKey: '__QUERY' },\n ],\n },\n ],\n writer: [\n {\n label: 'Writing by __QUERY',\n facets: [\n { facetType: 'mediatype', bucketKey: 'texts' },\n { facetType: 'creator', bucketKey: '__QUERY' },\n ],\n },\n ],\n poet: [\n {\n label: 'Writing by __QUERY',\n facets: [\n { facetType: 'mediatype', bucketKey: 'texts' },\n { facetType: 'creator', bucketKey: '__QUERY' },\n ],\n },\n ],\n photographer: [\n {\n label: 'Images by __QUERY',\n facets: [\n { facetType: 'mediatype', bucketKey: 'image' },\n { facetType: 'creator', bucketKey: '__QUERY' },\n ],\n },\n ],\n painter: [\n {\n label: 'Images by __QUERY',\n facets: [\n { facetType: 'mediatype', bucketKey: 'image' },\n { facetType: 'creator', bucketKey: '__QUERY' },\n ],\n },\n ],\n singer: [\n {\n label: 'Music by __QUERY',\n facets: [\n { facetType: 'mediatype', bucketKey: 'audio' },\n { facetType: 'creator', bucketKey: '__QUERY' },\n ],\n },\n ],\n songwriter: [\n {\n label: 'Music by __QUERY',\n facets: [\n { facetType: 'mediatype', bucketKey: 'audio' },\n { facetType: 'creator', bucketKey: '__QUERY' },\n ],\n },\n ],\n musician: [\n {\n label: 'Music by __QUERY',\n facets: [\n { facetType: 'mediatype', bucketKey: 'audio' },\n { facetType: 'creator', bucketKey: '__QUERY' },\n ],\n },\n ],\n };\n\n async getRecommendedFacets(query: string): Promise<SmartFacet[]> {\n const recommendations: SmartFacet[] = [];\n\n try {\n const urlQuery = encodeURIComponent(query);\n\n const wikidataResponse = await fetch(\n `https://www.wikidata.org/w/api.php?action=wbsearchentities&search=${urlQuery}&format=json&language=en&uselang=en&origin=*&type=item&limit=5`\n );\n const searchResults = await wikidataResponse.json();\n\n for (const [keyword, facets] of Object.entries(\n WikidataHeuristic.ENTITIES\n )) {\n const keywordRegex = new RegExp('\\\\b' + keyword + '\\\\b');\n if (keywordRegex.test(searchResults.search[0]?.description)) {\n const entityName = searchResults.search[0].label;\n recommendations.push(\n ...facets.map(\n sf =>\n ({\n label: sf.label?.replace('__QUERY', entityName),\n facets: sf.facets.map(f => {\n const replaced = {\n ...f,\n bucketKey: f.bucketKey.replace('__QUERY', query),\n };\n\n if (f.displayText) {\n replaced.displayText = replaced.displayText?.replace(\n '__QUERY',\n entityName\n );\n }\n\n return replaced;\n }),\n } as SmartFacet)\n )\n );\n }\n }\n\n return recommendations;\n } catch (err) {\n return [];\n }\n }\n}\n"]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { LitElement, CSSResultGroup, nothing } from 'lit';
|
|
2
2
|
import type { IaDropdown } from '@internetarchive/ia-dropdown';
|
|
3
|
-
import type {
|
|
3
|
+
import type { FacetRef, SmartFacet } from './models';
|
|
4
4
|
export declare class SmartFacetDropdown extends LitElement {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
facetInfo?: SmartFacet[];
|
|
6
|
+
labelPrefix?: string;
|
|
7
|
+
activeFacetRef?: FacetRef;
|
|
8
8
|
dropdown?: IaDropdown;
|
|
9
9
|
render(): import("lit-html").TemplateResult<1> | typeof nothing;
|
|
10
10
|
private get dropdownOptions();
|
|
@@ -6,12 +6,12 @@ let SmartFacetDropdown = class SmartFacetDropdown extends LitElement {
|
|
|
6
6
|
// COMPONENT LIFECYCLE METHODS
|
|
7
7
|
//
|
|
8
8
|
render() {
|
|
9
|
-
var _a;
|
|
10
|
-
if (!this.
|
|
9
|
+
var _a, _b;
|
|
10
|
+
if (!this.facetInfo || !this.activeFacetRef)
|
|
11
11
|
return nothing;
|
|
12
|
-
if (this.
|
|
12
|
+
if (this.facetInfo.length === 0)
|
|
13
13
|
return nothing;
|
|
14
|
-
const displayText = (_a = this.
|
|
14
|
+
const displayText = (_a = this.activeFacetRef.displayText) !== null && _a !== void 0 ? _a : this.activeFacetRef.bucketKey;
|
|
15
15
|
if (!displayText)
|
|
16
16
|
return nothing;
|
|
17
17
|
return html `
|
|
@@ -27,7 +27,7 @@ let SmartFacetDropdown = class SmartFacetDropdown extends LitElement {
|
|
|
27
27
|
@optionSelected=${this.optionSelected}
|
|
28
28
|
>
|
|
29
29
|
<span class="dropdown-label" slot="dropdown-label"
|
|
30
|
-
>${displayText}</span
|
|
30
|
+
>${(_b = this.labelPrefix) !== null && _b !== void 0 ? _b : nothing} ${displayText}</span
|
|
31
31
|
>
|
|
32
32
|
</ia-dropdown>
|
|
33
33
|
</div>
|
|
@@ -38,29 +38,45 @@ let SmartFacetDropdown = class SmartFacetDropdown extends LitElement {
|
|
|
38
38
|
//
|
|
39
39
|
get dropdownOptions() {
|
|
40
40
|
var _a, _b;
|
|
41
|
-
return ((_b = (_a = this.
|
|
42
|
-
var _a;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
return ((_b = (_a = this.facetInfo) === null || _a === void 0 ? void 0 : _a.map(smartFacet => {
|
|
42
|
+
var _a, _b;
|
|
43
|
+
const firstFacet = smartFacet.facets[0];
|
|
44
|
+
return {
|
|
45
|
+
id: firstFacet.bucketKey,
|
|
46
|
+
label: (_b = (_a = smartFacet.label) !== null && _a !== void 0 ? _a : firstFacet.displayText) !== null && _b !== void 0 ? _b : firstFacet.bucketKey,
|
|
47
|
+
};
|
|
47
48
|
})) !== null && _b !== void 0 ? _b : []);
|
|
48
49
|
}
|
|
49
50
|
get activeDropdownOption() {
|
|
50
|
-
if (!this.
|
|
51
|
+
if (!this.activeFacetRef)
|
|
51
52
|
return undefined;
|
|
52
|
-
return this.dropdownOptions.find(opt => { var _a; return opt.id === ((_a = this.
|
|
53
|
+
return this.dropdownOptions.find(opt => { var _a; return opt.id === ((_a = this.activeFacetRef) === null || _a === void 0 ? void 0 : _a.bucketKey); });
|
|
53
54
|
}
|
|
54
55
|
optionSelected(e) {
|
|
55
|
-
|
|
56
|
+
if (!this.facetInfo || !this.activeFacetRef)
|
|
57
|
+
return;
|
|
58
|
+
let selectedSmartFacet;
|
|
59
|
+
for (const smartFacet of this.facetInfo) {
|
|
60
|
+
const selectedRef = smartFacet.facets.find(b => b.bucketKey === e.detail.option.id);
|
|
61
|
+
if (selectedRef) {
|
|
62
|
+
this.activeFacetRef = selectedRef;
|
|
63
|
+
selectedSmartFacet = smartFacet;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (!selectedSmartFacet)
|
|
67
|
+
return;
|
|
56
68
|
this.dispatchEvent(new CustomEvent('facetClick', {
|
|
57
69
|
detail: {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
70
|
+
smartFacet: selectedSmartFacet,
|
|
71
|
+
details: [{
|
|
72
|
+
facetType: this.activeFacetRef.facetType,
|
|
73
|
+
bucket: {
|
|
74
|
+
key: this.activeFacetRef.bucketKey,
|
|
75
|
+
count: 0,
|
|
76
|
+
state: 'selected',
|
|
77
|
+
},
|
|
78
|
+
negative: false,
|
|
79
|
+
}],
|
|
64
80
|
},
|
|
65
81
|
}));
|
|
66
82
|
}
|
|
@@ -93,15 +109,15 @@ let SmartFacetDropdown = class SmartFacetDropdown extends LitElement {
|
|
|
93
109
|
`;
|
|
94
110
|
}
|
|
95
111
|
};
|
|
96
|
-
__decorate([
|
|
97
|
-
property({ type: String })
|
|
98
|
-
], SmartFacetDropdown.prototype, "facetType", void 0);
|
|
99
112
|
__decorate([
|
|
100
113
|
property({ type: Array })
|
|
101
|
-
], SmartFacetDropdown.prototype, "
|
|
114
|
+
], SmartFacetDropdown.prototype, "facetInfo", void 0);
|
|
115
|
+
__decorate([
|
|
116
|
+
property({ type: String })
|
|
117
|
+
], SmartFacetDropdown.prototype, "labelPrefix", void 0);
|
|
102
118
|
__decorate([
|
|
103
119
|
property({ type: Object })
|
|
104
|
-
], SmartFacetDropdown.prototype, "
|
|
120
|
+
], SmartFacetDropdown.prototype, "activeFacetRef", void 0);
|
|
105
121
|
__decorate([
|
|
106
122
|
query('ia-dropdown')
|
|
107
123
|
], SmartFacetDropdown.prototype, "dropdown", void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"smart-facet-dropdown.js","sourceRoot":"","sources":["../../../../src/collection-facets/smart-facets/smart-facet-dropdown.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAkB,OAAO,EAAE,MAAM,KAAK,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAKnE,IAAa,kBAAkB,GAA/B,MAAa,kBAAmB,SAAQ,UAAU;IAShD,EAAE;IACF,8BAA8B;IAC9B,EAAE;IAEF,MAAM;;QACJ,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"smart-facet-dropdown.js","sourceRoot":"","sources":["../../../../src/collection-facets/smart-facets/smart-facet-dropdown.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, CSSResultGroup, nothing } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport type { IaDropdown, optionInterface } from '@internetarchive/ia-dropdown';\nimport type { FacetRef, SmartFacet, SmartFacetEvent } from './models';\n\n@customElement('smart-facet-dropdown')\nexport class SmartFacetDropdown extends LitElement {\n @property({ type: Array }) facetInfo?: SmartFacet[];\n\n @property({ type: String }) labelPrefix?: string;\n\n @property({ type: Object }) activeFacetRef?: FacetRef;\n\n @query('ia-dropdown') dropdown?: IaDropdown;\n\n //\n // COMPONENT LIFECYCLE METHODS\n //\n\n render() {\n if (!this.facetInfo || !this.activeFacetRef) return nothing;\n if (this.facetInfo.length === 0) return nothing;\n\n const displayText = this.activeFacetRef.displayText ?? this.activeFacetRef.bucketKey;\n if (!displayText) return nothing;\n\n return html`\n <div class=\"dropdown-container\">\n <ia-dropdown\n class=\"dropdown\"\n displayCaret\n openViaButton\n closeOnSelect\n includeSelectedOption\n .options=${this.dropdownOptions}\n .selectedOption=${this.activeDropdownOption}\n @optionSelected=${this.optionSelected}\n >\n <span class=\"dropdown-label\" slot=\"dropdown-label\"\n >${this.labelPrefix ?? nothing} ${displayText}</span\n >\n </ia-dropdown>\n </div>\n `;\n }\n\n //\n // OTHER METHODS\n //\n\n private get dropdownOptions(): optionInterface[] {\n return (\n this.facetInfo?.map(smartFacet => {\n const firstFacet = smartFacet.facets[0];\n return {\n id: firstFacet.bucketKey,\n label: smartFacet.label ?? firstFacet.displayText ?? firstFacet.bucketKey,\n };\n }) ?? []\n );\n }\n\n private get activeDropdownOption(): optionInterface | undefined {\n if (!this.activeFacetRef) return undefined;\n return this.dropdownOptions.find(opt => opt.id === this.activeFacetRef?.bucketKey);\n }\n\n private optionSelected(e: CustomEvent<{ option: optionInterface }>): void {\n if (!this.facetInfo || !this.activeFacetRef) return;\n\n let selectedSmartFacet;\n for (const smartFacet of this.facetInfo) {\n const selectedRef = smartFacet.facets.find(b => b.bucketKey === e.detail.option.id);\n if (selectedRef) {\n this.activeFacetRef = selectedRef;\n selectedSmartFacet = smartFacet;\n }\n }\n\n if (!selectedSmartFacet) return;\n\n this.dispatchEvent(\n new CustomEvent<SmartFacetEvent>('facetClick', {\n detail: {\n smartFacet: selectedSmartFacet,\n details: [{\n facetType: this.activeFacetRef.facetType,\n bucket: {\n key: this.activeFacetRef.bucketKey,\n count: 0,\n state: 'selected',\n },\n negative: false,\n }],\n },\n })\n );\n }\n\n //\n // STYLES\n //\n\n static get styles(): CSSResultGroup {\n return css`\n .dropdown-container {\n padding: 5px 8px;\n border-radius: 5px;\n background: #194880;\n color: white;\n font-size: 1.6rem;\n font-family: inherit;\n box-shadow: 1px 1px rgba(0, 0, 0, 0.4);\n }\n\n .dropdown-label {\n font-size: 1.6rem;\n font-family: inherit;\n }\n\n .dropdown {\n --dropdownBorderWidth: 5px;\n --dropdownBorderColor: transparent;\n --caretWidth: 14px;\n --caretHeight: 14px;\n }\n `;\n }\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
function facetRefEquals(ref1, ref2) {
|
|
2
|
+
if (ref1 === undefined)
|
|
3
|
+
return ref2 !== undefined;
|
|
4
|
+
if (ref2 === undefined)
|
|
5
|
+
return ref1 !== undefined;
|
|
6
|
+
return ref1.facetType === ref2.facetType &&
|
|
7
|
+
ref1.bucketKey === ref2.bucketKey &&
|
|
8
|
+
ref1.displayText === ref2.displayText;
|
|
9
|
+
}
|
|
10
|
+
export function smartFacetEquals(sf1, sf2) {
|
|
11
|
+
return sf1.label === sf2.label &&
|
|
12
|
+
sf1.facets.length === sf2.facets.length &&
|
|
13
|
+
sf1.facets.every((sf, i) => facetRefEquals(sf, sf2.facets[i]));
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=smart-facet-equals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smart-facet-equals.js","sourceRoot":"","sources":["../../../../src/collection-facets/smart-facets/smart-facet-equals.ts"],"names":[],"mappings":"AAEA,SAAS,cAAc,CAAC,IAAe,EAAE,IAAe;IACtD,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,KAAK,SAAS,CAAC;IAClD,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,KAAK,SAAS,CAAC;IAElD,OAAO,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,SAAS;QACtC,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,SAAS;QACjC,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC,WAAW,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAe,EAAE,GAAe;IAC/D,OAAO,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,KAAK;QAC5B,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,MAAM;QACvC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC","sourcesContent":["import type { FacetRef, SmartFacet } from \"./models\";\n\nfunction facetRefEquals(ref1?: FacetRef, ref2?: FacetRef): boolean {\n if (ref1 === undefined) return ref2 !== undefined;\n if (ref2 === undefined) return ref1 !== undefined;\n \n return ref1.facetType === ref2.facetType &&\n ref1.bucketKey === ref2.bucketKey &&\n ref1.displayText === ref2.displayText;\n}\n\nexport function smartFacetEquals(sf1: SmartFacet, sf2: SmartFacet) {\n return sf1.label === sf2.label &&\n sf1.facets.length === sf2.facets.length &&\n sf1.facets.every((sf, i) => facetRefEquals(sf, sf2.facets[i]));\n}"]}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import type { SmartFacet, SmartQueryHeuristic } from './models';
|
|
2
2
|
export declare class SmartQueryHeuristicGroup implements SmartQueryHeuristic {
|
|
3
3
|
getRecommendedFacets(query: string): Promise<SmartFacet[]>;
|
|
4
|
+
/**
|
|
5
|
+
* Removes any duplicated smart facets from the given array.
|
|
6
|
+
* Smart facets are equal if they have the same `label` and same
|
|
7
|
+
* set of facet refs. Only the first occurrence of a given smart
|
|
8
|
+
* facet is kept.
|
|
9
|
+
* @param facets The array of smart facets to deduplicate
|
|
10
|
+
* @returns A new array containing the deduplicated set of facets
|
|
11
|
+
*/
|
|
12
|
+
private dedupe;
|
|
4
13
|
}
|
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
import { QueryKeywordsHeuristic } from './heuristics/query-keywords-heuristic';
|
|
2
|
-
import {
|
|
2
|
+
import { WikidataHeuristic } from './heuristics/wikidata-heuristic';
|
|
3
|
+
import { smartFacetEquals } from './smart-facet-equals';
|
|
3
4
|
export class SmartQueryHeuristicGroup {
|
|
4
5
|
async getRecommendedFacets(query) {
|
|
5
|
-
return [
|
|
6
|
+
return this.dedupe([
|
|
6
7
|
...(await new QueryKeywordsHeuristic().getRecommendedFacets(query)),
|
|
7
|
-
...(await new
|
|
8
|
-
];
|
|
8
|
+
...(await new WikidataHeuristic().getRecommendedFacets(query)),
|
|
9
|
+
]);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Removes any duplicated smart facets from the given array.
|
|
13
|
+
* Smart facets are equal if they have the same `label` and same
|
|
14
|
+
* set of facet refs. Only the first occurrence of a given smart
|
|
15
|
+
* facet is kept.
|
|
16
|
+
* @param facets The array of smart facets to deduplicate
|
|
17
|
+
* @returns A new array containing the deduplicated set of facets
|
|
18
|
+
*/
|
|
19
|
+
dedupe(facets) {
|
|
20
|
+
let result = [...facets];
|
|
21
|
+
for (const curFacet of facets) {
|
|
22
|
+
result = result.filter(sf => curFacet === sf || !smartFacetEquals(curFacet, sf));
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
9
25
|
}
|
|
10
26
|
}
|
|
11
27
|
//# sourceMappingURL=smart-facet-heuristics.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"smart-facet-heuristics.js","sourceRoot":"","sources":["../../../../src/collection-facets/smart-facets/smart-facet-heuristics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"smart-facet-heuristics.js","sourceRoot":"","sources":["../../../../src/collection-facets/smart-facets/smart-facet-heuristics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAEpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,OAAO,wBAAwB;IACnC,KAAK,CAAC,oBAAoB,CAAC,KAAa;QACtC,OAAO,IAAI,CAAC,MAAM,CAAC;YACjB,GAAG,CAAC,MAAM,IAAI,sBAAsB,EAAE,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;YACnE,GAAG,CAAC,MAAM,IAAI,iBAAiB,EAAE,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;SAC/D,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACK,MAAM,CAAC,MAAoB;QACjC,IAAI,MAAM,GAAiB,CAAC,GAAG,MAAM,CAAC,CAAC;QACvC,KAAK,MAAM,QAAQ,IAAI,MAAM,EAAE;YAC7B,MAAM,GAAG,MAAM,CAAC,MAAM,CACpB,EAAE,CAAC,EAAE,CAAC,QAAQ,KAAK,EAAE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,EAAE,CAAC,CACzD,CAAC;SACH;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF","sourcesContent":["import { QueryKeywordsHeuristic } from './heuristics/query-keywords-heuristic';\nimport { WikidataHeuristic } from './heuristics/wikidata-heuristic';\nimport type { SmartFacet, SmartQueryHeuristic } from './models';\nimport { smartFacetEquals } from './smart-facet-equals';\n\nexport class SmartQueryHeuristicGroup implements SmartQueryHeuristic {\n async getRecommendedFacets(query: string): Promise<SmartFacet[]> {\n return this.dedupe([\n ...(await new QueryKeywordsHeuristic().getRecommendedFacets(query)),\n ...(await new WikidataHeuristic().getRecommendedFacets(query)),\n ]);\n }\n\n /**\n * Removes any duplicated smart facets from the given array.\n * Smart facets are equal if they have the same `label` and same\n * set of facet refs. Only the first occurrence of a given smart\n * facet is kept.\n * @param facets The array of smart facets to deduplicate\n * @returns A new array containing the deduplicated set of facets\n */\n private dedupe(facets: SmartFacet[]): SmartFacet[] {\n let result: SmartFacet[] = [...facets];\n for (const curFacet of facets) {\n result = result.filter(\n sf => curFacet === sf || !smartFacetEquals(curFacet, sf)\n );\n }\n return result;\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "The Internet Archive Collection Browser.",
|
|
4
4
|
"license": "AGPL-3.0-only",
|
|
5
5
|
"author": "Internet Archive",
|
|
6
|
-
"version": "2.7.2-alpha.
|
|
6
|
+
"version": "2.7.2-alpha.2",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"module": "dist/index.js",
|
|
9
9
|
"scripts": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@internetarchive/search-service": "^1.4.0",
|
|
35
35
|
"@internetarchive/shared-resize-observer": "^0.2.0",
|
|
36
36
|
"@lit/localize": "^0.11.2",
|
|
37
|
-
"dompurify": "^2.
|
|
37
|
+
"dompurify": "^2.5.7",
|
|
38
38
|
"eslint-plugin-lit": "^1.6.1",
|
|
39
39
|
"lit": "^2.2.2",
|
|
40
40
|
"typescript-cookie": "^1.0.3"
|
|
@@ -4,7 +4,7 @@ import type {
|
|
|
4
4
|
SmartFacet,
|
|
5
5
|
} from '../models';
|
|
6
6
|
|
|
7
|
-
// If wikidata
|
|
7
|
+
// If wikidata describes the top query result as X, recommend facet Y, e.g.:
|
|
8
8
|
// X Y
|
|
9
9
|
// written work mt:texts
|
|
10
10
|
// film mt:movies
|
|
@@ -12,9 +12,13 @@ import type {
|
|
|
12
12
|
// filmmaker mt:movies and creator:<query>
|
|
13
13
|
// photographer mt:image and creator:<query>
|
|
14
14
|
// visual artist mt:image and creator:<query>
|
|
15
|
-
|
|
15
|
+
// etc.
|
|
16
|
+
export class WikidataHeuristic implements SmartQueryHeuristic {
|
|
16
17
|
private static readonly ENTITIES: KeywordFacetMap = {
|
|
18
|
+
'written work': [{ facets: [{ facetType: 'mediatype', bucketKey: 'texts' }] }],
|
|
17
19
|
literature: [{ facets: [{ facetType: 'mediatype', bucketKey: 'texts' }] }],
|
|
20
|
+
book: [{ facets: [{ facetType: 'mediatype', bucketKey: 'texts' }] }],
|
|
21
|
+
novel: [{ facets: [{ facetType: 'mediatype', bucketKey: 'texts' }] }],
|
|
18
22
|
filmmaker: [
|
|
19
23
|
{
|
|
20
24
|
label: 'Films by __QUERY',
|
|
@@ -110,9 +114,10 @@ export class WikidataEntityHeuristic implements SmartQueryHeuristic {
|
|
|
110
114
|
const searchResults = await wikidataResponse.json();
|
|
111
115
|
|
|
112
116
|
for (const [keyword, facets] of Object.entries(
|
|
113
|
-
|
|
117
|
+
WikidataHeuristic.ENTITIES
|
|
114
118
|
)) {
|
|
115
|
-
|
|
119
|
+
const keywordRegex = new RegExp('\\b' + keyword + '\\b');
|
|
120
|
+
if (keywordRegex.test(searchResults.search[0]?.description)) {
|
|
116
121
|
const entityName = searchResults.search[0].label;
|
|
117
122
|
recommendations.push(
|
|
118
123
|
...facets.map(
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { css, html, LitElement, CSSResultGroup, nothing } from 'lit';
|
|
2
2
|
import { customElement, property, query } from 'lit/decorators.js';
|
|
3
3
|
import type { IaDropdown, optionInterface } from '@internetarchive/ia-dropdown';
|
|
4
|
-
import type {
|
|
4
|
+
import type { FacetRef, SmartFacet, SmartFacetEvent } from './models';
|
|
5
5
|
|
|
6
6
|
@customElement('smart-facet-dropdown')
|
|
7
7
|
export class SmartFacetDropdown extends LitElement {
|
|
8
|
-
@property({ type:
|
|
8
|
+
@property({ type: Array }) facetInfo?: SmartFacet[];
|
|
9
9
|
|
|
10
|
-
@property({ type:
|
|
10
|
+
@property({ type: String }) labelPrefix?: string;
|
|
11
11
|
|
|
12
|
-
@property({ type: Object })
|
|
12
|
+
@property({ type: Object }) activeFacetRef?: FacetRef;
|
|
13
13
|
|
|
14
14
|
@query('ia-dropdown') dropdown?: IaDropdown;
|
|
15
15
|
|
|
@@ -18,10 +18,10 @@ export class SmartFacetDropdown extends LitElement {
|
|
|
18
18
|
//
|
|
19
19
|
|
|
20
20
|
render() {
|
|
21
|
-
if (!this.
|
|
22
|
-
if (this.
|
|
21
|
+
if (!this.facetInfo || !this.activeFacetRef) return nothing;
|
|
22
|
+
if (this.facetInfo.length === 0) return nothing;
|
|
23
23
|
|
|
24
|
-
const displayText = this.
|
|
24
|
+
const displayText = this.activeFacetRef.displayText ?? this.activeFacetRef.bucketKey;
|
|
25
25
|
if (!displayText) return nothing;
|
|
26
26
|
|
|
27
27
|
return html`
|
|
@@ -37,7 +37,7 @@ export class SmartFacetDropdown extends LitElement {
|
|
|
37
37
|
@optionSelected=${this.optionSelected}
|
|
38
38
|
>
|
|
39
39
|
<span class="dropdown-label" slot="dropdown-label"
|
|
40
|
-
>${displayText}</span
|
|
40
|
+
>${this.labelPrefix ?? nothing} ${displayText}</span
|
|
41
41
|
>
|
|
42
42
|
</ia-dropdown>
|
|
43
43
|
</div>
|
|
@@ -50,28 +50,48 @@ export class SmartFacetDropdown extends LitElement {
|
|
|
50
50
|
|
|
51
51
|
private get dropdownOptions(): optionInterface[] {
|
|
52
52
|
return (
|
|
53
|
-
this.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
this.facetInfo?.map(smartFacet => {
|
|
54
|
+
const firstFacet = smartFacet.facets[0];
|
|
55
|
+
return {
|
|
56
|
+
id: firstFacet.bucketKey,
|
|
57
|
+
label: smartFacet.label ?? firstFacet.displayText ?? firstFacet.bucketKey,
|
|
58
|
+
};
|
|
59
|
+
}) ?? []
|
|
57
60
|
);
|
|
58
61
|
}
|
|
59
62
|
|
|
60
63
|
private get activeDropdownOption(): optionInterface | undefined {
|
|
61
|
-
if (!this.
|
|
62
|
-
return this.dropdownOptions.find(opt => opt.id === this.
|
|
64
|
+
if (!this.activeFacetRef) return undefined;
|
|
65
|
+
return this.dropdownOptions.find(opt => opt.id === this.activeFacetRef?.bucketKey);
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
private optionSelected(e: CustomEvent<{ option: optionInterface }>): void {
|
|
69
|
+
if (!this.facetInfo || !this.activeFacetRef) return;
|
|
70
|
+
|
|
71
|
+
let selectedSmartFacet;
|
|
72
|
+
for (const smartFacet of this.facetInfo) {
|
|
73
|
+
const selectedRef = smartFacet.facets.find(b => b.bucketKey === e.detail.option.id);
|
|
74
|
+
if (selectedRef) {
|
|
75
|
+
this.activeFacetRef = selectedRef;
|
|
76
|
+
selectedSmartFacet = smartFacet;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!selectedSmartFacet) return;
|
|
81
|
+
|
|
66
82
|
this.dispatchEvent(
|
|
67
|
-
new CustomEvent('facetClick', {
|
|
83
|
+
new CustomEvent<SmartFacetEvent>('facetClick', {
|
|
68
84
|
detail: {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
85
|
+
smartFacet: selectedSmartFacet,
|
|
86
|
+
details: [{
|
|
87
|
+
facetType: this.activeFacetRef.facetType,
|
|
88
|
+
bucket: {
|
|
89
|
+
key: this.activeFacetRef.bucketKey,
|
|
90
|
+
count: 0,
|
|
91
|
+
state: 'selected',
|
|
92
|
+
},
|
|
93
|
+
negative: false,
|
|
94
|
+
}],
|
|
75
95
|
},
|
|
76
96
|
})
|
|
77
97
|
);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { FacetRef, SmartFacet } from "./models";
|
|
2
|
+
|
|
3
|
+
function facetRefEquals(ref1?: FacetRef, ref2?: FacetRef): boolean {
|
|
4
|
+
if (ref1 === undefined) return ref2 !== undefined;
|
|
5
|
+
if (ref2 === undefined) return ref1 !== undefined;
|
|
6
|
+
|
|
7
|
+
return ref1.facetType === ref2.facetType &&
|
|
8
|
+
ref1.bucketKey === ref2.bucketKey &&
|
|
9
|
+
ref1.displayText === ref2.displayText;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function smartFacetEquals(sf1: SmartFacet, sf2: SmartFacet) {
|
|
13
|
+
return sf1.label === sf2.label &&
|
|
14
|
+
sf1.facets.length === sf2.facets.length &&
|
|
15
|
+
sf1.facets.every((sf, i) => facetRefEquals(sf, sf2.facets[i]));
|
|
16
|
+
}
|
|
@@ -1,12 +1,31 @@
|
|
|
1
1
|
import { QueryKeywordsHeuristic } from './heuristics/query-keywords-heuristic';
|
|
2
|
-
import {
|
|
2
|
+
import { WikidataHeuristic } from './heuristics/wikidata-heuristic';
|
|
3
3
|
import type { SmartFacet, SmartQueryHeuristic } from './models';
|
|
4
|
+
import { smartFacetEquals } from './smart-facet-equals';
|
|
4
5
|
|
|
5
6
|
export class SmartQueryHeuristicGroup implements SmartQueryHeuristic {
|
|
6
7
|
async getRecommendedFacets(query: string): Promise<SmartFacet[]> {
|
|
7
|
-
return [
|
|
8
|
+
return this.dedupe([
|
|
8
9
|
...(await new QueryKeywordsHeuristic().getRecommendedFacets(query)),
|
|
9
|
-
...(await new
|
|
10
|
-
];
|
|
10
|
+
...(await new WikidataHeuristic().getRecommendedFacets(query)),
|
|
11
|
+
]);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Removes any duplicated smart facets from the given array.
|
|
16
|
+
* Smart facets are equal if they have the same `label` and same
|
|
17
|
+
* set of facet refs. Only the first occurrence of a given smart
|
|
18
|
+
* facet is kept.
|
|
19
|
+
* @param facets The array of smart facets to deduplicate
|
|
20
|
+
* @returns A new array containing the deduplicated set of facets
|
|
21
|
+
*/
|
|
22
|
+
private dedupe(facets: SmartFacet[]): SmartFacet[] {
|
|
23
|
+
let result: SmartFacet[] = [...facets];
|
|
24
|
+
for (const curFacet of facets) {
|
|
25
|
+
result = result.filter(
|
|
26
|
+
sf => curFacet === sf || !smartFacetEquals(curFacet, sf)
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
11
30
|
}
|
|
12
31
|
}
|