MediaWiki:TemplateVideo.js:修订间差异

    来自真佛百科
    Tbpedia>Emilio
    (Protected "MediaWiki:TemplateVideo.js": Prevent accidental edits as we explore h5p functionality. ([Edit=Allow only administrators] (expires 20:34, 12 March 2024 (UTC)) [Move=Allow only administrators] (expires 20:34, 12 March 2024 (UTC))))
     
    (导入1个版本)
     
    (没有差异)

    2024年3月2日 (六) 17:37的最新版本

    /**
     * This script interacts with [[Template:Video]]
     * 
     * Most of the complexity of this script stems from the fact that it's designed
     * to handle videos from YouTube, Vimeo, Commons or Appropedia
     * 
     * [[Category:Template script pages]]
     */
    window.TemplateVideo = {
    
    	init: function () {
    		var $videos = $( '.template-video' );
    
    		// Give each video an id and an index
    		$videos.each( function ( index ) {
    			$( this ).attr( {
    				'id': 'video-' + index,
    				'data-video-index': index
    			} );
    		} );
    
    		// Replace plain timestamps for links
    		$videos.find( '.template-video-annotations' ).html( function ( index, html ) {
    			if ( /(\d\d?:\d\d)/.test( html ) ) {
    				return html.replace( /(\d\d?:\d\d)/g, '<a class="timestamp" href="#$1">$1</a>' );
    			}
    		} );
    
    		// Play the relevant video when a timestamp is clicked
    		$videos.find( '.template-video-annotations .timestamp' ).on( 'click', function () {
    			var $link = $( this );
    			var $video = $link.closest( '.template-video' );
    			var index = $video.data( 'video-index' );
    			var hash = $link.attr( 'href' );
    			if ( $video.find( 'iframe, video' ).length ) {
    				TemplateVideo.playVideoAtTime( index, hash );
    			} else if ( $video.hasClass( 'youtube' ) ) {
    				TemplateVideo.loadYouTubeVideo.bind( this )();
    			} else if ( $video.hasClass( 'vimeo' ) ) {
    				TemplateVideo.loadVimeoVideo.bind( this )();
    			}
    		} );
    
    		// Add event listeners to highlight the relevant annotation
    		$videos.filter( '.appropedia, .commons' ).each( function () {
    			var $video = $( this );
    			var player = $video.find( 'video' )[0];
    			var previousTime = -1;
    			player.addEventListener( 'timeupdate', function () {
    				var currentTime = player.currentTime;
    				currentTime = Math.floor( currentTime );
    				if ( currentTime === previousTime ) {
    					return;
    				}
    				previousTime = currentTime;
    				TemplateVideo.highlightAnnotation( $video, currentTime );
    			} );
    		} );
    
    		// Load a YouTube video when a YouTube play button or thumbnail is clicked
    		$videos.filter( '.youtube' ).find( '.template-video-play, .template-video-thumb' ).on( 'click', TemplateVideo.loadYouTubeVideo );
    
    		// Load a Vimeo video when a Vimeo play button or thumbnail is clicked
    		$videos.filter( '.vimeo' ).find( '.template-video-play, .template-video-thumb' ).on( 'click', TemplateVideo.loadVimeoVideo );
    	},
    
    	isYouTubeLoaded: false,
    	loadYouTubeVideo: function () {
    		var $video = $( this ).closest( '.template-video' );
    
    		// Make the iframe
    		var params = new URLSearchParams( {
    			autoplay: 1,
    			enablejsapi: 1,
    			rel: 0,
    			origin: window.location.origin
    		} );
    		var id = $video.data( 'video-id' );
    		var url = 'https://www.youtube.com/embed/' + id + '?' + params.toString();
    		var $iframe = $( '<iframe src="' + url + '" width="640" height="360" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>' );
    
    		// Update the DOM
    		$video.find( '.template-video-content' ).html( $iframe );
    
    		// Load the YouTube IFrame Player API code only once
    		if ( TemplateVideo.isYouTubeLoaded === false ) {
    			$.getScript( 'https://www.youtube.com/iframe_api' );
    			window.onYouTubeIframeAPIReady = function () {
    				TemplateVideo.isYouTubeLoaded = true;
    				TemplateVideo.makeYouTubePlayer( $video );
    			};	
    		} else {
    			TemplateVideo.makeYouTubePlayer( $video );
    		}
    	},
    
    	isVimeoLoaded: false,
    	loadVimeoVideo: function () {
    		var $video = $( this ).closest( '.template-video' );
    
    		// Make the iframe
    		var id = $video.data( 'video-id' );
    		var url = 'https://player.vimeo.com/video/' + id;
    		var $iframe = $( '<iframe src="' + url + '" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>' );
    
    		// Update the DOM
    		$video.find( '.template-video-content' ).html( $iframe );
    
    		// Load the Vimeo Player SDK code only once
    		if ( TemplateVideo.isVimeoLoaded === false ) {
    			$.getScript( 'https://player.vimeo.com/api/player.js' ).done( function () {
    				TemplateVideo.isVimeoLoaded = true;
    				TemplateVideo.makeVimeoPlayer( $video );
    			} );
    		} else {
    			TemplateVideo.makeVimeoPlayer( $video );
    		}
    	},
    
    	// This will hold both YouTube and Vimeo players
    	players: [],
    
    	// Create a YouTube player
    	makeYouTubePlayer: function ( $video ) {
    		var $iframe = $video.find( 'iframe' );
    		var index = $video.data( 'video-index' );
    		var id = 'video-iframe-' + index;
    		$iframe.attr( 'id', id );
    		var player = new YT.Player( id, { origin: window.location.origin } );
    		TemplateVideo.players[ index ] = player;
    
    		player.addEventListener( 'onReady', function () {
    			TemplateVideo.playVideoAtTime( index );
    
    			// Highlight the relevant annotation
    			var previousTime = -1;
    			setInterval( function () {
    				var currentTime = player.getCurrentTime();
    				currentTime = Math.floor( currentTime );
    				if ( currentTime === previousTime ) {
    					return;
    				}
    				previousTime = currentTime;
    				TemplateVideo.highlightAnnotation( $video, currentTime );
    			}, 1000 );
    		} );
    	},
    
    	// Create a Vimeo player
    	makeVimeoPlayer: function ( $video ) {
    		var $iframe = $video.find( 'iframe' );
    		var index = $video.data( 'video-index' );
    		var iframe = $iframe[0];
    		var player = new Vimeo.Player( iframe );
    		TemplateVideo.players[ index ] = player;
    
    		player.on( 'loaded', function () {
    			TemplateVideo.playVideoAtTime( index );
    
    			// Highlight the relevant annotation
    			var previousTime = -1;
    			setInterval( function () {
    				player.getCurrentTime().then( function ( currentTime ) {
    					currentTime = Math.floor( currentTime );
    					if ( currentTime === previousTime ) {
    						return;
    					}
    					previousTime = currentTime;
    					TemplateVideo.highlightAnnotation( $video, currentTime );
    				} );
    			}, 1000 );
    		} );
    	},
    
    	// Play the specified video at the specified time
    	playVideoAtTime: function ( index, hash ) {
    
    		// Figure out the intended video and time
    		if ( !Number.isInteger( index ) ) {
    			index = 0;
    		}
    		if ( !hash ) {
    			hash = window.location.hash;
    		}
    		var time = hash.substr( 1 ).split( ':' );
    		var minutes = time[1] ? parseInt( time[0], 10 ) : 0;
    		var seconds = time[1] ? parseInt( time[1], 10 ) + minutes * 60 : parseInt( time[0], 10 );
    		if ( !Number.isInteger( seconds ) ) {
    			return;
    		}
    		var $video = $( '#video-' + index );
    
    		// Play the specified video at the specified time
    		var player;
    		if ( $video.hasClass( 'youtube' ) ) {
    			player = TemplateVideo.players[ index ];
    			player.seekTo( seconds );
    			player.playVideo();
    		} else if ( $video.hasClass( 'vimeo' ) ) {
    			player = TemplateVideo.players[ index ];
    			player.setCurrentTime( seconds );
    			player.play();
    		} else {
    			player = $video.find( 'video' )[0];
    			player.currentTime = seconds;
    			player.play();
    		}
    
    		// Center the video
    		$video.find( '.template-video-content' )[0].scrollIntoView( { behavior: 'smooth', block: 'center' } );
    	},
    
    	// Find the relevant annotation and highlight it
    	highlightAnnotation: function ( $video, currentTime ) {
    		$video.find( '.template-video-annotations a' ).each( function () {
    			var $link = $( this );
    			var href = $link.attr( 'href' );
    			var time = href.substr( 1 ).split( ':' );
    			var minutes = time[1] ? parseInt( time[0], 10 ) : 0;
    			var seconds = time[1] ? parseInt( time[1], 10 ) + minutes * 60 : parseInt( time[0], 10 );
    			var $item = $link.closest( 'li' );
    			if ( currentTime === seconds ) {
    				var $annotations = $item.closest( '.template-video-annotations' );
    				$annotations.find( '.highlight' ).removeClass( 'highlight' );
    				$item.addClass( 'highlight' );
    				$annotations.find( '.mw-collapsible' ).hide();
    				if ( $item.is( ':last-child' ) ) {
    					$item.closest( 'ul' ).next( '.mw-collapsible' ).show();
    				}
    				return false; // Break the loop
    			}
    		} );
    	}
    };
    
    $( TemplateVideo.init );