MediaWiki:Common.js: Difference between revisions
From zunagi
Created page with "→Any JavaScript here will be loaded for all users on every page load.: $( function () { const input = document.getElementById( 'zunagi-search-input' ); const box = document.getElementById( 'zunagi-search-suggestions' ); if ( !input || !box ) { return; } let timer = null; let requestNumber = 0; function closeSuggestions() { box.innerHTML = ''; box.classList.remove( 'is-open' ); } function openArticle( tit..." |
mNo edit summary |
||
| Line 1: | Line 1: | ||
/* Any JavaScript here will be loaded for all users on every page load. */ | /* Any JavaScript here will be loaded for all users on every page load. */ | ||
$( function () { | $( function () { | ||
const | const form = document.getElementById( 'zunagi-search-form' ); | ||
const box = document.getElementById( 'zunagi-search-suggestions' ); | const box = document.getElementById( 'zunagi-search-suggestions' ); | ||
if ( ! | if ( !form || !box ) { | ||
return; | |||
} | |||
const input = form.querySelector( | |||
'input[type="search"], input[name="search"], input[name="searchText"]' | |||
); | |||
if ( !input ) { | |||
return; | return; | ||
} | } | ||
| Line 10: | Line 18: | ||
let timer = null; | let timer = null; | ||
let requestNumber = 0; | let requestNumber = 0; | ||
let selectedIndex = -1; | |||
let results = []; | |||
function closeSuggestions() { | function closeSuggestions() { | ||
box.innerHTML = ''; | box.innerHTML = ''; | ||
box.classList.remove( 'is-open' ); | box.classList.remove( 'is-open' ); | ||
selectedIndex = -1; | |||
results = []; | |||
} | } | ||
function | function openPage( title ) { | ||
window.location.href = mw.util.getUrl( title ); | window.location.href = mw.util.getUrl( title ); | ||
} | } | ||
function | function stripHtml( html ) { | ||
const element = document.createElement( 'div' ); | |||
element.innerHTML = html; | |||
return element.textContent || ''; | |||
} | |||
function renderSuggestions( pages ) { | |||
box.innerHTML = ''; | box.innerHTML = ''; | ||
results = pages; | |||
selectedIndex = -1; | |||
if ( ! | if ( !pages.length ) { | ||
closeSuggestions(); | closeSuggestions(); | ||
return; | return; | ||
} | } | ||
pages.forEach( function ( page ) { | |||
const link = document.createElement( 'a' ); | const link = document.createElement( 'a' ); | ||
const title = document.createElement( 'span' ); | |||
const description = document.createElement( 'span' ); | |||
link.href = mw.util.getUrl( title ); | link.href = mw.util.getUrl( page.title ); | ||
link.className = 'zunagi-search-suggestion'; | link.className = 'zunagi-search-suggestion'; | ||
title.className = 'zunagi-search-suggestion-title'; | |||
title.textContent = page.title; | |||
} | description.className = 'zunagi-search-suggestion-description'; | ||
description.textContent = stripHtml( page.snippet || '' ); | |||
link.appendChild( title ); | |||
if ( description.textContent ) { | |||
link.appendChild( description ); | |||
} | |||
box.appendChild( link ); | box.appendChild( link ); | ||
| Line 44: | Line 72: | ||
box.classList.add( 'is-open' ); | box.classList.add( 'is-open' ); | ||
} | |||
function updateSelection() { | |||
const items = box.querySelectorAll( '.zunagi-search-suggestion' ); | |||
items.forEach( function ( item, index ) { | |||
item.classList.toggle( | |||
'is-selected', | |||
index === selectedIndex | |||
); | |||
} ); | |||
} | } | ||
| Line 62: | Line 101: | ||
new mw.Api().get( { | new mw.Api().get( { | ||
action: ' | action: 'query', | ||
search: query, | list: 'search', | ||
srsearch: query, | |||
srnamespace: 0, | |||
srlimit: 8, | |||
srprop: 'snippet', | |||
format: 'json' | format: 'json' | ||
} ).done( function ( data ) { | } ).done( function ( data ) { | ||
| Line 72: | Line 113: | ||
} | } | ||
renderSuggestions( | |||
} ).fail( closeSuggestions ); | data.query && data.query.search | ||
}, | ? data.query.search | ||
: [] | |||
); | |||
} ).fail( function () { | |||
closeSuggestions(); | |||
} ); | |||
}, 300 ); | |||
} ); | } ); | ||
input.addEventListener( 'keydown', function ( event ) { | input.addEventListener( 'keydown', function ( event ) { | ||
if ( event.key === 'Escape' ) { | const items = box.querySelectorAll( | ||
'.zunagi-search-suggestion' | |||
); | |||
if ( event.key === 'ArrowDown' && items.length ) { | |||
event.preventDefault(); | |||
selectedIndex = | |||
( selectedIndex + 1 ) % items.length; | |||
updateSelection(); | |||
} else if ( event.key === 'ArrowUp' && items.length ) { | |||
event.preventDefault(); | |||
selectedIndex = | |||
selectedIndex <= 0 | |||
? items.length - 1 | |||
: selectedIndex - 1; | |||
updateSelection(); | |||
} else if ( | |||
event.key === 'Enter' && | |||
selectedIndex >= 0 && | |||
results[ selectedIndex ] | |||
) { | |||
event.preventDefault(); | |||
openPage( results[ selectedIndex ].title ); | |||
} else if ( event.key === 'Escape' ) { | |||
closeSuggestions(); | closeSuggestions(); | ||
} | } | ||
| Line 85: | Line 155: | ||
document.addEventListener( 'click', function ( event ) { | document.addEventListener( 'click', function ( event ) { | ||
if ( | if ( | ||
event.target | !form.contains( event.target ) && | ||
!box.contains( event.target ) | !box.contains( event.target ) | ||
) { | ) { | ||
Revision as of 14:03, 11 July 2026
/* Any JavaScript here will be loaded for all users on every page load. */
$( function () {
const form = document.getElementById( 'zunagi-search-form' );
const box = document.getElementById( 'zunagi-search-suggestions' );
if ( !form || !box ) {
return;
}
const input = form.querySelector(
'input[type="search"], input[name="search"], input[name="searchText"]'
);
if ( !input ) {
return;
}
let timer = null;
let requestNumber = 0;
let selectedIndex = -1;
let results = [];
function closeSuggestions() {
box.innerHTML = '';
box.classList.remove( 'is-open' );
selectedIndex = -1;
results = [];
}
function openPage( title ) {
window.location.href = mw.util.getUrl( title );
}
function stripHtml( html ) {
const element = document.createElement( 'div' );
element.innerHTML = html;
return element.textContent || '';
}
function renderSuggestions( pages ) {
box.innerHTML = '';
results = pages;
selectedIndex = -1;
if ( !pages.length ) {
closeSuggestions();
return;
}
pages.forEach( function ( page ) {
const link = document.createElement( 'a' );
const title = document.createElement( 'span' );
const description = document.createElement( 'span' );
link.href = mw.util.getUrl( page.title );
link.className = 'zunagi-search-suggestion';
title.className = 'zunagi-search-suggestion-title';
title.textContent = page.title;
description.className = 'zunagi-search-suggestion-description';
description.textContent = stripHtml( page.snippet || '' );
link.appendChild( title );
if ( description.textContent ) {
link.appendChild( description );
}
box.appendChild( link );
} );
box.classList.add( 'is-open' );
}
function updateSelection() {
const items = box.querySelectorAll( '.zunagi-search-suggestion' );
items.forEach( function ( item, index ) {
item.classList.toggle(
'is-selected',
index === selectedIndex
);
} );
}
input.setAttribute( 'autocomplete', 'off' );
input.addEventListener( 'input', function () {
const query = input.value.trim();
clearTimeout( timer );
if ( query.length < 2 ) {
closeSuggestions();
return;
}
timer = setTimeout( function () {
const thisRequest = ++requestNumber;
new mw.Api().get( {
action: 'query',
list: 'search',
srsearch: query,
srnamespace: 0,
srlimit: 8,
srprop: 'snippet',
format: 'json'
} ).done( function ( data ) {
if ( thisRequest !== requestNumber ) {
return;
}
renderSuggestions(
data.query && data.query.search
? data.query.search
: []
);
} ).fail( function () {
closeSuggestions();
} );
}, 300 );
} );
input.addEventListener( 'keydown', function ( event ) {
const items = box.querySelectorAll(
'.zunagi-search-suggestion'
);
if ( event.key === 'ArrowDown' && items.length ) {
event.preventDefault();
selectedIndex =
( selectedIndex + 1 ) % items.length;
updateSelection();
} else if ( event.key === 'ArrowUp' && items.length ) {
event.preventDefault();
selectedIndex =
selectedIndex <= 0
? items.length - 1
: selectedIndex - 1;
updateSelection();
} else if (
event.key === 'Enter' &&
selectedIndex >= 0 &&
results[ selectedIndex ]
) {
event.preventDefault();
openPage( results[ selectedIndex ].title );
} else if ( event.key === 'Escape' ) {
closeSuggestions();
}
} );
document.addEventListener( 'click', function ( event ) {
if (
!form.contains( event.target ) &&
!box.contains( event.target )
) {
closeSuggestions();
}
} );
} );