Update backend format for search; Delay cover image load
This commit is contained in:
parent
63c7d3676d
commit
8283c1987a
|
@ -6,7 +6,8 @@ import { modal } from '../partials/modal';
|
||||||
|
|
||||||
export const resultDetails = (searchController, result, emit = () => {}) => {
|
export const resultDetails = (searchController, result, emit = () => {}) => {
|
||||||
const { __ } = searchController.i18n;
|
const { __ } = searchController.i18n;
|
||||||
const modalId = `result_${result.uri}`;
|
const source = result.sources[0];
|
||||||
|
const modalId = `result_${source.uri}`;
|
||||||
|
|
||||||
const hasReviews = typeof result.averageRating !== 'undefined' && typeof result.numberOfReviews !== 'undefined';
|
const hasReviews = typeof result.averageRating !== 'undefined' && typeof result.numberOfReviews !== 'undefined';
|
||||||
|
|
||||||
|
@ -27,37 +28,41 @@ export const resultDetails = (searchController, result, emit = () => {}) => {
|
||||||
|
|
||||||
const tabNames = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen', 'twenty'];
|
const tabNames = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen', 'twenty'];
|
||||||
|
|
||||||
|
const coversHTMLArray = result.covers.map((cover, index, allCovers) => {
|
||||||
|
return html`<div>
|
||||||
|
<img src=${cover.url} alt="${cover.sourceId.replace(':', ' ').toUpperCase()}, Published: ${cover.publishDate}">
|
||||||
|
${typeof allCovers[index - 1] === 'undefined'
|
||||||
|
? null
|
||||||
|
: html`<label class="button" for="cover_${allCovers[index - 1].sourceId}" style="margin-right:8px;">
|
||||||
|
${'<'}
|
||||||
|
</label>`
|
||||||
|
}
|
||||||
|
${typeof allCovers[index + 1] === 'undefined'
|
||||||
|
? null
|
||||||
|
: html`<label class="button" for="cover_${allCovers[index + 1].sourceId}">
|
||||||
|
${'>'}
|
||||||
|
</label>`
|
||||||
|
}
|
||||||
|
</div>`;
|
||||||
|
});
|
||||||
|
|
||||||
const modalContent = html`<article class="flex">
|
const modalContent = html`<article class="flex">
|
||||||
<div class="sixth-700" style="text-align:center;">
|
<div class="sixth-700" style="text-align:center;">
|
||||||
<h4>${__('search.covers')}</h4>
|
<h4>${__('search.covers')}</h4>
|
||||||
${typeof result.covers === 'undefined'
|
${typeof result.covers === 'undefined'
|
||||||
? html`<span style="font-size:3em;"><i class="icon-loading animate-spin"></i></span>`
|
? html`<span style="font-size:3em;"><i class="icon-loading animate-spin"></i></span>`
|
||||||
: html`<div class="tabs ${typeof tabNames[result.covers.length - 1] !== 'undefined' ? tabNames[result.covers.length - 1] : null}">
|
: html`<div class="tabs ${typeof tabNames[result.covers.length - 1] !== 'undefined' ? tabNames[result.covers.length - 1] : tabNames[19]}">
|
||||||
${result.covers.map((cover, index) => {
|
${result.covers.map((cover, index) => {
|
||||||
return [
|
return [
|
||||||
html`<input id="cover_${cover.uri}" type="radio" name="${modalId}_covers" ${index === 0 ? 'checked' : null} />`,
|
html`<input id="cover_${cover.sourceId}" type="radio" name="${modalId}_covers" ${index === 0 ? 'checked' : null} />`,
|
||||||
// html`<label class="small pseudo button toggle" for="cover_${cover.uri}">•</label>`,
|
// html`<label class="small pseudo button toggle" for="cover_${cover.sourceId}">•</label>`,
|
||||||
];
|
];
|
||||||
})}
|
})}
|
||||||
<div class="row">
|
<div class="row" id="covers_${modalId}">${
|
||||||
${result.covers.map((cover, index, allCovers) => {
|
searchController.openModal === modalId
|
||||||
return html`<div>
|
? coversHTMLArray
|
||||||
<img src=${cover.url} alt="${cover.uri.replace(':', ' ').toUpperCase()}, Published: ${cover.publishDate}">
|
: '' /* Leave the covers column empty until opened to prevent loading too many images */
|
||||||
${typeof allCovers[index - 1] === 'undefined'
|
}</div>
|
||||||
? null
|
|
||||||
: html`<label class="button" for="cover_${allCovers[index - 1].uri}" style="margin-right:8px;">
|
|
||||||
${'<'}
|
|
||||||
</label>`
|
|
||||||
}
|
|
||||||
${typeof allCovers[index + 1] === 'undefined'
|
|
||||||
? null
|
|
||||||
: html`<label class="button" for="cover_${allCovers[index + 1].uri}">
|
|
||||||
${'>'}
|
|
||||||
</label>`
|
|
||||||
}
|
|
||||||
</div>`;
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>`
|
</div>`
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
@ -72,7 +77,7 @@ export const resultDetails = (searchController, result, emit = () => {}) => {
|
||||||
<h4>Top Reviews</h4>
|
<h4>Top Reviews</h4>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="/book/${result.uri}" class="small button">
|
<a href="/book/${source.uri}" class="small button">
|
||||||
<span style="margin-right:8px;"><i class="icon-chat"></i></span>
|
<span style="margin-right:8px;"><i class="icon-chat"></i></span>
|
||||||
<span>${result.numberOfReviews}</span>
|
<span>${result.numberOfReviews}</span>
|
||||||
<span>${__('search.see_interaction_details')}</span>
|
<span>${__('search.see_interaction_details')}</span>
|
||||||
|
@ -92,27 +97,29 @@ export const resultDetails = (searchController, result, emit = () => {}) => {
|
||||||
</p>
|
</p>
|
||||||
${!searchController.showShelves ? null : html`<ul>${searchController.shelves.map(shelf => {
|
${!searchController.showShelves ? null : html`<ul>${searchController.shelves.map(shelf => {
|
||||||
return html`<li>
|
return html`<li>
|
||||||
<button class="pseudo" onclick=${() => searchController.addToShelf({source: 'inventaire', uri: result.uri}, shelf.id)}>
|
<button class="pseudo" onclick=${() => searchController.addToShelf({ id: result.id, ...source }, shelf.id)}>
|
||||||
${shelf.name}
|
${shelf.name}
|
||||||
</button>
|
</button>
|
||||||
</li>`;
|
</li>`;
|
||||||
})}</ul>`}
|
})}</ul>`}
|
||||||
<p>
|
<p>
|
||||||
<a class="small button" href=${result.link} target="_blank">
|
<a class="small button" href=${source.link} target="_blank">
|
||||||
${__('search.see_book_details')}
|
${__('search.see_book_details')}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</article>`;
|
</article>`;
|
||||||
|
|
||||||
|
const onShow = () => {
|
||||||
|
const coversColumn = document.getElementById(`covers_${modalId}`);
|
||||||
|
coversColumn.innerHTML = '';
|
||||||
|
coversHTMLArray.forEach(element => coversColumn.appendChild(element));
|
||||||
|
};
|
||||||
|
|
||||||
return modal(modalId, searchController, modalContent, {
|
return modal(modalId, searchController, modalContent, {
|
||||||
styles: "width:90%;",
|
styles: "width:90%;",
|
||||||
buttonHTML, // This should be replaced with buttonHTML containing the ratings and number of reviews etc.
|
buttonHTML, // This should be replaced with buttonHTML containing the ratings and number of reviews etc.
|
||||||
headerText: result.name,
|
headerText: result.name,
|
||||||
onShow: () => {
|
onShow,
|
||||||
if (typeof result.covers === 'undefined') {
|
|
||||||
searchController.getCovers(result.uri).then(() => emit('render'));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -15,6 +15,7 @@ class Inventaire {
|
||||||
|
|
||||||
static handleQuickEntity(entityObject) {
|
static handleQuickEntity(entityObject) {
|
||||||
return {
|
return {
|
||||||
|
id: null,
|
||||||
name: (
|
name: (
|
||||||
typeof entityObject.label !== 'undefined'
|
typeof entityObject.label !== 'undefined'
|
||||||
? entityObject.label
|
? entityObject.label
|
||||||
|
@ -25,22 +26,26 @@ class Inventaire {
|
||||||
? entityObject.description
|
? entityObject.description
|
||||||
: null
|
: null
|
||||||
),
|
),
|
||||||
source: 'inventaire',
|
sources: [
|
||||||
link: (
|
{
|
||||||
typeof entityObject.uri !== 'undefined'
|
source: 'inventaire',
|
||||||
? `${Inventaire.url}/entity/${entityObject.uri}`
|
uri: (
|
||||||
: null
|
typeof entityObject.uri !== 'undefined'
|
||||||
),
|
? entityObject.uri
|
||||||
uri: (
|
: null
|
||||||
typeof entityObject.uri !== 'undefined'
|
),
|
||||||
? entityObject.uri
|
link: (
|
||||||
: null
|
typeof entityObject.uri !== 'undefined'
|
||||||
),
|
? `${Inventaire.url}/entity/${entityObject.uri}`
|
||||||
|
: null
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
covers: (
|
covers: (
|
||||||
typeof entityObject.image !== 'undefined'
|
typeof entityObject.image !== 'undefined'
|
||||||
? entityObject.image.map(imageId => {
|
? entityObject.image.map(imageId => {
|
||||||
return {
|
return {
|
||||||
uri: imageId.toString(),
|
sourceId: imageId.toString(),
|
||||||
url: `${Inventaire.url}/img/entities/${imageId}`,
|
url: `${Inventaire.url}/img/entities/${imageId}`,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -72,17 +77,21 @@ class Inventaire {
|
||||||
: null
|
: null
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
source: 'inventaire',
|
sources: [
|
||||||
link: (
|
{
|
||||||
typeof entityObject.uri !== 'undefined'
|
source: 'inventaire',
|
||||||
? `${Inventaire.url}/entity/${entityObject.uri}`
|
uri: (
|
||||||
: null
|
typeof entityObject.uri !== 'undefined'
|
||||||
),
|
? entityObject.uri
|
||||||
uri: (
|
: null
|
||||||
typeof entityObject.uri !== 'undefined'
|
),
|
||||||
? entityObject.uri
|
link: (
|
||||||
: null
|
typeof entityObject.uri !== 'undefined'
|
||||||
),
|
? `${Inventaire.url}/entity/${entityObject.uri}`
|
||||||
|
: null
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +118,7 @@ class Inventaire {
|
||||||
|
|
||||||
if (typeof bookData.entities !== 'undefined' && typeof bookData.entities[uri] !== 'undefined') {
|
if (typeof bookData.entities !== 'undefined' && typeof bookData.entities[uri] !== 'undefined') {
|
||||||
bookData = Inventaire.handleEntity(bookData.entities[uri], this.lang);
|
bookData = Inventaire.handleEntity(bookData.entities[uri], this.lang);
|
||||||
bookData['covers'] = await this.getCovers(bookData.uri);
|
bookData['covers'] = await this.getCovers(bookData.sources[0].uri);
|
||||||
|
|
||||||
return bookData;
|
return bookData;
|
||||||
}
|
}
|
||||||
|
@ -126,7 +135,7 @@ class Inventaire {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: property `wdt:P629` is a given entity (uri)'s list of editions (ISBNs).
|
// Note: property `wdt:P629` is a given entity (uri)'s list of editions (ISBNs).
|
||||||
const editionsRequest = fetch(`${Inventaire.url}/api/entities?action=reverse-claims&uri=${encodeURIComponent(uri)}&property=wdt:P629`)
|
const editionsRequest = fetch(`${Inventaire.url}/api/entities?action=reverse-claims&value=${encodeURIComponent(uri)}&property=wdt:P629`)
|
||||||
editionsRequest.catch(exception => {
|
editionsRequest.catch(exception => {
|
||||||
console.error(exception);
|
console.error(exception);
|
||||||
return {
|
return {
|
||||||
|
@ -180,7 +189,7 @@ class Inventaire {
|
||||||
}).map(key => {
|
}).map(key => {
|
||||||
const entity = responseJSON.entities[key];
|
const entity = responseJSON.entities[key];
|
||||||
return {
|
return {
|
||||||
uri: entity.uri,
|
sourceId: entity.uri,
|
||||||
url: typeof entity.claims['invp:P2'] !== 'undefined' ? `${Inventaire.url}/img/entities/${entity.claims['invp:P2'][0]}` : null,
|
url: typeof entity.claims['invp:P2'] !== 'undefined' ? `${Inventaire.url}/img/entities/${entity.claims['invp:P2'][0]}` : null,
|
||||||
publishDate: typeof entity.claims['wdt:P577'] !== 'undefined' ? entity.claims['wdt:P577'][0] : null,
|
publishDate: typeof entity.claims['wdt:P577'] !== 'undefined' ? entity.claims['wdt:P577'][0] : null,
|
||||||
}
|
}
|
||||||
|
@ -193,7 +202,10 @@ class Inventaire {
|
||||||
return a.publishDate < b.publishDate ? -1 : 1;
|
return a.publishDate < b.publishDate ? -1 : 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
return covers;
|
return covers.map(cover => {
|
||||||
|
delete cover.publishDate;
|
||||||
|
return cover;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ class BookReferenceController {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get formatted book data from source
|
// Get formatted book data from source
|
||||||
const bookData = dataClass.getBookData(sourceId);
|
const bookData = await dataClass.getBookData(sourceId);
|
||||||
|
|
||||||
if (typeof bookData.uri !== 'undefined') {
|
if (typeof bookData.uri !== 'undefined') {
|
||||||
// Check for references by exact name and author from source
|
// Check for references by exact name and author from source
|
||||||
|
|
|
@ -43,7 +43,14 @@ function searchInventaire(searchTerm, language) {
|
||||||
message: 'An error occurred when trying read the response from Inventaire as JSON.',
|
message: 'An error occurred when trying read the response from Inventaire as JSON.',
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return json.then(responseJSON => responseJSON.results.map(work => Inventaire.handleEntity(work, language)));
|
return json.then(responseJSON => {
|
||||||
|
return responseJSON.results.map(async work => {
|
||||||
|
const inventaire = new Inventaire(langauge);
|
||||||
|
const bookData = Inventaire.handleEntity(work, language);
|
||||||
|
bookData['covers'] = await inventaire.getCovers(bookData.sources[0].uri);
|
||||||
|
return bookData;
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ const { Op, fn, col } = require('sequelize');
|
||||||
|
|
||||||
const BooksController = require('../bookData');
|
const BooksController = require('../bookData');
|
||||||
const { quickSearchInventaire } = require('./Inventaire');
|
const { quickSearchInventaire } = require('./Inventaire');
|
||||||
|
const Inventaire = require('../bookData/Inventaire');
|
||||||
|
|
||||||
const defaultSearchOptions = {
|
const defaultSearchOptions = {
|
||||||
searchBy: 'name', // A column name in the BookReference model, mainly 'name' or 'description'
|
searchBy: 'name', // A column name in the BookReference model, mainly 'name' or 'description'
|
||||||
|
@ -57,6 +58,30 @@ class SearchController {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static formatReferenceSources(reference) {
|
||||||
|
const referenceSources = Object.keys(reference.sources);
|
||||||
|
const reformattedSources = referenceSources.map(source => {
|
||||||
|
const uri = reference.sources[source];
|
||||||
|
let link;
|
||||||
|
switch (source) {
|
||||||
|
default:
|
||||||
|
case 'inventaire': {
|
||||||
|
link = `${Inventaire.url}/entity/${uri}`
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
source,
|
||||||
|
uri,
|
||||||
|
link,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
reference.sources = reformattedSources;
|
||||||
|
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
|
||||||
async search(searchTerm, options = defaultSearchOptions) {
|
async search(searchTerm, options = defaultSearchOptions) {
|
||||||
const searchBy = options.searchBy.replace('title', 'name').replace('author', 'description');
|
const searchBy = options.searchBy.replace('title', 'name').replace('author', 'description');
|
||||||
const { source, language } = options;
|
const { source, language } = options;
|
||||||
|
@ -77,22 +102,23 @@ class SearchController {
|
||||||
|
|
||||||
// Add any search results that match refs with the same URI and delete from results array
|
// Add any search results that match refs with the same URI and delete from results array
|
||||||
const urisToCheck = searchResults.filter(
|
const urisToCheck = searchResults.filter(
|
||||||
result => !bookReferences.some(ref => result.uri === ref.sources[source])
|
result => !bookReferences.some(ref => result.sources[0].uri === ref.sources[source])
|
||||||
).map(result => result.uri);
|
).map(result => result.sources[0].uri);
|
||||||
|
|
||||||
let extraReferences = [];
|
let extraReferences = [];
|
||||||
if (urisToCheck.length > 0) {
|
if (urisToCheck.length > 0) {
|
||||||
// Need to figure this out
|
// Need to figure this out
|
||||||
extraReferences = await this.searchReferencesBySourceCodes(source, urisToCheck);
|
extraReferences = await this.searchReferencesBySourceCodes(source, urisToCheck);
|
||||||
}
|
}
|
||||||
|
searchResults = searchResults.filter( // Only show the rest of the search results
|
||||||
|
result => !extraReferences.some(
|
||||||
|
ref => result.sources[0].uri === ref.sources[source]
|
||||||
|
)
|
||||||
|
);
|
||||||
return [
|
return [
|
||||||
...bookReferences,
|
...bookReferences.map(match => SearchController.formatReferenceSources(match)),
|
||||||
...extraReferences,
|
...extraReferences.map(match => SearchController.formatReferenceSources(match)),
|
||||||
...searchResults.filter( // Only show the rest of the search results
|
...searchResults,
|
||||||
result => !extraReferences.some(
|
|
||||||
ref => result.uri === ref.sources[source]
|
|
||||||
)
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue