MediaWiki:Common.js
From zunagi
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/* 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();
}
} );
} );