MediaWiki:Common.js: Difference between revisions

From PRS
Jump to navigation Jump to search
Preparation for better viewing of training videos - adds clickable timestamps
 
No 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. */
 
/* ── Fix TimedMediaHandler: remove disabled, block popup ── */
$(function () {
$(function () {
    /* Only run on pages that contain a training video wrapper */
     if ($('.training-video-wrap').length === 0) return;
     if ($('.training-video-wrap').length === 0) return;
 
     /* ── Find elements ── */
     setTimeout(function () {
     var $video     = $('.training-video-wrap video');
        /* Remove disabled attribute so video can play inline */
     var $entries   = $('.ts-entry');
        $('.mw-file-element').each(function () {
     var $body       = $('.ts-scroll-body');
            $(this).removeAttr('disabled');
     var $markers   = $('.ts-progress-marker');
            $(this).attr('controls', 'controls');
     var $fill       = $('.ts-progress-fill');
        });
     var $timeDisp   = $('.ts-time-display');
 
        /* Block the popup link and play inline instead */
     if ($video.length === 0) return; // no video on this page
        $('a.mw-tmh-play').on('click', function (e) {
 
            e.preventDefault();
            e.stopPropagation();
            var video = $(this).closest('.mw-tmh-player').find('video')[0];
            if (video) {
                video.play();
            }
        });
        /* Now initialise the transcript sync */
        initTranscript();
    }, 600);
});
/* ── Transcript sync ── */
function initTranscript() {
     var $video   = $('.training-video-wrap video');
     var $entries = $('.ts-entry');
     var $body     = $('.ts-scroll-body');
     var $markers = $('.ts-progress-marker');
     var $fill     = $('.ts-progress-fill');
     var $timeDisp = $('.ts-time-display');
     if ($video.length === 0) return;
     var videoEl = $video[0];
     var videoEl = $video[0];
 
     /* ── Format seconds → m:ss ── */
     /* ── Format seconds → m:ss ── */
     function fmt(s) {
     function fmt(s) {
Line 23: Line 47:
         return Math.floor(s / 60) + ':' + ('0' + (s % 60)).slice(-2);
         return Math.floor(s / 60) + ':' + ('0' + (s % 60)).slice(-2);
     }
     }
 
     /* ── Collect timestamp data from DOM ── */
     /* ── Collect timestamp data from DOM ── */
     var timestamps = [];
     var timestamps = [];
Line 29: Line 53:
         timestamps.push(parseInt($(this).data('time'), 10));
         timestamps.push(parseInt($(this).data('time'), 10));
     });
     });
 
     /* ── Highlight the active transcript entry ── */
     /* ── Highlight the active transcript entry ── */
     function highlightActive() {
     function highlightActive() {
Line 43: Line 67:
         var $active = $entries.eq(activeIdx);
         var $active = $entries.eq(activeIdx);
         if ($active.length && $body.length) {
         if ($active.length && $body.length) {
             var entryTop   = $active.position().top;
             var entryTop     = $active.position().top;
             var bodyScrollTop = $body.scrollTop();
             var bodyScrollTop = $body.scrollTop();
             var bodyHeight = $body.height();
             var bodyHeight   = $body.height();
             if (entryTop < 0 || entryTop > bodyHeight - 60) {
             if (entryTop < 0 || entryTop > bodyHeight - 60) {
                 $body.animate({ scrollTop: bodyScrollTop + entryTop - 60 }, 200);
                 $body.animate({ scrollTop: bodyScrollTop + entryTop - 60 }, 200);
Line 51: Line 75:
         }
         }
     }
     }
 
     /* ── Update progress bar ── */
     /* ── Update progress bar ── */
     function updateProgress() {
     function updateProgress() {
Line 59: Line 83:
         $timeDisp.text(fmt(videoEl.currentTime) + ' / ' + fmt(videoEl.duration));
         $timeDisp.text(fmt(videoEl.currentTime) + ' / ' + fmt(videoEl.duration));
     }
     }
 
     /* ── Bind native video events ── */
     /* ── Bind native video events ── */
     $video.on('timeupdate', function () {
     $video.on('timeupdate', function () {
Line 65: Line 89:
         updateProgress();
         updateProgress();
     });
     });
 
     $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);
Line 74: Line 97:
         });
         });
     });
     });
 
    /* If metadata already loaded */
    if (videoEl.readyState >= 1) {
        $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 ── */
     /* ── Transcript entry click → seek video ── */
     $entries.on('click', function () {
     $entries.on('click', function () {
Line 82: Line 114:
         highlightActive();
         highlightActive();
     });
     });
 
     /* ── Progress bar click → seek ── */
     /* ── Progress bar click → seek ── */
     $('.ts-progress-track').on('click', function (e) {
     $('.ts-progress-track').on('click', function (e) {
Line 89: Line 121:
         videoEl.currentTime = ratio * videoEl.duration;
         videoEl.currentTime = ratio * videoEl.duration;
     });
     });
 
     /* ── Marker click → seek ── */
     /* ── Marker click → seek ── */
     $markers.on('click', function (e) {
     $markers.on('click', function (e) {
Line 97: Line 129:
         if (videoEl.paused) videoEl.play();
         if (videoEl.paused) videoEl.play();
     });
     });
 
}
});

Revision as of 07:18, 22 April 2026

/* Any JavaScript here will be loaded for all users on every page load. */
 
/* ── Fix TimedMediaHandler: remove disabled, block popup ── */
$(function () {
    if ($('.training-video-wrap').length === 0) return;
 
    setTimeout(function () {
        /* Remove disabled attribute so video can play inline */
        $('.mw-file-element').each(function () {
            $(this).removeAttr('disabled');
            $(this).attr('controls', 'controls');
        });
 
        /* Block the popup link and play inline instead */
        $('a.mw-tmh-play').on('click', function (e) {
            e.preventDefault();
            e.stopPropagation();
            var video = $(this).closest('.mw-tmh-player').find('video')[0];
            if (video) {
                video.play();
            }
        });
 
        /* Now initialise the transcript sync */
        initTranscript();
 
    }, 600);
});
 
/* ── Transcript sync ── */
function initTranscript() {
 
    var $video    = $('.training-video-wrap video');
    var $entries  = $('.ts-entry');
    var $body     = $('.ts-scroll-body');
    var $markers  = $('.ts-progress-marker');
    var $fill     = $('.ts-progress-fill');
    var $timeDisp = $('.ts-time-display');
 
    if ($video.length === 0) return;
 
    var videoEl = $video[0];
 
    /* ── Format seconds → m:ss ── */
    function fmt(s) {
        s = Math.floor(s);
        return Math.floor(s / 60) + ':' + ('0' + (s % 60)).slice(-2);
    }
 
    /* ── 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);
        });
        /* Auto-scroll transcript panel to keep active line visible */
        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) + '%');
        });
    });
 
    /* If metadata already loaded */
    if (videoEl.readyState >= 1) {
        $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();
    });
}