Difference between revisions of "MediaWiki:Common.js"
From Conceptual Reconstructionism Project
Thaumasnot (talk | contribs) |
Thaumasnot (talk | contribs) |
||
Line 138: | Line 138: | ||
}); | }); | ||
// Create context menu for music references | |||
function playSample(menuItem, segment) { | |||
var m = /\[\-?(\d+)s \+(\d+)s\]/.exec(menuItem.text()); | |||
if (m) { | |||
var lowerBound = m[1]; | |||
var upperBound = m[2] | |||
var trackIndex = segment.trackIndex; | |||
playbackData.autostopTime = segment.endTime + upperBound; | |||
playbackData.htmlAudios[trackIndex].currentTime = Math.max(0, segment.startTime - lowerBound); | |||
playbackData.htmlAudios[trackIndex].play(); | |||
} | |||
} | |||
var soundContextMenu = $('<div class="sound-meta-menu meta-menu">') | |||
.append($('<div>\u25B6 [-0s +0s]</div>') | |||
.append($('<div>\u25B6 [-2s +2s]</div>') | |||
.append($('<div>\u25B6 [-5s +5s]</div>') | |||
.append($('<div>\u25B6 [-10s +10s]</div>')); | |||
// Update timing data | // Update timing data | ||
Line 151: | Line 174: | ||
} | } | ||
else { | else { | ||
var segment = new TimeSegment( | |||
m.groups.track? parseInt(m.groups.track) : 0, | m.groups.track? parseInt(m.groups.track) : 0, | ||
(m.groups.minuteStart? parseInt(m.groups.minuteStart) : 0) * 60 + parseFloat(m.groups.secondStart), | (m.groups.minuteStart? parseInt(m.groups.minuteStart) : 0) * 60 + parseFloat(m.groups.secondStart), | ||
(m.groups.minuteEnd? parseInt(m.groups.minuteEnd) : 0) * 60 + parseFloat(m.groups.secondEnd), | (m.groups.minuteEnd? parseInt(m.groups.minuteEnd) : 0) * 60 + parseFloat(m.groups.secondEnd), | ||
$(this).find('.meta-progress') | $(this).find('.meta-progress') | ||
)); | ); | ||
function attachSoundContextMenu() { | |||
soundContextMenu.detach().appendTo($(this)); | |||
soundContextMenu.children('div').click(function () { playSample($(this), segment); }) | |||
} | |||
if (!isMobile) { | |||
$(this).hover(attachSoundContextMenu); | |||
} else { | |||
$(this).after($('<span class="context-menu-anchor">\u23F5</span>').click(attachSoundContextMenu)); | |||
} | |||
playbackData.segments.push(segment); | |||
} | } | ||
} | } | ||
Line 165: | Line 200: | ||
}); | }); | ||
playbackData.segments.sort(function(a, b) { return a.startTime - b.startTime; }); | playbackData.segments.sort(function(a, b) { return a.trackIndex - b.trackIndex || a.startTime - b.startTime; }); | ||
// Playing tick | // Playing tick |
Revision as of 13:52, 21 December 2021
/* Any JavaScript here will be loaded for all users on every page load. */ var isMobile = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent); function TimeSegment(trackIndex, startTime, endTime, element) { this.trackIndex = trackIndex; this.startTime = startTime; this.endTime = endTime; this.element = element; } TimeSegment.prototype.isDisabled = function() { return !this.element.hasClass('active'); }; TimeSegment.prototype.disable = function() { this.element.removeClass('active'); }; TimeSegment.prototype.update = function(trackIndex, currentTime) { var percent = 100.0 * Math.max(currentTime - this.startTime, 0) / (this.endTime - this.startTime) if (trackIndex === this.trackIndex && percent > 0.0 && percent < 100.0) { this.element.get(0).style.setProperty('--gauge-fill', percent + "%"); this.element.addClass('active'); } else { this.disable(); } }; function PlaybackData() { this.autostopTime = null; this.segments = []; this.htmlAudios = []; this.closestPlayableSegIndex = 0; this.playingAudioIndex = null; }; var playbackData = new PlaybackData(); $(document).ready(function() { // Create one audio player per declared track var audioPlayer = $('<div class="audio-player"></div>').insertAfter($('*[data-track]').last()); function selectAudioPlayer(trackNumber) { audioPlayer.find('figure.active').removeClass('active'); audioPlayer.find('figure').eq(trackNumber).addClass('active'); audioPlayer.find('.selected').removeClass('selected'); audioPlayer.find('.track-menu div').eq(trackNumber).addClass('selected'); } $('*[data-track]').each(function(trackNumber) { var audio = $('<audio></audio>') .prop('controls', true) .attr('preload', 'auto') .attr('src', $(this).attr('data-track')); $('<figure></figure>') .addClass(trackNumber === 0? 'active': '') .append($('<figcaption></figcaption>') .text($(this).attr('data-track-title'))) .appendTo(audioPlayer) .append(audio); function onPlay(event) { if (playbackData.playingAudioIndex != null && playbackData.playingAudioIndex !== trackNumber) { playbackData.htmlAudios[playbackData.playingAudioIndex].pause(); selectAudioPlayer(trackNumber); } playbackData.playingAudioIndex = trackNumber; } function onPause(event) { if (playbackData.playingAudioIndex === trackNumber) { playbackData.playingAudioIndex = null; playbackData.autostopTime = null; } playbackData.closestPlayableSegIndex = 0; } function onSeeked(event) { playbackData.closestPlayableSegIndex = 0; playbackData.segments.forEach(function(s) { s.disable(); }); } function onEnded(event) { var nextPlayingAudioIndex = playbackData.playingAudioIndex + 1; onPause(event); onSeeked(event); if (nextPlayingAudioIndex < playbackData.htmlAudios.length) { playbackData.htmlAudios[nextPlayingAudioIndex].play(); } } audio.on('play', onPlay); audio.on('pause', onPause); audio.on('ended', onEnded); audio.on('seeked', onSeeked); playbackData.htmlAudios.push(audio.get(0)); }); if ($('*[data-track]').length > 1) { var trackMenu = $('<div class="track-menu"></div>').appendTo(audioPlayer); $('*[data-track]').each(function(trackNumber) { $('<div></div>') .text(trackNumber + 1) .click(function() { selectAudioPlayer(trackNumber); } ) .addClass(trackNumber === 0? 'selected': '') .prop('title', audioPlayer.find('figcaption').eq(trackNumber).text()) .appendTo(trackMenu); }); } // Create hyperlinks out of reconstruction markup $('*[data-def]').click(function() { var url = location.href; location.href = "#" + $(this).attr('data-def'); history.replaceState(null, null, url); }); // Create context menu for music references function playSample(menuItem, segment) { var m = /\[\-?(\d+)s \+(\d+)s\]/.exec(menuItem.text()); if (m) { var lowerBound = m[1]; var upperBound = m[2] var trackIndex = segment.trackIndex; playbackData.autostopTime = segment.endTime + upperBound; playbackData.htmlAudios[trackIndex].currentTime = Math.max(0, segment.startTime - lowerBound); playbackData.htmlAudios[trackIndex].play(); } } var soundContextMenu = $('<div class="sound-meta-menu meta-menu">') .append($('<div>\u25B6 [-0s +0s]</div>') .append($('<div>\u25B6 [-2s +2s]</div>') .append($('<div>\u25B6 [-5s +5s]</div>') .append($('<div>\u25B6 [-10s +10s]</div>')); // Update timing data $('*[data-segment]').each(function() { var m = /(?<track>\d+\/)?((?<minuteStart>\d+):)?(?<secondStart>\d+(.\d*)?)-((?<minuteEnd>\d+):)?(?<secondEnd>\d+(.\d*)?)/.exec($(this).attr('data-segment')); if (m) { if (m.groups.track != null && playbackData.htmlAudios.length <= parseInt(m.groups.track)) { $(this).append('Track number does not refer to existing track (note that the index starts with 0)'); } else { var segment = new TimeSegment( m.groups.track? parseInt(m.groups.track) : 0, (m.groups.minuteStart? parseInt(m.groups.minuteStart) : 0) * 60 + parseFloat(m.groups.secondStart), (m.groups.minuteEnd? parseInt(m.groups.minuteEnd) : 0) * 60 + parseFloat(m.groups.secondEnd), $(this).find('.meta-progress') ); function attachSoundContextMenu() { soundContextMenu.detach().appendTo($(this)); soundContextMenu.children('div').click(function () { playSample($(this), segment); }) } if (!isMobile) { $(this).hover(attachSoundContextMenu); } else { $(this).after($('<span class="context-menu-anchor">\u23F5</span>').click(attachSoundContextMenu)); } playbackData.segments.push(segment); } } else { $(this).append('Invalid syntax for segment time'); } }); playbackData.segments.sort(function(a, b) { return a.trackIndex - b.trackIndex || a.startTime - b.startTime; }); // Playing tick window.setInterval(function() { if (playbackData.playingAudioIndex === null) { return; } var playingAudio = playbackData.htmlAudios[playbackData.playingAudioIndex]; var currentTime = playingAudio.currentTime; var previouSegmentActive = false; var newActiveSegment = null; for(var segIndex = playbackData.closestPlayableSegIndex; segIndex < playbackData.segments.length; segIndex++) { var segment = playbackData.segments[segIndex]; var wasDisabled = segment.isDisabled(); segment.update(playbackData.playingAudioIndex, currentTime); if (segment.isDisabled()) { if (segment.startTime > currentTime && segment.trackIndex === playbackData.playingAudioIndex) { break; } continue; } if (!previouSegmentActive) { playbackData.closestPlayableSegIndex = segIndex; } previouSegmentActive = true; if (wasDisabled && newActiveSegment == null) { newActiveSegment = segment; } } function ensureVisible(element) { var offset = element.offset().top - $(window).scrollTop(); var SCROLL_OFFSET = 150; if (offset > window.innerHeight) { $('html,body').animate({ scrollTop: Math.max(0, offset - SCROLL_OFFSET) }, 500); } else if (offset < 0) { $('html,body').animate({ scrollTop: Math.max(0, element.offset().top - SCROLL_OFFSET) }, 500); } } if (newActiveSegment != null) { ensureVisible(newActiveSegment.element); } if (playbackData.autostopTime != null && currentTime >= playbackData.autostopTime) { playingAudio.pause(); return; } }, 50); });