import $ from 'jquery'; import DOMPurify from 'dompurify'; import validate from './validate'; import AccessibleSlider from './slider'; function addBuildplayerFunctions(AblePlayer) { AblePlayer.prototype.injectPlayerCode = function() { // create and inject surrounding HTML structure // If iOS & video: // iOS does not support any of the player's functionality - everything plays in its own player // Therefore, AblePlayer is not loaded & all functionality is disabled // (this all determined. If this is iOS && video, this function is never called) var captionsContainer; // Wrappers, from inner to outer: // $mediaContainer - contains the original media element // $ableDiv - contains the media player and all its objects (e.g., captions, controls, descriptions) // $ableWrapper - contains additional widgets (e.g., transcript window, sign window) this.$mediaContainer = this.$media.wrap('
').parent(); this.$ableDiv = this.$mediaContainer.wrap('
').parent(); this.$ableWrapper = this.$ableDiv.wrap('
').parent(); this.$ableWrapper.addClass('able-skin-' + this.skin); if (this.mediaType === 'video') { // youtube adds its own big play button // don't show ours *unless* video has a poster attribute // (which obstructs the YouTube poster & big play button) if (this.player !== 'youtube' || this.hasPoster) { this.injectBigPlayButton(); } } // add container that captions or description will be appended to // Note: new Jquery object must be assigned _after_ wrap, hence the temp captionsContainer variable captionsContainer = $('
'); if (this.mediaType === 'video') { captionsContainer.addClass('able-vidcap-container'); } else if (this.mediaType === 'audio') { captionsContainer.addClass('able-audcap-container'); // hide this by default. It will be shown if captions are available captionsContainer.addClass('captions-off'); } this.injectPlayerControlArea(); // this may need to be injected after captions??? this.$captionsContainer = this.$mediaContainer.wrap(captionsContainer).parent(); this.injectAlert(this.$ableDiv); this.injectPlaylist(); this.injectAudioPoster(); // Do this last, as it should be prepended to the top of this.$ableDiv // after everything else has prepended this.injectOffscreenHeading(); }; AblePlayer.prototype.injectAudioPoster = function() { if ( this.mediaType === 'audio' && this.hasPoster ) { const audioPoster = DOMPurify.sanitize(this.audioPoster); const audioPosterAlt = DOMPurify.sanitize(this.audioPosterAlt); let audioPosterImg = document.createElement( 'img' ); audioPosterImg.setAttribute( 'src', audioPoster ); audioPosterImg.setAttribute( 'alt', audioPosterAlt ); this.$audioWrapper = this.$playerDiv.wrap( '
' ).parent(); this.$audioWrapper.prepend( audioPosterImg ); } } AblePlayer.prototype.injectOffscreenHeading = function () { // Inject an offscreen heading to the media container. // If heading hasn't already been manually defined via data-heading-level, // automatically assign a level that is one level deeper than the closest parent heading // as determined by getNextHeadingLevel() var headingType; if (this.playerHeadingLevel == '0') { // do NOT inject a heading (at author's request) } else { if (typeof this.playerHeadingLevel === 'undefined') { this.playerHeadingLevel = this.getNextHeadingLevel(this.$ableDiv); // returns in integer 1-6 } headingType = 'h' + this.playerHeadingLevel.toString(); this.$headingDiv = $('<' + headingType + '>'); this.$ableDiv.prepend(this.$headingDiv); this.$headingDiv.addClass('able-offscreen'); this.$headingDiv.text( this.translate( 'playerHeading', 'Media player' ) ); } }; AblePlayer.prototype.injectBigPlayButton = function () { var thisObj = this; this.$bigPlayButton = $('' ); $alertDismiss.attr( 'aria-label', this.translate( 'dismissButton', 'Dismiss' ) ); $alertDismiss.text( '×' ); $alertDismiss.appendTo(this.$alertBox); $alertDismiss.on( 'click', function(e) { $(this).parent('div').hide(); }); this.$alertBox.appendTo($container); if ( ! this.$srAlertBox ) { this.$srAlertBox = $('
'); this.$srAlertBox.addClass('able-screenreader-alert'); this.$srAlertBox.appendTo($container); } }; AblePlayer.prototype.injectPlaylist = function () { if (this.playlistEmbed === true) { // move playlist into player, immediately before statusBarDiv var playlistClone = this.$playlistDom.clone(); playlistClone.insertBefore(this.$statusBarDiv); // Update to the new playlist copy. this.$playlist = playlistClone.find('li'); } }; AblePlayer.prototype.createPopup = function (which, tracks) { // Create popup menu and append to player // 'which' parameter is either 'captions', 'chapters', 'prefs', 'transcript-window' or 'sign-window' // 'tracks', if provided, is a list of tracks to be used as menu items var thisObj, $menu, includeMenuItem, i, $menuItem, prefCat, whichPref, hasDefault, track, windowOptions, $thisItem, $prevItem, $nextItem, hasDescription, hasTranscript; thisObj = this; $menu = $('