mediawiki-skins-Citizen/resources/skins.citizen.search/searchClients/mwRestApi.js
2023-08-03 21:01:21 -04:00

123 lines
3 KiB
JavaScript

/** @module mwRestApiSearchClient */
const fetchJson = require( '../fetch.js' );
const urlGenerator = require( '../urlGenerator.js' );
/**
* @typedef {Object} RestResponse
* @property {RestResult[]} pages
*/
/**
* @typedef {Object} RestResult
* @property {number} id
* @property {string} key
* @property {string} title
* @property {string | null } matched_title
* @property {string} [description]
* @property {RestThumbnail | null} [thumbnail]
*/
/**
* @typedef {Object} RestThumbnail
* @property {string} url
* @property {number | null} [width]
* @property {number | null} [height]
*/
/**
* @typedef {Object} SearchResponse
* @property {string} query
* @property {SearchResult[]} results
*/
/**
* @param {MwMap} config
* @param {string} query
* @param {Object} response
* @param {boolean} showDescription
* @return {SearchResponse}
*/
function adaptApiResponse( config, query, response, showDescription ) {
const urlGeneratorInstance = urlGenerator( config );
return {
query,
results: response.pages.map( ( page ) => {
const thumbnail = page.thumbnail;
return {
id: page.id,
label: page.matched_title || page.title,
key: page.key,
title: page.title,
description: showDescription ? page.description : undefined,
url: urlGeneratorInstance.generateUrl( page ),
thumbnail: thumbnail ? {
url: thumbnail.url,
width: thumbnail.width ?? undefined,
height: thumbnail.height ?? undefined
} : undefined
};
} )
};
}
/**
* @typedef {Object} AbortableSearchFetch
* @property {Promise<SearchResponse>} fetch
* @property {Function} abort
*/
/**
* @callback fetchByTitle
* @param {string} query The search term.
* @param {number} [limit] Maximum number of results.
* @return {AbortableSearchFetch}
*/
/**
* @callback loadMore
* @param {string} query The search term.
* @param {number} offset The number of search results that were already loaded.
* @param {number} [limit] How many further search results to load (at most).
* @return {AbortableSearchFetch}
*/
/**
* @typedef {Object} SearchClient
* @property {fetchByTitle} fetchByTitle
* @property {loadMore} [loadMore]
*/
/**
* @param {MwMap} config
* @return {SearchClient}
*/
function mwRestApiSearchClient( config ) {
return {
/**
* @type {fetchByTitle}
*/
fetchByTitle: ( q, limit = config.wgCitizenMaxSearchResults, showDescription = true ) => {
const searchApiUrl = config.wgScriptPath + '/rest.php';
const params = { q, limit: limit.toString() };
const search = new URLSearchParams( params );
const url = `${searchApiUrl}/v1/search/title?${search.toString()}`;
const result = fetchJson( url, {
headers: {
accept: 'application/json'
}
} );
const searchResponsePromise = result.fetch
.then( ( /** @type {RestResponse} */ res ) => {
return adaptApiResponse( config, q, res, showDescription );
} );
return {
abort: result.abort,
fetch: searchResponsePromise
};
}
};
}
module.exports = mwRestApiSearchClient;