mirror of
https://github.com/StarCitizenTools/mediawiki-skins-Citizen.git
synced 2024-11-15 02:24:04 +00:00
refactor: improve search loading indicator behavior
This commit is contained in:
parent
546fa36d33
commit
4bbb59f978
|
@ -243,17 +243,12 @@ window.WMTypeAhead = function ( appendTo, searchInput ) {
|
|||
|
||||
callbackIndex = window.callbackStack.addCallback( window.portalOpensearchCallback );
|
||||
|
||||
// Add loading animation when suggestion is loading
|
||||
appendEl.classList.add( 'search-form__loading' );
|
||||
|
||||
// Check if use REST API
|
||||
if ( useREST ) {
|
||||
fetch(`${scriptPath}/rest.php/v1/search/title?q=${searchString}&limit=${maxSearchResults}`)
|
||||
.then(async function (response) {
|
||||
var data = await response.json();
|
||||
clearTypeAheadElements();
|
||||
// Clean up loading animation after result ls loaded
|
||||
appendEl.classList.remove( 'search-form__loading' );
|
||||
window.callbackStack.queue[ callbackIndex ]( data, string );
|
||||
} );
|
||||
} else {
|
||||
|
@ -296,8 +291,6 @@ window.WMTypeAhead = function ( appendTo, searchInput ) {
|
|||
api.get( searchQuery )
|
||||
.done( ( data ) => {
|
||||
clearTypeAheadElements();
|
||||
// Clean up loading animation after result ls loaded
|
||||
appendEl.classList.remove( 'search-form__loading' );
|
||||
window.callbackStack.queue[ callbackIndex ]( data, string );
|
||||
} );
|
||||
}
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
/* Some of the functions are based on Vector */
|
||||
/* ESLint does not like having class names as const */
|
||||
/* eslint-disable mediawiki/class-doc */
|
||||
const SEARCH_INPUT_ID = 'searchInput',
|
||||
SEARCH_LOADING_CLASS = 'search-form__loading';
|
||||
|
||||
/**
|
||||
* Based on Vector
|
||||
* Loads the search module via `mw.loader.using` on the element's
|
||||
* focus event. Or, if the element is already focused, loads the
|
||||
* search module immediately.
|
||||
|
@ -23,6 +28,59 @@ function loadSearchModule( element, moduleName, afterLoadFn ) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event callback that shows or hides the loading indicator based on the event type.
|
||||
* The loading indicator states are:
|
||||
* 1. Show on input event (while user is typing)
|
||||
* 2. Hide on focusout event (when user removes focus from the input )
|
||||
* 3. Show when input is focused, if it contains a query. (in case user re-focuses on input)
|
||||
*
|
||||
* @param {Event} event
|
||||
*/
|
||||
function renderSearchLoadingIndicator( event ) {
|
||||
const form = /** @type {HTMLElement} */ ( event.currentTarget ),
|
||||
input = /** @type {HTMLInputElement} */ ( event.target );
|
||||
|
||||
if (
|
||||
!( event.currentTarget instanceof HTMLElement ) ||
|
||||
!( event.target instanceof HTMLInputElement ) ||
|
||||
!( input.id === SEARCH_INPUT_ID ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( event.type === 'input' ) {
|
||||
form.classList.add( SEARCH_LOADING_CLASS );
|
||||
|
||||
} else if ( event.type === 'focusout' ) {
|
||||
form.classList.remove( SEARCH_LOADING_CLASS );
|
||||
|
||||
} else if ( event.type === 'focusin' && input.value.trim() ) {
|
||||
form.classList.add( SEARCH_LOADING_CLASS );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches or detaches the event listeners responsible for activating
|
||||
* the loading indicator.
|
||||
*
|
||||
* @param {HTMLElement} element
|
||||
* @param {boolean} attach
|
||||
* @param {function(Event): void} eventCallback
|
||||
*/
|
||||
function setLoadingIndicatorListeners( element, attach, eventCallback ) {
|
||||
|
||||
/** @type { "addEventListener" | "removeEventListener" } */
|
||||
const addOrRemoveListener = ( attach ? 'addEventListener' : 'removeEventListener' );
|
||||
|
||||
[ 'input', 'focusin', 'focusout' ].forEach( function ( eventType ) {
|
||||
element[ addOrRemoveListener ]( eventType, eventCallback );
|
||||
} );
|
||||
|
||||
if ( !attach ) {
|
||||
element.classList.remove( SEARCH_LOADING_CLASS );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually focus on the input field if checkbox is checked
|
||||
*
|
||||
|
@ -64,13 +122,13 @@ function bindExpandOnSlash( window, checkbox, input ) {
|
|||
/**
|
||||
* @param {Window} window
|
||||
* @param {HTMLInputElement} input
|
||||
* @param {HTMLElement} target
|
||||
* @return {void}
|
||||
*/
|
||||
function initCheckboxHack( window, input ) {
|
||||
function initCheckboxHack( window, input, target ) {
|
||||
const checkboxHack = require( './checkboxHack.js' ),
|
||||
button = document.getElementById( 'search-toggle' ),
|
||||
checkbox = document.getElementById( 'search-checkbox' ),
|
||||
target = document.getElementById( 'searchform' );
|
||||
checkbox = document.getElementById( 'search-checkbox' );
|
||||
|
||||
if ( checkbox instanceof HTMLInputElement && button ) {
|
||||
checkboxHack.bindToggleOnClick( checkbox, button );
|
||||
|
@ -95,12 +153,16 @@ function initCheckboxHack( window, input ) {
|
|||
* @return {void}
|
||||
*/
|
||||
function initSearch( window ) {
|
||||
const searchInput = document.getElementById( 'searchInput' );
|
||||
const searchForm = document.getElementById( 'searchform' ),
|
||||
searchInput = document.getElementById( SEARCH_INPUT_ID );
|
||||
|
||||
initCheckboxHack( window, searchInput );
|
||||
initCheckboxHack( window, searchInput, searchForm );
|
||||
|
||||
if ( mw.config.get( 'wgCitizenEnableSearch' ) ) {
|
||||
loadSearchModule( searchInput, 'skins.citizen.scripts.search', () => {} );
|
||||
setLoadingIndicatorListeners( searchForm, true, renderSearchLoadingIndicator );
|
||||
loadSearchModule( searchInput, 'skins.citizen.scripts.search', () => {
|
||||
setLoadingIndicatorListeners( searchForm, false, renderSearchLoadingIndicator );
|
||||
} );
|
||||
} else {
|
||||
loadSearchModule( searchInput, 'mediawiki.searchSuggest', () => {} );
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue