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 input = document.getElementById( 'zunagi-search-input' );
     const form = document.getElementById( 'zunagi-search-form' );
     const box = document.getElementById( 'zunagi-search-suggestions' );
     const box = document.getElementById( 'zunagi-search-suggestions' );


     if ( !input || !box ) {
     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 openArticle( title ) {
     function openPage( title ) {
         window.location.href = mw.util.getUrl( title );
         window.location.href = mw.util.getUrl( title );
     }
     }


     function showSuggestions( titles ) {
     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 ( !titles.length ) {
         if ( !pages.length ) {
             closeSuggestions();
             closeSuggestions();
             return;
             return;
         }
         }


         titles.forEach( function ( title ) {
         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';
            link.textContent = title;


             link.addEventListener( 'mousedown', function ( event ) {
             title.className = 'zunagi-search-suggestion-title';
                event.preventDefault();
            title.textContent = page.title;
                 openArticle( 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: 'opensearch',
                 action: 'query',
                 search: query,
                 list: 'search',
                 namespace: 0,
                srsearch: query,
                 limit: 8,
                 srnamespace: 0,
                 srlimit: 8,
                srprop: 'snippet',
                 format: 'json'
                 format: 'json'
             } ).done( function ( data ) {
             } ).done( function ( data ) {
Line 72: Line 113:
                 }
                 }


                 showSuggestions( data[ 1 ] || [] );
                 renderSuggestions(
             } ).fail( closeSuggestions );
                    data.query && data.query.search
         }, 250 );
                        ? 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 !== input &&
             !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();
        }
    } );
} );