Update backend format for search; Delay cover image load

This commit is contained in:
Robbie Antenesse 2020-08-24 15:16:14 -06:00
parent 63c7d3676d
commit 8283c1987a
5 changed files with 121 additions and 69 deletions

View File

@ -6,7 +6,8 @@ import { modal } from '../partials/modal';
export const resultDetails = (searchController, result, emit = () => {}) => {
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';
@ -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 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">
<div class="sixth-700" style="text-align:center;">
<h4>${__('search.covers')}</h4>
${typeof result.covers === 'undefined'
? 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) => {
return [
html`<input id="cover_${cover.uri}" type="radio" name="${modalId}_covers" ${index === 0 ? 'checked' : null} />`,
// html`<label class="small pseudo button toggle" for="cover_${cover.uri}">•</label>`,
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.sourceId}">•</label>`,
];
})}
<div class="row">
${result.covers.map((cover, index, allCovers) => {
return html`<div>
<img src=${cover.url} alt="${cover.uri.replace(':', ' ').toUpperCase()}, Published: ${cover.publishDate}">
${typeof allCovers[index - 1] === 'undefined'
? 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 class="row" id="covers_${modalId}">${
searchController.openModal === modalId
? coversHTMLArray
: '' /* Leave the covers column empty until opened to prevent loading too many images */
}</div>
</div>`
}
</div>
@ -72,7 +77,7 @@ export const resultDetails = (searchController, result, emit = () => {}) => {
<h4>Top Reviews</h4>
</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>${result.numberOfReviews}</span>
<span>${__('search.see_interaction_details')}</span>
@ -92,27 +97,29 @@ export const resultDetails = (searchController, result, emit = () => {}) => {
</p>
${!searchController.showShelves ? null : html`<ul>${searchController.shelves.map(shelf => {
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}
</button>
</li>`;
})}</ul>`}
<p>
<a class="small button" href=${result.link} target="_blank">
<a class="small button" href=${source.link} target="_blank">
${__('search.see_book_details')}
</a>
</p>
</div>
</article>`;
const onShow = () => {
const coversColumn = document.getElementById(`covers_${modalId}`);
coversColumn.innerHTML = '';
coversHTMLArray.forEach(element => coversColumn.appendChild(element));
};
return modal(modalId, searchController, modalContent, {
styles: "width:90%;",
buttonHTML, // This should be replaced with buttonHTML containing the ratings and number of reviews etc.
headerText: result.name,
onShow: () => {
if (typeof result.covers === 'undefined') {
searchController.getCovers(result.uri).then(() => emit('render'));
}
},
onShow,
});
}

View File

@ -15,6 +15,7 @@ class Inventaire {
static handleQuickEntity(entityObject) {
return {
id: null,
name: (
typeof entityObject.label !== 'undefined'
? entityObject.label
@ -25,22 +26,26 @@ class Inventaire {
? entityObject.description
: null
),
source: 'inventaire',
link: (
typeof entityObject.uri !== 'undefined'
? `${Inventaire.url}/entity/${entityObject.uri}`
: null
),
uri: (
typeof entityObject.uri !== 'undefined'
? entityObject.uri
: null
),
sources: [
{
source: 'inventaire',
uri: (
typeof entityObject.uri !== 'undefined'
? entityObject.uri
: null
),
link: (
typeof entityObject.uri !== 'undefined'
? `${Inventaire.url}/entity/${entityObject.uri}`
: null
),
},
],
covers: (
typeof entityObject.image !== 'undefined'
? entityObject.image.map(imageId => {
return {
uri: imageId.toString(),
sourceId: imageId.toString(),
url: `${Inventaire.url}/img/entities/${imageId}`,
}
})
@ -72,17 +77,21 @@ class Inventaire {
: null
)
),
source: 'inventaire',
link: (
typeof entityObject.uri !== 'undefined'
? `${Inventaire.url}/entity/${entityObject.uri}`
: null
),
uri: (
typeof entityObject.uri !== 'undefined'
? entityObject.uri
: null
),
sources: [
{
source: 'inventaire',
uri: (
typeof entityObject.uri !== 'undefined'
? entityObject.uri
: null
),
link: (
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') {
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;
}
@ -126,7 +135,7 @@ class Inventaire {
}
// 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 => {
console.error(exception);
return {
@ -180,7 +189,7 @@ class Inventaire {
}).map(key => {
const entity = responseJSON.entities[key];
return {
uri: entity.uri,
sourceId: entity.uri,
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,
}
@ -193,7 +202,10 @@ class Inventaire {
return a.publishDate < b.publishDate ? -1 : 1;
});
return covers;
return covers.map(cover => {
delete cover.publishDate;
return cover;
});
});
}
}

View File

@ -28,7 +28,7 @@ class BookReferenceController {
}
// Get formatted book data from source
const bookData = dataClass.getBookData(sourceId);
const bookData = await dataClass.getBookData(sourceId);
if (typeof bookData.uri !== 'undefined') {
// Check for references by exact name and author from source

View File

@ -43,7 +43,14 @@ function searchInventaire(searchTerm, language) {
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;
});
});
}
}

View File

@ -3,6 +3,7 @@ const { Op, fn, col } = require('sequelize');
const BooksController = require('../bookData');
const { quickSearchInventaire } = require('./Inventaire');
const Inventaire = require('../bookData/Inventaire');
const defaultSearchOptions = {
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) {
const searchBy = options.searchBy.replace('title', 'name').replace('author', 'description');
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
const urisToCheck = searchResults.filter(
result => !bookReferences.some(ref => result.uri === ref.sources[source])
).map(result => result.uri);
result => !bookReferences.some(ref => result.sources[0].uri === ref.sources[source])
).map(result => result.sources[0].uri);
let extraReferences = [];
if (urisToCheck.length > 0) {
// Need to figure this out
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 [
...bookReferences,
...extraReferences,
...searchResults.filter( // Only show the rest of the search results
result => !extraReferences.some(
ref => result.uri === ref.sources[source]
)
),
...bookReferences.map(match => SearchController.formatReferenceSources(match)),
...extraReferences.map(match => SearchController.formatReferenceSources(match)),
...searchResults,
];
}