MediaWiki:Gadget-TimelinePreview.js

From Angelina Jordan Wiki
Revision as of 17:19, 11 November 2025 by Most2dot0 (talk | contribs) (go back to earler (3rd?) version, to see if suppression worked for non-collapsed items)

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.
// Gadget: Timeline hover previews
// Requires: mediawiki.api, mediawiki.util, jquery

mw.loader.using(['mediawiki.api', 'mediawiki.util']).then(function () {
    var api = new mw.Api();
    var timelineCache = null;

    // Precreate popup once
    var popup = $('<div>')
        .css({
            position: 'absolute',
            zIndex: 1000,
            background: 'white',
            border: '1px solid #ccc',
            padding: '0.5em',
            maxWidth: '320px',
            boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
            borderRadius: '4px'
        })
        .hide()
        .appendTo(document.body);

    function loadTimeline() {
        if (timelineCache) return $.Deferred().resolve();

        return api.get({
            action: 'parse',
            page: 'Timeline',
            prop: 'text',
            formatversion: 2
        }).then(function (data) {
            var html = $('<div>').html(data.parse.text);
            timelineCache = {};
            html.find('dt').each(function () {
                var dt = $(this);
                var id = dt.find('span[id]').attr('id');
                if (!id) return;
                var ddList = [];
                var el = dt.next();
                while (el.length && el.prop('tagName') === 'DD') {
                    ddList.push(el.html());
                    el = el.next();
                }
                timelineCache[id] = ddList.join('<br>');
            });
        });
    }

    function showPopup($link, html) {
        popup.html(html).show();
        var offset = $link.offset();
        popup.css({
            top: offset.top + $link.outerHeight() + 5,
            left: offset.left
        });
    }

    function hidePopup() {
        popup.hide();
    }

    function onHover() {
        var $link = $(this);
        var href = $link.attr('href') || '';
        var match =
            href.match(/\/Timeline#(\d{4}-\d{2}-\d{2})$/) ||
            href.match(/^#(\d{4}-\d{2}-\d{2})$/);
        if (!match) return;

        var id = match[1];
        loadTimeline().then(function () {
            var content = timelineCache[id];
            if (content) showPopup($link, content);
        });
    }

    function attach() {
        $('a[href*="Timeline#"], a[href^="#"]').each(function () {
            var $link = $(this);
            var href = $link.attr('href') || '';
            if (
                href.match(/Timeline#\d{4}-\d{2}-\d{2}$/) ||
                href.match(/^#\d{4}-\d{2}-\d{2}$/)
            ) {
                // Disable built-in MediaWiki page previews
                $link.attr('data-mw-previews-disable', 'true');

                // Rebind hover handlers safely
                $link.off('.timelinePreview')
                    .on('mouseenter.timelinePreview', onHover)
                    .on('mouseleave.timelinePreview', hidePopup);
            }
        });
    }

    // Attach to current content
    mw.hook('wikipage.content').add(attach);

    // Observe dynamic content (collapsed sections, lazy loads, etc.)
    var observer = new MutationObserver(function (mutations) {
        for (var i = 0; i < mutations.length; i++) {
            if (mutations[i].addedNodes.length) {
                attach();
                break;
            }
        }
    });
    observer.observe(document.body, { childList: true, subtree: true });
});