MediaWiki:Gadget-YSWSSearch.js

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.
(function () {
    'use strict';
    function todayISO() {
        var d = new Date();
        return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0');
    }
    function init(root) {
        if (root.dataset.yswsInitialized === '1') return;
        var rows = Array.from(root.querySelectorAll('tr.ysws-program'));
        if (!rows.length) return;
        root.dataset.yswsInitialized = '1';
        var controls = document.createElement('div');
        controls.className = 'ysws-controls';
        var label = document.createElement('label');
        label.textContent = 'Search programs';
        var input = document.createElement('input');
        input.type = 'search';
        input.className = 'ysws-search';
        input.placeholder = 'Search name or description';
        input.autocomplete = 'off';
        input.id = 'ysws-search-' + Math.random().toString(36).slice(2);
        label.htmlFor = input.id;
        var results = document.createElement('p');
        results.className = 'ysws-results';
        results.setAttribute('role', 'status');
        results.setAttribute('aria-live', 'polite');
        controls.append(label, input, results);
        var tableWrap = root.querySelector('.ysws-table-wrapper');
        root.insertBefore(controls, tableWrap || root.firstChild);
        var empty = document.createElement('p');
        empty.className = 'ysws-empty';
        empty.textContent = 'No programs match your search.';
        empty.hidden = true;
        if (tableWrap) tableWrap.after(empty); else root.appendChild(empty);
        var today = todayISO();
        rows.forEach(function (row) {
            var start = row.dataset.start || '';
            var end = row.dataset.end || '';
            var status = 'Unknown';
            if (start && start > today) status = 'Upcoming';
            else if (end && end < today) status = 'Ended';
            else if (start && end && start <= today && end >= today) status = 'Ongoing';
            var cell = row.querySelector('.ysws-status');
            if (cell) { cell.textContent = status; cell.setAttribute('data-sort-value', status); }
        });
        function update() {
            var q = input.value.trim().toLocaleLowerCase();
            var count = 0;
            rows.forEach(function (row) {
                var name = row.querySelector('.ysws-name');
                var desc = row.querySelector('.ysws-description');
                var haystack = ((name && name.textContent) || '') + ' ' + ((desc && desc.textContent) || '');
                var match = haystack.toLocaleLowerCase().includes(q);
                row.hidden = !match;
                if (match) count++;
            });
            results.textContent = count + ' of ' + rows.length + ' programs shown';
            empty.hidden = count !== 0;
        }
        input.addEventListener('input', update);
        update();
    }
    function initAll(node) {
        if (!node || !node.querySelectorAll) return;
        node.querySelectorAll('.ysws-directory').forEach(init);
        if (node.matches && node.matches('.ysws-directory')) init(node);
    }
    mw.hook('wikipage.content').add(function ($content) { $content.each(function () { initAll(this); }); });
    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function () { initAll(document); });
    else initAll(document);
}());