MediaWiki:Common.js: Difference between revisions

From PRS
Jump to navigation Jump to search
No edit summary
No edit summary
 
(10 intermediate revisions by the same user not shown)
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. */


/* ── Prevent TMH from removing native video controls ── */
/* ============================================================
$(function () {
  Training Video – Video source loader + Synced Transcript
    if ($('.training-video-wrap').length === 0) return;
  ============================================================ */


    function startGuarding() {
mw.hook('wikipage.content').add(function () {
        var video = document.querySelector('.mw-file-element');
        if (!video) {
            setTimeout(startGuarding, 100);
            return;
        }


        /* Watch for TMH removing the controls attribute and restore it immediately */
    if ($('.training-video-wrap').length === 0) return;
        var observer = new MutationObserver(function (mutations) {
            mutations.forEach(function (mutation) {
                if (mutation.attributeName === 'controls') {
                    var current = video.getAttribute('controls');
                    if (current === null) {
                        video.setAttribute('controls', '');
                    }
                }
            });
        });


        observer.observe(video, {
    var $video = $('.training-video-wrap video');
            attributes: true,
    if ($video.length === 0) return;
            attributeFilter: ['controls']
        });


        /* Make sure controls are set initially */
    var videoEl = $video[0];
        video.setAttribute('controls', '');
    var filename = $video.attr('data-file');
    }


     startGuarding();
     if (!filename) return;
});


/* ============================================================
    /* ── Use MediaWiki API to get the real file URL ── */
  Training Video – Synced Transcript Sidebar
    $.ajax({
  ============================================================ */
        url: '/wiki/api.php',
$(function () {
        data: {
    /* Only run on pages that contain a training video wrapper */
            action: 'query',
    if ($('.training-video-wrap').length === 0) return;
            titles: 'File:' + filename,
 
            prop: 'imageinfo',
    /* ── Find elements ── */
            iiprop: 'url',
    var $video      = $('.training-video-wrap video');
            format: 'json'
    var $entries    = $('.ts-entry');
        },
    var $body      = $('.ts-scroll-body');
        dataType: 'json',
    var $markers    = $('.ts-progress-marker');
        success: function (data) {
    var $fill      = $('.ts-progress-fill');
            var pages = data.query.pages;
    var $timeDisp  = $('.ts-time-display');
            var page = pages[Object.keys(pages)[0]];
 
            if (page.imageinfo && page.imageinfo[0]) {
    if ($video.length === 0) return; // no video on this page
                var url = page.imageinfo[0].url;
 
                videoEl.src = url;
     var videoEl = $video[0];
                videoEl.load();
            }
        }
     });


     /* ── Format seconds → m:ss ── */
     /* ── Format seconds → m:ss ── */
Line 60: Line 44:
         return Math.floor(s / 60) + ':' + ('0' + (s % 60)).slice(-2);
         return Math.floor(s / 60) + ':' + ('0' + (s % 60)).slice(-2);
     }
     }
    var $entries  = $('.ts-entry');
    var $body    = $('.ts-scroll-body');
    var $markers  = $('.ts-progress-marker');
    var $fill    = $('.ts-progress-fill');
    var $timeDisp = $('.ts-time-display');


     /* ── Collect timestamp data from DOM ── */
     /* ── Collect timestamp data from DOM ── */
Line 77: Line 67:
             $(this).toggleClass('ts-active', i === activeIdx);
             $(this).toggleClass('ts-active', i === activeIdx);
         });
         });
        /* Auto-scroll transcript panel to keep active line visible */
         var $active = $entries.eq(activeIdx);
         var $active = $entries.eq(activeIdx);
         if ($active.length && $body.length) {
         if ($active.length && $body.length) {
Line 105: Line 94:
     $video.on('loadedmetadata', function () {
     $video.on('loadedmetadata', function () {
         $timeDisp.text('0:00 / ' + fmt(videoEl.duration));
         $timeDisp.text('0:00 / ' + fmt(videoEl.duration));
        /* Position progress bar markers once duration is known */
         $markers.each(function () {
         $markers.each(function () {
             var t = parseInt($(this).data('time'), 10);
             var t = parseInt($(this).data('time'), 10);

Latest revision as of 02:27, 23 April 2026

/* Any JavaScript here will be loaded for all users on every page load. */

/* ============================================================
   Training Video – Video source loader + Synced Transcript
   ============================================================ */

mw.hook('wikipage.content').add(function () {

    if ($('.training-video-wrap').length === 0) return;

    var $video = $('.training-video-wrap video');
    if ($video.length === 0) return;

    var videoEl = $video[0];
    var filename = $video.attr('data-file');

    if (!filename) return;

    /* ── Use MediaWiki API to get the real file URL ── */
    $.ajax({
        url: '/wiki/api.php',
        data: {
            action: 'query',
            titles: 'File:' + filename,
            prop: 'imageinfo',
            iiprop: 'url',
            format: 'json'
        },
        dataType: 'json',
        success: function (data) {
            var pages = data.query.pages;
            var page = pages[Object.keys(pages)[0]];
            if (page.imageinfo && page.imageinfo[0]) {
                var url = page.imageinfo[0].url;
                videoEl.src = url;
                videoEl.load();
            }
        }
    });

    /* ── Format seconds → m:ss ── */
    function fmt(s) {
        s = Math.floor(s);
        return Math.floor(s / 60) + ':' + ('0' + (s % 60)).slice(-2);
    }

    var $entries  = $('.ts-entry');
    var $body     = $('.ts-scroll-body');
    var $markers  = $('.ts-progress-marker');
    var $fill     = $('.ts-progress-fill');
    var $timeDisp = $('.ts-time-display');

    /* ── Collect timestamp data from DOM ── */
    var timestamps = [];
    $entries.each(function () {
        timestamps.push(parseInt($(this).data('time'), 10));
    });

    /* ── Highlight the active transcript entry ── */
    function highlightActive() {
        var cur = videoEl.currentTime;
        var activeIdx = 0;
        for (var i = 0; i < timestamps.length; i++) {
            if (cur >= timestamps[i]) activeIdx = i;
        }
        $entries.each(function (i) {
            $(this).toggleClass('ts-active', i === activeIdx);
        });
        var $active = $entries.eq(activeIdx);
        if ($active.length && $body.length) {
            var entryTop      = $active.position().top;
            var bodyScrollTop = $body.scrollTop();
            var bodyHeight    = $body.height();
            if (entryTop < 0 || entryTop > bodyHeight - 60) {
                $body.animate({ scrollTop: bodyScrollTop + entryTop - 60 }, 200);
            }
        }
    }

    /* ── Update progress bar ── */
    function updateProgress() {
        if (!videoEl.duration) return;
        var pct = (videoEl.currentTime / videoEl.duration) * 100;
        $fill.css('width', pct + '%');
        $timeDisp.text(fmt(videoEl.currentTime) + ' / ' + fmt(videoEl.duration));
    }

    /* ── Bind native video events ── */
    $video.on('timeupdate', function () {
        highlightActive();
        updateProgress();
    });

    $video.on('loadedmetadata', function () {
        $timeDisp.text('0:00 / ' + fmt(videoEl.duration));
        $markers.each(function () {
            var t = parseInt($(this).data('time'), 10);
            $(this).css('left', ((t / videoEl.duration) * 100) + '%');
        });
    });

    /* ── Transcript entry click → seek video ── */
    $entries.on('click', function () {
        var t = parseInt($(this).data('time'), 10);
        videoEl.currentTime = t;
        if (videoEl.paused) videoEl.play();
        highlightActive();
    });

    /* ── Progress bar click → seek ── */
    $('.ts-progress-track').on('click', function (e) {
        var rect  = this.getBoundingClientRect();
        var ratio = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
        videoEl.currentTime = ratio * videoEl.duration;
    });

    /* ── Marker click → seek ── */
    $markers.on('click', function (e) {
        e.stopPropagation();
        var t = parseInt($(this).data('time'), 10);
        videoEl.currentTime = t;
        if (videoEl.paused) videoEl.play();
    });

});
/* ============================================================ */