refactor(core): ♻️ move some suggestion functions to searchResults

This commit is contained in:
alistair3149 2024-05-22 00:03:49 -04:00
parent 434ec2ebaf
commit ae7a01f690
No known key found for this signature in database
2 changed files with 71 additions and 53 deletions

View file

@ -2,8 +2,77 @@
// const htmlHelper = require( './htmlHelper.js' )(); // const htmlHelper = require( './htmlHelper.js' )();
const searchAction = require( './searchAction.js' )(); const searchAction = require( './searchAction.js' )();
/**
* Returns an object with methods related to search results handling.
*
* @return {Object} An object with the following methods:
* - getRedirectLabel: A function that generates HTML for a search result label with redirection information.
* - highlightTitle: A function that highlights a matched title within a given text.
* - fetch: A function that fetches search results based on a query value using an active search client.
* - render: A function that renders search results in a specified typeahead element.
* - clear: A function that clears search results from a typeahead element.
*/
function searchResults() { function searchResults() {
return { return {
getRedirectLabel: function ( title, matchedTitle, queryValue ) {
const normalizeText = ( text ) => {
return text.replace( /[-\s]/g, ( match ) => match.toLowerCase() ).toLowerCase();
};
const redirectMessageCache = {};
const getRedirectMessage = () => {
if ( !redirectMessageCache[ matchedTitle ] ) {
redirectMessageCache[ matchedTitle ] = mw.message( 'search-redirect', matchedTitle ).plain();
}
return redirectMessageCache[ matchedTitle ];
};
const isRedirectUseful = () => {
const cleanTitle = normalizeText( title );
const cleanMatchedTitle = normalizeText( matchedTitle );
return !(
cleanTitle.includes( cleanMatchedTitle ) ||
cleanMatchedTitle.includes( cleanTitle )
);
};
const generateRedirectHtml = () => {
const div = document.createElement( 'div' );
div.classList.add( 'citizen-typeahead__labelItem' );
div.title = getRedirectMessage( matchedTitle );
const spanIcon = document.createElement( 'span' );
spanIcon.classList.add( 'citizen-ui-icon', 'mw-ui-icon-wikimedia-articleRedirect' );
div.appendChild( spanIcon );
const spanText = document.createElement( 'span' );
spanText.textContent = this.highlightTitle( matchedTitle, queryValue );
div.appendChild( spanText );
return div.outerHTML;
};
let html = '';
if ( matchedTitle && isRedirectUseful() ) {
html = generateRedirectHtml();
}
return html;
},
highlightTitle: ( function () {
const regexCache = {};
return function ( title, match ) {
if ( !match ) {
return title;
}
if ( !regexCache[ match ] ) {
regexCache[ match ] = new RegExp( mw.util.escapeRegExp( match ), 'i' );
}
const regex = regexCache[ match ];
return title.replace( regex, '<span class="citizen-typeahead__highlight">$&</span>' );
};
}() ),
fetch: function ( queryValue, activeSearchClient ) { fetch: function ( queryValue, activeSearchClient ) {
return activeSearchClient.fetchByTitle( queryValue ); return activeSearchClient.fetchByTitle( queryValue );
}, },

View file

@ -344,57 +344,6 @@ async function getSuggestions() {
const renderSuggestions = ( results ) => { const renderSuggestions = ( results ) => {
const fragment = document.createDocumentFragment(); const fragment = document.createDocumentFragment();
if ( results.length > 0 ) { if ( results.length > 0 ) {
/**
* Return the redirect title with search query highlight
*
* @param {string} text
* @return {string}
*/
const highlightTitle = ( text ) => {
const regex = new RegExp( mw.util.escapeRegExp( searchQuery.valueHtml ), 'i' );
return text.replace( regex, `<span class="${ PREFIX }__highlight">$&</span>` );
};
/**
* Return the HTML of the redirect label
*
* @param {string} title
* @param {string} matchedTitle
* @return {string}
*/
const getRedirectLabel = ( title, matchedTitle ) => {
/**
* Check if the redirect is useful (T303013)
*
* @return {boolean}
*/
const isRedirectUseful = () => {
// Change to lowercase then remove space and dashes
const cleanup = ( text ) => {
return text.toLowerCase().replace( /[-\s]/g, '' );
};
const
cleanTitle = cleanup( title ),
cleanMatchedTitle = cleanup( matchedTitle );
return !(
cleanTitle.includes( cleanMatchedTitle ) ||
cleanMatchedTitle.includes( cleanTitle )
);
};
let html = '';
// Result is a redirect
// Show the redirect title and highlight it
if ( matchedTitle && isRedirectUseful() ) {
html = `<div class="${ PREFIX }__labelItem" title="${ mw.message( 'search-redirect', matchedTitle ).plain() }">
<span class="citizen-ui-icon mw-ui-icon-wikimedia-articleRedirect"></span>
<span>${ highlightTitle( matchedTitle ) }</span>
</div>`;
}
return html;
};
// Create suggestion items // Create suggestion items
const itemGroupData = { const itemGroupData = {
id: 'suggestion', id: 'suggestion',
@ -405,10 +354,10 @@ async function getSuggestions() {
type: 'page', type: 'page',
size: 'md', size: 'md',
link: result.url, link: result.url,
title: highlightTitle( result.title ), title: searchResults.highlightTitle( result.title, searchQuery.valueHtml ),
desc: result.description desc: result.description
}; };
data.label = getRedirectLabel( result.title, result.label ); data.label = searchResults.getRedirectLabel( result.title, result.label );
if ( result.thumbnail ) { if ( result.thumbnail ) {
data.thumbnail = result.thumbnail.url; data.thumbnail = result.thumbnail.url;
} else { } else {