+ this.hasFallback = true;
+ }
+ i++;
+ }
+ }
+ if (!this.hasFallback) {
+ // the HTML code does not include any nested fallback content
+ // inject our own
+ // NOTE: this message is not translated, since fallback may be needed
+ // due to an error loading the translation file
+ // This will only be needed on very rare occasions, so English is ok.
+ $fallback = $('').text('Media player unavailable.');
+ this.$media.append($fallback);
+ }
+
+ // get height and width attributes, if present
+ // and add them to a style attribute
+ if (this.$media.attr('width')) {
+ this.$media.css('width',this.$media.attr('width') + 'px');
+ }
+ if (this.$media.attr('height')) {
+ this.$media.css('height',this.$media.attr('height') + 'px');
+ }
+ // Remove data-able-player attribute
+ this.$media.removeAttr('data-able-player');
+
+ // Add controls attribute (so browser will add its own controls)
+ this.$media.prop('controls',true);
+
+ if (this.testFallback == 2) {
+
+ // emulate browser failure to support HTML5 media by changing the media tag name
+ // browsers should display the supported content that's nested inside
+ $(this.$media).replaceWith($(''));
+ this.$newFallbackElement = $('#foobar-' + this.mediaId);
+
+ // append all children from the original media
+ if (this.$media.children().length) {
+ i = this.$media.children().length - 1;
+ while (i >= 0) {
+ this.$newFallbackElement.prepend($(this.$media.children()[i]));
+ i--;
+ }
+ }
+ if (!this.hasFallback) {
+ // inject our own fallback content, defined above
+ this.$newFallbackElement.append($fallback);
+ }
+ } else {
+ console.warn("Able Player encountered a problem, falling back to browser's HTML5 player.");
+ }
+ return;
+ };
+
+ AblePlayer.prototype.calculateControlLayout = function () {
+
+ // Calculates the layout for controls based on media and options.
+ // Returns an array with 4 keys (for legacy skin) or 2 keys (for 2020 skin)
+ // Keys are the following order:
+ // 0 = Top left
+ // 1 = Top right
+ // 2 = Bottom left (legacy skin only)
+ // 3 = Bottom right (legacy skin only)
+ // Each key contains an array of control names to put in that section.
+
+ var controlLayout, playbackSupported, numA11yButtons;
+
+ controlLayout = [];
+ controlLayout[0] = [];
+ controlLayout[1] = [];
+ if (this.skin === 'legacy') {
+ controlLayout[2] = [];
+ controlLayout[3] = [];
+ }
+
+ controlLayout[0].push('play');
+ controlLayout[0].push('restart');
+ controlLayout[0].push('rewind');
+ controlLayout[0].push('forward');
+
+ if (this.skin === 'legacy') {
+ controlLayout[1].push('seek');
+ }
+
+ if (this.hasPlaylist) {
+ if (this.skin === 'legacy') {
+ controlLayout[0].push('previous');
+ controlLayout[0].push('next');
+ } else {
+ controlLayout[0].push('previous');
+ controlLayout[0].push('next');
+ }
+ }
+
+ if (this.isPlaybackRateSupported()) {
+ playbackSupported = true;
+ if (this.skin === 'legacy') {
+ controlLayout[2].push('slower');
+ controlLayout[2].push('faster');
+ }
+ } else {
+ playbackSupported = false;
+ }
+
+ numA11yButtons = 0;
+ if (this.hasCaptions) {
+ numA11yButtons++;
+ if (this.skin === 'legacy') {
+ controlLayout[2].push('captions');
+ } else {
+ controlLayout[1].push('captions');
+ }
+ }
+ if (this.hasSignLanguage) {
+ numA11yButtons++;
+ if (this.skin === 'legacy') {
+ controlLayout[2].push('sign');
+ } else {
+ controlLayout[1].push('sign');
+ }
+ }
+ if (this.mediaType === 'video') {
+ if (this.hasOpenDesc || this.hasClosedDesc) {
+ numA11yButtons++;
+ if (this.skin === 'legacy') {
+ controlLayout[2].push('descriptions');
+ } else {
+ controlLayout[1].push('descriptions');
+ }
+ }
+ }
+ if (this.transcriptType !== null && !(this.hideTranscriptButton)) {
+ numA11yButtons++;
+ if (this.skin === 'legacy') {
+ controlLayout[2].push('transcript');
+ } else {
+ controlLayout[1].push('transcript');
+ }
+ }
+ if (this.hasChapters && this.useChaptersButton) {
+ numA11yButtons++;
+ if (this.skin === 'legacy') {
+ controlLayout[2].push('chapters');
+ } else {
+ controlLayout[1].push('chapters');
+ }
+ }
+
+ if (this.skin == '2020' && numA11yButtons > 0) {
+ controlLayout[1].push('pipe');
+ }
+
+ if (playbackSupported && this.skin === '2020') {
+ controlLayout[1].push('faster');
+ controlLayout[1].push('slower');
+ controlLayout[1].push('pipe');
+ }
+
+ if (this.skin === 'legacy') {
+ controlLayout[3].push('preferences');
+ } else {
+ controlLayout[1].push('preferences');
+ }
+
+ if (this.mediaType === 'video' && this.allowFullscreen && this.nativeFullscreenSupported() ) {
+ if (this.skin === 'legacy') {
+ controlLayout[3].push('fullscreen');
+ } else {
+ controlLayout[1].push('fullscreen');
+ }
+ }
+
+ if (this.browserSupportsVolume()) {
+ this.volumeButton = 'volume-' + this.getVolumeName(this.volume);
+ if (this.skin === 'legacy') {
+ controlLayout[1].push('volume');
+ } else {
+ controlLayout[1].push('volume');
+ }
+ } else {
+ this.volume = false;
+ }
+ return controlLayout;
+ };
+
+ AblePlayer.prototype.addControls = function() {
+
+ // determine which controls to show based on several factors:
+ // mediaType (audio vs video)
+ // availability of tracks (e.g., for closed captions & audio description)
+ // browser support (e.g., for sliders and speedButtons)
+ // user preferences (???)
+ // some controls are aligned on the left, and others on the right
+
+ var thisObj, controlLayout, numSections,
+ i, j, controls, $controllerSpan, $sliderDiv, sliderLabel, $pipe, control,
+ buttonTitle, $newButton, buttonText, position, buttonHeight,
+ buttonWidth, buttonSide, controllerWidth, tooltipId, tooltipY, tooltipX,
+ tooltipWidth, tooltipStyle, tooltip, tooltipTimerId, captionLabel, popupMenuId;
+
+ thisObj = this;
+
+ // Initialize the layout into the this.controlLayout variable.
+ controlLayout = this.calculateControlLayout();
+ numSections = controlLayout.length;
+
+ // add an empty div to serve as a tooltip
+ tooltipId = this.mediaId + '-tooltip';
+ this.$tooltipDiv = $('',{
+ 'id': tooltipId,
+ 'class': 'able-tooltip'
+ }).hide();
+ this.$controllerDiv.append(this.$tooltipDiv);
+
+ if (this.skin == '2020') {
+ // add a full-width seek bar
+ $sliderDiv = $('
');
+ sliderLabel = this.mediaType + ' ' + this.translate( 'seekbarLabel', 'timeline' );
+ this.$controllerDiv.append($sliderDiv);
+ this.seekBar = new AccessibleSlider($sliderDiv, this.duration, this.seekInterval, sliderLabel );
+ }
+
+ // add a full-width seek bar
+ let $controlRow = $('
');
+ this.$controllerDiv.append($controlRow);
+
+ for (i = 0; i < numSections; i++) {
+ controls = controlLayout[i];
+ if ((i % 2) === 0) { // even keys on the left
+ $controllerSpan = $('
',{
+ 'class': 'able-left-controls'
+ });
+ } else { // odd keys on the right
+ $controllerSpan = $('
',{
+ 'class': 'able-right-controls'
+ });
+ }
+ $controlRow.append($controllerSpan);
+
+ for (j=0; j
');
+ sliderLabel = this.mediaType + ' ' + this.translate( 'seekbarLabel', 'timeline' );
+ $controllerSpan.append($sliderDiv);
+ if (typeof this.duration === 'undefined' || this.duration === 0) {
+ // set arbitrary starting duration, and change it when duration is known
+ this.duration = 60;
+ // also set elapsed to 0
+ this.elapsed = 0;
+ }
+ this.seekBar = new AccessibleSlider( $sliderDiv, this.duration, this.seekInterval, sliderLabel );
+ } else if (control === 'pipe') {
+ $pipe = $('
', {
+ 'aria-hidden': 'true',
+ 'class': 'able-pipe',
+ });
+ $pipe.append('|');
+ $controllerSpan.append($pipe);
+ } else {
+ // this control is a button
+ buttonTitle = this.getButtonTitle(control);
+
+ // Buttons consist of a with an
inside.
+ // We add aria-label to the button (but not title)
+ // This has been thoroughly tested and works well in all screen reader/browser combinations
+ // See https://github.com/ableplayer/ableplayer/issues/81
+
+ // NOTE: Changed from to elements are rendered poorly in high contrast mode
+ // in some OS/browser/plugin combinations
+
+ // In 5.0.0, icons are always SVG, so the font & image icon edge cases are removed.
+ $newButton = $('
',{
+ 'role': 'button',
+ 'tabindex': '0',
+ 'class': 'able-button-handler-' + control
+ });
+
+ if (control === 'volume' || control === 'preferences' || control === 'captions') {
+ if (control == 'preferences') {
+ this.prefCats = this.getPreferencesGroups();
+ if (this.prefCats.length > 1) {
+ // Prefs button will trigger a menu
+ popupMenuId = this.mediaId + '-prefs-menu';
+ $newButton.attr({
+ 'aria-controls': popupMenuId,
+ 'aria-haspopup': 'menu',
+ 'aria-expanded': 'false'
+ });
+ } else if (this.prefCats.length === 1) {
+ // Prefs button will trigger a dialog
+ $newButton.attr({
+ 'aria-haspopup': 'dialog'
+ });
+ }
+ } else if (control === 'volume') {
+ popupMenuId = this.mediaId + '-volume-slider';
+ // volume slider popup is not a menu or a dialog
+ // therefore, using aria-expanded rather than aria-haspopup to communicate properties/state
+ $newButton.attr({
+ 'aria-controls': popupMenuId,
+ 'aria-expanded': 'false'
+ });
+ } else if (control === 'captions' && this.captions) {
+ if (this.captions.length > 1) {
+ $newButton.attr('aria-expanded', 'false');
+ } else {
+ $newButton.attr('aria-pressed', 'false');
+ }
+ }
+ }
+ var getControl = control;
+ if ( control === 'faster' && this.speedIcons === 'animals' ) {
+ getControl = 'rabbit';
+ }
+ if ( control === 'slower' && this.speedIcons === 'animals' ) {
+ getControl = 'turtle';
+ }
+ if ( control === 'volume' ) {
+ this.getIcon( $newButton, this.volumeButton );
+ } else {
+ if ( 'fullscreen' === getControl ) {
+ getControl = ( this.fullscreen ) ? 'fullscreen-collapse' : 'fullscreen-expand';
+ }
+ this.getIcon( $newButton, getControl );
+ }
+
+ this.setText($newButton,buttonTitle);
+ // add an event listener that displays a tooltip on mouseenter or focus
+ $newButton.on('mouseenter focus',function(e) {
+
+ // when entering a new tooltip, we can forget about hiding the previous tooltip.
+ // since the same tooltip div is used, it's location just changes.
+ clearTimeout(tooltipTimerId);
+
+ buttonText = $(this).attr('aria-label');
+ // get position of this button
+ position = $(this).position();
+ buttonHeight = $(this).height();
+ buttonWidth = $(this).width();
+ // position() is expressed using top and left (of button);
+ // add right (of button) too, for convenience
+ controllerWidth = thisObj.$controllerDiv.width();
+ position.right = controllerWidth - position.left - buttonWidth;
+
+ // The following formula positions tooltip below the button
+ // which allows the tooltip to be hoverable as per WCAG 2.x SC 1.4.13
+ // without obstructing the seekbar
+ tooltipY = position.top + buttonHeight + 5;
+
+ if ($(this).parent().hasClass('able-right-controls')) {
+ // this control is on the right side
+ buttonSide = 'right';
+ } else {
+ // this control is on the left side
+ buttonSide = 'left';
+ }
+ // populate tooltip, then calculate its width before showing it
+ tooltipWidth = AblePlayer.localGetElementById($newButton[0], tooltipId).text(buttonText).width();
+ // center the tooltip horizontally over the button
+ if (buttonSide == 'left') {
+ tooltipX = position.left - tooltipWidth/2;
+ if (tooltipX < 0) {
+ // tooltip would exceed the bounds of the player. Adjust.
+ tooltipX = 2;
+ }
+ tooltipStyle = {
+ left: tooltipX + 'px',
+ right: '',
+ top: tooltipY + 'px'
+ };
+ } else {
+ tooltipX = position.right - tooltipWidth/2;
+ if (tooltipX < 0) {
+ // tooltip would exceed the bounds of the player. Adjust.
+ tooltipX = 2;
+ }
+ tooltipStyle = {
+ left: '',
+ right: tooltipX + 'px',
+ top: tooltipY + 'px'
+ };
+ }
+ tooltip = AblePlayer.localGetElementById($newButton[0], tooltipId).text(buttonText).css(tooltipStyle);
+ thisObj.showTooltip(tooltip);
+ $(this).on('mouseleave blur',function() {
+
+ // (keep the tooltip visible if user hovers over it)
+ // This causes unwanted side effects if tooltips are positioned above the buttons
+ // as the persistent tooltip obstructs the seekbar,
+ // blocking users from being able to move a pointer from a button to the seekbar
+ // This limitation was addressed in 4.4.49 by moving the tooltip below the buttons
+
+ // clear existing timeout before reassigning variable
+ clearTimeout(tooltipTimerId);
+ tooltipTimerId = setTimeout(function() {
+ // give the user a half second to move cursor to tooltip before removing
+ // see https://www.w3.org/WAI/WCAG21/Understanding/content-on-hover-or-focus#hoverable
+ AblePlayer.localGetElementById($newButton[0], tooltipId).text('').hide();
+ }, 500);
+
+ thisObj.$tooltipDiv.on('mouseenter focus', function() {
+ clearTimeout(tooltipTimerId);
+ });
+
+ thisObj.$tooltipDiv.on('mouseleave blur', function() {
+ AblePlayer.localGetElementById($newButton[0], tooltipId).text('').hide();
+ });
+
+ });
+ });
+
+ if (control === 'captions') {
+ if (!this.prefCaptions || this.prefCaptions !== 1) {
+ // captions are available, but user has them turned off
+ if (this.captions.length > 1) {
+ captionLabel = this.translate( 'captions', 'Captions' );
+ } else {
+ captionLabel = this.translate( 'showCaptions', 'Show captions' );
+ }
+ $newButton.addClass('buttonOff').attr('title',captionLabel);
+ $newButton.attr('aria-pressed', 'false');
+ }
+ } else if (control === 'descriptions') {
+ if (!this.prefDesc || this.prefDesc !== 1) {
+ // user prefer non-audio described version
+ // Therefore, load media without description
+ // Description can be toggled on later with this button
+ $newButton.addClass('buttonOff').attr( 'title', this.translate( 'turnOnDescriptions', 'Turn on descriptions' ) );
+ }
+ }
+
+ $controllerSpan.append($newButton);
+
+ // create variables of buttons that are referenced throughout the AblePlayer object
+ if (control === 'play') {
+ this.$playpauseButton = $newButton;
+ } else if (control == 'previous') {
+ this.$prevButton = $newButton;
+ // if player is being rebuilt because user clicked the Prev button
+ // return focus to that (newly built) button
+ if (this.buttonWithFocus == 'previous') {
+ this.$prevButton.trigger('focus');
+ this.buttonWithFocus = null;
+ }
+ } else if (control == 'next') {
+ this.$nextButton = $newButton;
+ // if player is being rebuilt because user clicked the Next button
+ // return focus to that (newly built) button
+ if (this.buttonWithFocus == 'next') {
+ this.$nextButton.trigger('focus');
+ this.buttonWithFocus = null;
+ }
+ } else if (control === 'captions') {
+ this.$ccButton = $newButton;
+ } else if (control === 'sign') {
+ this.$signButton = $newButton;
+ // gray out sign button if sign language window is not active
+ if (!(this.$signWindow.is(':visible'))) {
+ this.$signButton.addClass('buttonOff');
+ }
+ } else if (control === 'descriptions') {
+ this.$descButton = $newButton;
+ // button will be enabled or disabled in description.js > initDescription()
+ } else if (control === 'mute') {
+ this.$muteButton = $newButton;
+ } else if (control === 'transcript') {
+ this.$transcriptButton = $newButton;
+ // gray out transcript button if transcript is not active
+ if (!(this.$transcriptDiv.is(':visible'))) {
+ this.$transcriptButton.addClass('buttonOff').attr( 'title', this.translate( 'showTranscript', 'Show transcript' ) );
+ }
+ } else if (control === 'fullscreen') {
+ this.$fullscreenButton = $newButton;
+ } else if (control === 'chapters') {
+ this.$chaptersButton = $newButton;
+ } else if (control === 'preferences') {
+ this.$prefsButton = $newButton;
+ } else if (control === 'volume') {
+ this.$volumeButton = $newButton;
+ }
+ }
+ if (control === 'volume') {
+ // in addition to the volume button, add a hidden slider
+ this.addVolumeSlider($controllerSpan);
+ }
+ }
+ if ((i % 2) == 1) {
+ this.$controllerDiv.append('
');
+ }
+ }
+
+ if (typeof this.$captionsDiv !== 'undefined') {
+ // stylize captions based on user prefs
+ this.stylizeCaptions(this.$captionsDiv);
+ }
+ if (typeof this.$descDiv !== 'undefined') {
+ // stylize descriptions based on user's caption prefs
+ this.stylizeCaptions(this.$descDiv);
+ }
+
+ // combine left and right controls arrays for future reference
+ this.controls = [];
+ for (var sec in controlLayout) if (Object.hasOwn(controlLayout, sec)) {
+ this.controls = this.controls.concat(controlLayout[sec]);
+ }
+
+ // Update state-based display of controls.
+ this.refreshControls();
+ };
+
+ AblePlayer.prototype.cuePlaylistItem = function(sourceIndex) {
+
+ // Move to a new item in a playlist.
+ // NOTE: Swapping source for audio description is handled elsewhere;
+ // see description.js > swapDescription()
+
+ var $newItem, prevPlayer, newPlayer, itemTitle, itemLang, nowPlayingSpan;
+
+ var thisObj = this;
+
+ prevPlayer = this.player;
+
+ if (this.initializing) ; else {
+ if (this.playerCreated) {
+ // remove the old
+ this.deletePlayer('playlist');
+ }
+ }
+
+ // set swappingSrc; needs to be true within recreatePlayer(), called below
+ this.swappingSrc = true;
+
+ // if a new playlist item is being requested, and playback has already started,
+ // it should be ok to play automatically, regardless of how it was requested
+ if (this.startedPlaying) {
+ this.okToPlay = true;
+ } else {
+ this.okToPlay = false;
+ }
+
+ // We are no longer loading the previous media source
+ // Only now, as a new source is requested, is it safe to reset this var
+ // It will be reset to true when media.load() is called
+ this.loadingMedia = false;
+
+ // Determine appropriate player to play this media
+ $newItem = this.$playlist.eq(sourceIndex);
+ this.playlistIndex = sourceIndex;
+ if (this.hasAttr($newItem,'data-youtube-id')) {
+ this.youTubeId = this.getYouTubeId($newItem.attr('data-youtube-id'));
+ if (this.hasAttr($newItem,'data-youtube-desc-id')) {
+ this.youTubeDescId = this.getYouTubeId($newItem.attr('data-youtube-desc-id'));
+ }
+ newPlayer = 'youtube';
+ } else if (this.hasAttr($newItem,'data-vimeo-id')) {
+ this.vimeoId = this.getVimeoId($newItem.attr('data-vimeo-id'));
+ if (this.hasAttr($newItem,'data-vimeo-desc-id')) {
+ this.vimeoDescId = this.getVimeoId($newItem.attr('data-vimeo-desc-id'));
+ }
+ newPlayer = 'vimeo';
+ } else {
+ newPlayer = 'html5';
+ }
+ if (newPlayer === 'youtube') {
+ if (prevPlayer === 'html5') {
+ // pause and hide the previous media
+ if (this.playing) {
+ this.pauseMedia();
+ }
+ this.$media.hide();
+ }
+ } else {
+ // the new player is not youtube
+ this.youTubeId = false;
+ if (prevPlayer === 'youtube') {
+ // unhide the media element
+ this.$media.show();
+ }
+ }
+ this.player = newPlayer;
+
+ // remove source and track elements from previous playlist item
+ this.$media.empty();
+
+ // transfer media attributes from playlist to media element
+ if (this.hasAttr($newItem,'data-poster')) {
+ this.$media.attr('poster',$newItem.attr('data-poster'));
+ }
+ if (this.hasAttr($newItem,'data-youtube-desc-id')) {
+ this.$media.attr('data-youtube-desc-id',$newItem.attr('data-youtube-desc-id'));
+ }
+ if (this.youTubeId) {
+ this.$media.attr('data-youtube-id',$newItem.attr('data-youtube-id'));
+ }
+
+ // add new
elements from playlist data
+ var $sourceSpans = $newItem.children('span.able-source');
+ if ($sourceSpans.length) {
+ $sourceSpans.each(function() {
+ const $this = $(this);
+
+ // Check if the required data-src attribute exists
+ if (thisObj.hasAttr($this, "data-src")) {
+ const sanitizedSrc = purify.sanitize($this.attr("data-src"));
+
+ // Validate the protocol of the sanitized URL
+ if (validate.isProtocolSafe(sanitizedSrc)) {
+ // Create a new element with the sanitized src
+ const $newSource = $("", { src: sanitizedSrc });
+
+ // List of optional attributes to sanitize and add
+ const optionalAttributes = [
+ "data-type",
+ "data-desc-src",
+ "data-sign-src",
+ ];
+
+ // Process optional attributes
+ optionalAttributes.forEach((attr) => {
+ if (thisObj.hasAttr($this, attr)) {
+ const attrValue = $this.attr(attr); // Get the attribute value
+ const sanitizedValue = purify.sanitize(attrValue); // Sanitize the value
+
+ // If the attribute ends with "-src", validate the protocol
+ if (attr.endsWith("-src") && validate.isProtocolSafe(sanitizedValue)) {
+ $newSource.attr(attr, sanitizedValue); // Add the sanitized and validated attribute
+ } else if (!attr.endsWith("-src")) {
+ $newSource.attr(attr, sanitizedValue); // Add sanitized value for non-src attributes
+ }
+ }
+ });
+
+ // Append the new element to the media object
+ thisObj.$media.append($newSource);
+ }
+ }
+ });
+ }
+
+ // add new elements from playlist data
+ var $trackSpans = $newItem.children('span.able-track');
+ if ($trackSpans.length) {
+ // for each element in $trackSpans, create a new element
+ $trackSpans.each(function() {
+ const $this = $(this);
+ if (thisObj.hasAttr($this, "data-src") && thisObj.hasAttr($this, "data-kind") && thisObj.hasAttr($this, "data-srclang")) {
+ // all required attributes are present
+ const sanitizedSrc = purify.sanitize($this.attr("data-src"));
+ // Validate the protocol of the sanitized URL
+ if (validate.isProtocolSafe(sanitizedSrc)) {
+ // Create a new element with the sanitized src
+ const $newTrack = $("", {
+ src: sanitizedSrc,
+ kind: $this.attr("data-kind"),
+ srclang: $this.attr("data-srclang"),
+ });
+ // List of optional attributes to sanitize and add
+ const optionalAttributes = [
+ "data-label",
+ "data-desc",
+ "data-default",
+ ];
+ optionalAttributes.forEach((attr) => {
+ if (thisObj.hasAttr($this, attr)) {
+ $newTrack.attr(attr, purify.sanitize($this.attr(attr)));
+ }
+ });
+ // Append the new element to the media object
+ thisObj.$media.append($newTrack);
+ }
+ }
+ });
+ }
+
+ itemTitle = purify.sanitize( $newItem.text() );
+ if (this.hasAttr($newItem,'lang')) {
+ itemLang = $newItem.attr('lang');
+ }
+ // Update relevant arrays
+ this.$sources = this.$media.find('source');
+
+ // recreate player, informed by new attributes and track elements
+ if (this.recreatingPlayer) {
+ // stopgap to prevent multiple firings of recreatePlayer()
+ return;
+ }
+ this.recreatePlayer().then(function() {
+
+ // update playlist to indicate which item is playing
+ thisObj.$playlist.removeClass('able-current')
+ .children('button').removeAttr('aria-current');
+ thisObj.$playlist.eq(sourceIndex).addClass('able-current')
+ .children('button').attr('aria-current','true');
+
+ // update Now Playing div
+ if (thisObj.showNowPlaying === true) {
+ if (typeof thisObj.$nowPlayingDiv !== 'undefined') {
+ nowPlayingSpan = $('');
+ if (typeof itemLang !== 'undefined') {
+ nowPlayingSpan.attr('lang',itemLang);
+ }
+ nowPlayingSpan.html('' + thisObj.translate( 'selectedTrack', 'Selected Track' ) + ': ' + itemTitle);
+ thisObj.$nowPlayingDiv.html(nowPlayingSpan);
+ }
+ }
+
+ // if thisObj.swappingSrc is true, media will autoplay when ready
+ if (thisObj.initializing) { // this is the first track - user hasn't pressed play yet
+ thisObj.swappingSrc = false;
+ } else {
+ if (thisObj.player === 'html5') {
+ if (!thisObj.loadingMedia) {
+ thisObj.media.load();
+ thisObj.loadingMedia = true;
+ }
+ } else if (thisObj.player === 'youtube') {
+ thisObj.okToPlay = true;
+ }
+ }
+ thisObj.initializing = false;
+ thisObj.playerCreated = true; // remains true until browser is refreshed
+ });
+ };
+
+ AblePlayer.prototype.deletePlayer = function(context) {
+
+ // remove player components that need to be rebuilt
+ // after swapping media sources that have different durations
+ // or explicitly declared data-desc attributes
+
+ // Context is one of the following:
+ // playlist - called from cuePlaylistItem()
+ // swap-desc-html - called from swapDescription with this.player == 'html'
+ // swap-desc-youtube - called from swapDescription with this.player == 'youtube'
+ // swap-desc-vimeo - called from swapDescription with this.player == 'vimeo'
+
+ if (this.player === 'youtube' && this.youTubePlayer) {
+ this.youTubePlayer.destroy();
+ }
+
+ if (this.player === 'vimeo' && this.vimeoPlayer) {
+ this.vimeoPlayer.destroy();
+ }
+
+ // Empty elements that will be rebuilt
+ this.$controllerDiv.empty();
+ // this.$statusBarDiv.empty();
+ // this.$timer.empty();
+ this.$elapsedTimeContainer.empty().text('0:00'); // span.able-elapsedTime
+ this.$durationContainer.empty(); // span.able-duration
+
+ // Remove popup windows and modal dialogs; these too will be rebuilt
+ if (this.$signWindow) {
+ this.$signWindow.remove();
+ }
+ if (this.$transcriptArea) {
+ this.$transcriptArea.remove();
+ }
+ $('.able-modal-dialog').remove();
+
+ // Remove caption and description wrappers
+ if (this.$captionsWrapper) {
+ this.$captionsWrapper.remove();
+ }
+ if (this.$descDiv) {
+ this.$descDiv.remove();
+ }
+
+ // reset key variables
+ this.hasCaptions = false;
+ this.hasChapters = false;
+ this.hasDescTracks = false;
+ this.hasOpenDesc = false;
+ this.hasClosedDesc = false;
+
+ this.captionsPopup = null;
+ this.chaptersPopup = null;
+ this.transcriptType = null;
+
+ this.playerDeleted = true; // will reset to false in recreatePlayer()
+ };
+
+ AblePlayer.prototype.getButtonTitle = function(control) {
+
+ if (control === 'playpause') {
+ return this.translate( 'play', 'Play' );
+ } else if (control === 'play') {
+ return this.translate( 'play', 'Play' );
+ } else if (control === 'pause') {
+ return this.translate( 'pause', 'Pause' );
+ } else if (control === 'restart') {
+ return this.translate( 'restart', 'Restart' );
+ } else if (control === 'previous') {
+ return this.translate( 'prevTrack', 'Previous track' );
+ } else if (control === 'next') {
+ return this.translate( 'nextTrack', 'Next track' );
+ } else if (control === 'rewind') {
+ return this.translate( 'rewind', 'Rewind' );
+ } else if (control === 'forward') {
+ return this.translate( 'forward', 'Forward' );
+ } else if (control === 'captions') {
+ if (this.captions.length > 1) {
+ return this.translate( 'captions', 'Captions' );
+ } else {
+ return (this.captionsOn) ? this.translate( 'hideCaptions', 'Hide captions' ) : this.translate( 'showCaptions', 'Show captions' );
+ }
+ } else if (control === 'descriptions') {
+ return (this.descOn) ? this.translate( 'turnOffDescriptions', 'Turn off descriptions' ) : this.translate( 'turnOnDescriptions', 'Turn on descriptions' );
+ } else if (control === 'transcript') {
+ return (this.$transcriptDiv.is(':visible')) ? this.translate( 'hideTranscript', 'Hide transcript' ) : this.translate( 'showTranscript', 'Show transcript' );
+ } else if (control === 'chapters') {
+ return this.translate( 'chapters', 'Chapters' );
+ } else if (control === 'sign') {
+ return this.translate( 'sign', 'Sign language' );
+ } else if (control === 'volume') {
+ return this.translate( 'volume', 'Volume' );
+ } else if (control === 'faster') {
+ return this.translate( 'faster', 'Faster' );
+ } else if (control === 'slower') {
+ return this.translate( 'slower', 'Slower' );
+ } else if (control === 'preferences') {
+ return this.translate( 'preferences', 'Preferences' );
+ } else if (control === 'fullscreen') {
+ return ( !this.fullscreen ) ? this.translate( 'enterFullScreen', 'Enter full screen' ) : this.translate( 'exitFullScreen', 'Exit full screen' );
+ } else {
+ // there should be no other controls, but just in case:
+ // return the name of the control with first letter in upper case
+ // ultimately will need to get a translated label from this.tt
+ if (this.debug) ;
+ return this.capitalizeFirstLetter( control );
+ }
+ };
+ }
- var startTime = $(media).data('start-time');
- var isNumeric = ( typeof startTime === 'number' || ( typeof startTime === 'string' && value.trim() !== '' && ! isNaN(value) && isFinite( Number(value) ) ) ) ? true : false;
- this.startTime = ( startTime !== undefined && isNumeric ) ? startTime : 0;
+ function addCaptionFunctions(AblePlayer) {
+ AblePlayer.prototype.updateCaption = function (time) {
+ if (
+ !this.usingYouTubeCaptions &&
+ !this.usingVimeoCaptions &&
+ typeof this.$captionsWrapper !== "undefined"
+ ) {
+ if (this.captionsOn) {
+ this.$captionsWrapper.show();
+ if (typeof time !== "undefined") {
+ this.showCaptions(time);
+ }
+ } else if (this.$captionsWrapper) {
+ this.$captionsWrapper.hide();
+ this.prefCaptions = 0;
+ }
+ }
+ };
- this.debug = ($(media).data('debug') !== undefined && $(media).data('debug') !== false) ? true : false;
+ AblePlayer.prototype.updateCaptionsMenu = function (lang) {
+ // uncheck all previous menu items
+ this.captionsPopup.find("li").attr("aria-checked", "false");
+ if (typeof lang === "undefined") {
+ // check the last menu item (captions off)
+ this.captionsPopup.find("li").last().attr("aria-checked", "true");
+ } else {
+ // check the newly selected lang
+ this.captionsPopup
+ .find("li[lang=" + lang + "]")
+ .attr("aria-checked", "true");
+ }
+ };
- if ($(media).data('root-path') !== undefined) {
- this.rootPath = $(media).data('root-path').replace(/\/?$/, '/');
- } else {
- this.rootPath = this.getRootPath();
- }
-
- this.defaultVolume = 7;
- if ($(media).data('volume') !== undefined && $(media).data('volume') !== "") {
- var volume = $(media).data('volume');
- if (volume >= 0 && volume <= 10) {
- this.defaultVolume = volume;
- }
- }
- this.volume = this.defaultVolume;
-
-
- if ($(media).data('use-chapters-button') !== undefined && $(media).data('use-chapters-button') === false) {
- this.useChaptersButton = false;
- } else {
- this.useChaptersButton = true;
- }
-
- if ($(media).data('descriptions-audible') !== undefined && $(media).data('descriptions-audible') === false) {
- this.readDescriptionsAloud = false;
- } else if ($(media).data('description-audible') !== undefined && $(media).data('description-audible') === false) {
- this.readDescriptionsAloud = false;
- } else {
- this.readDescriptionsAloud = true;
- }
-
- this.descVoices = [];
-
- this.descReader = ($(media).data('desc-reader') == 'screenreader') ? 'screenreader' : 'browser';
-
- this.defaultStateCaptions = ($(media).data('state-captions') == 'off') ? 0 : 1;
- this.defaultStateDescriptions = ($(media).data('state-descriptions') == 'on') ? 1 : 0;
-
- this.defaultDescPause = ($(media).data('desc-pause-default') == 'off') ? 0 : 1;
-
- if ($(media).data('heading-level') !== undefined && $(media).data('heading-level') !== "") {
- var headingLevel = $(media).data('heading-level');
- if (/^[0-6]*$/.test(headingLevel)) {
- this.playerHeadingLevel = headingLevel;
- }
- }
-
- var transcriptDivLocation = $(media).data('transcript-div');
- if ( transcriptDivLocation !== undefined && transcriptDivLocation !== "" && null !== document.getElementById( transcriptDivLocation ) ) {
- this.transcriptDivLocation = transcriptDivLocation;
- } else {
- this.transcriptDivLocation = null;
- }
- var includeTranscript = $(media).data('include-transcript');
- this.hideTranscriptButton = ( includeTranscript !== undefined && includeTranscript === false) ? true : false;
-
- this.transcriptType = null;
- if ($(media).data('transcript-src') !== undefined) {
- this.transcriptSrc = $(media).data('transcript-src');
- if (this.transcriptSrcHasRequiredParts()) {
- this.transcriptType = 'manual';
- } else {
-
- }
- } else if ($(media).find('track[kind="captions"],track[kind="subtitles"],track:not([kind])').length > 0) {
- this.transcriptType = (this.transcriptDivLocation) ? 'external' : 'popup';
- }
-
- this.lyricsMode = ($(media).data('lyrics-mode') !== undefined && $(media).data('lyrics-mode') !== false) ? true : false;
-
- if ($(media).data('transcript-title') !== undefined && $(media).data('transcript-title') !== "") {
- this.transcriptTitle = $(media).data('transcript-title');
- }
-
- var signDivLocation = $(media).data('sign-div');
- if ( signDivLocation !== undefined && signDivLocation !== "" && null !== document.getElementById( signDivLocation ) ) {
- this.$signDivLocation = $( '#' + signDivLocation );
- } else {
- this.$signDivLocation = null;
- }
-
- this.defaultCaptionsPosition = ($(media).data('captions-position') === 'overlay') ? 'overlay' : 'below';
-
- var chaptersDiv = $(media).data('chapters-div');
- if ( chaptersDiv !== undefined && chaptersDiv !== "") {
- this.chaptersDivLocation = chaptersDiv;
- }
-
- if ($(media).data('chapters-title') !== undefined) {
- this.chaptersTitle = $(media).data('chapters-title');
- }
-
- var defaultChapter = $(media).data('chapters-default');
- this.defaultChapter = ( defaultChapter !== undefined && defaultChapter !== "") ? defaultChapter : null;
-
- this.speedIcons = ($(media).data('speed-icons') === 'arrows') ? 'arrows' : 'animals';
-
- var seekbarScope = $(media).data('seekbar-scope');
- this.seekbarScope = ( seekbarScope === 'chapter' || seekbarScope === 'chapters') ? 'chapter' : 'video';
-
- var youTubeId = $(media).data('youtube-id');
- if ( youTubeId !== undefined && youTubeId !== "") {
- this.youTubeId = this.getYouTubeId(youTubeId);
- if ( ! this.hasPoster ) {
- let poster = this.getYouTubePosterUrl(this.youTubeId,'640');
- $(media).attr( 'poster', poster );
- }
- }
-
- var youTubeDescId = $(media).data('youtube-desc-id');
- if ( youTubeDescId !== undefined && youTubeDescId !== "") {
- this.youTubeDescId = this.getYouTubeId(youTubeDescId);
- }
-
- var youTubeSignId = $(media).data('youtube-sign-src');
- if ( youTubeSignId !== undefined && youTubeSignId !== "") {
- this.youTubeSignId = this.getYouTubeId(youTubeSignId);
- }
-
- var youTubeNoCookie = $(media).data('youtube-nocookie');
- this.youTubeNoCookie = (youTubeNoCookie !== undefined && youTubeNoCookie) ? true : false;
-
- var vimeoId = $(media).data('vimeo-id');
- if ( vimeoId !== undefined && vimeoId !== "") {
- this.vimeoId = this.getVimeoId(vimeoId);
- if ( ! this.hasPoster ) {
- let poster = thisObj.getVimeoPosterUrl(this.vimeoId,'1200');
- $(media).attr( 'poster', poster );
- }
- }
- var vimeoDescId = $(media).data('vimeo-desc-id');
- if ( vimeoDescId !== undefined && vimeoDescId !== "") {
- this.vimeoDescId = this.getVimeoId(vimeoDescId);
- }
-
- this.skin = ($(media).data('skin') == 'legacy') ? 'legacy' : '2020';
-
- if ($(media).data('width') !== undefined) {
- this.playerWidth = parseInt($(media).data('width'));
- } else if ($(media)[0].getAttribute('width')) {
- this.playerWidth = parseInt($(media)[0].getAttribute('width'));
- } else {
- this.playerWidth = null;
- }
-
- this.iconType = 'font';
- this.forceIconType = false;
- if ($(media).data('icon-type') !== undefined && $(media).data('icon-type') !== "") {
- var iconType = $(media).data('icon-type');
- if (iconType === 'font' || iconType === 'image' || iconType === 'svg') {
- this.iconType = iconType;
- this.forceIconType = true;
- }
- }
-
- var allowFullScreen = $(media).data('allow-fullscreen');
- this.allowFullscreen = (allowFullScreen !== undefined && allowFullScreen === false) ? false : true;
-
- this.clickedFullscreenButton = false;
- this.restoringAfterFullscreen = false;
-
- this.defaultSeekInterval = 10;
- this.useFixedSeekInterval = false;
- if ($(media).data('seek-interval') !== undefined && $(media).data('seek-interval') !== "") {
- var seekInterval = $(media).data('seek-interval');
- if (/^[1-9][0-9]*$/.test(seekInterval)) {
- this.seekInterval = seekInterval;
- this.useFixedSeekInterval = true;
- }
- }
-
- var showNowPlaying = $(media).data('show-now-playing');
- this.showNowPlaying = (showNowPlaying !== undefined && showNowPlaying === false) ? false : true;
-
- if ($(media).data('use-ttml') !== undefined) {
- this.useTtml = true;
- this.convert = require('xml-js');
- } else {
- this.useTtml = false;
- }
-
- var testFallback = $(media).data('test-fallback');
- if ( testFallback !== undefined && testFallback !== false) {
- this.testFallback = ( testFallback == '2' ) ? 2 : 1;
- } else {
- this.testFallback = false;
- }
-
- var lang = $(media).data('lang');
- this.lang = ( lang !== undefined && lang !== "") ? lang.toLowerCase() : null;
-
- var metaType = $(media).data('meta-type');
- if ( metaType !== undefined && metaType !== "") {
- this.metaType = metaType;
- }
- var metaDiv = $(media).data('meta-div');
- if ( metaDiv !== undefined && metaDiv !== "") {
- this.metaDiv = metaDiv;
- }
-
- var searchDiv = $(media).data('search-div');
- if ( searchDiv !== undefined && searchDiv !== "") {
-
- this.searchDiv = searchDiv;
-
- var searchString = $(media).data('search');
- if ( searchString !== undefined && searchString !== "") {
- this.searchString = searchString;
- }
-
- var searchLang = $(media).data('search-lang');
- this.searchLang = ( searchLang !== undefined && searchLang !== "") ? searchLang : null;
-
- var searchIgnoreCaps = $(media).data('search-ignore-caps');
- this.searchIgnoreCaps = ( searchIgnoreCaps !== undefined && searchIgnoreCaps !== false) ? true : false;
- }
-
- if ($(media).data('hide-controls') !== undefined && $(media).data('hide-controls') !== false) {
- this.hideControls = true;
- this.hideControlsOriginal = true;
- } else {
- this.hideControls = false;
- this.hideControlsOriginal = false;
- }
-
- if ($(media).data('steno-mode') !== undefined && $(media).data('steno-mode') !== false) {
- this.stenoMode = true;
- if ($(media).data('steno-iframe-id') !== undefined && $(media).data('steno-iframe-id') !== "") {
- this.stenoFrameId = $(media).data('steno-iframe-id');
- this.$stenoFrame = $('#' + this.stenoFrameId);
- if (!(this.$stenoFrame.length)) {
- this.stenoFrameId = null;
- this.$stenoFrame = null;
- }
- } else {
- this.stenoFrameId = null;
- this.$stenoFrame = null;
- }
- } else {
- this.stenoMode = false;
- this.stenoFrameId = null;
- this.$stenoFrame = null;
- }
-
- this.setDefaults();
-
-
- this.ableIndex = AblePlayer.nextIndex;
- AblePlayer.nextIndex += 1;
-
- this.title = $(media).attr('title');
-
- this.tt = {};
- var thisObj = this;
- async function fetchTranslations(thisObj) {
- try {
- await thisObj.getTranslationText();
- thisObj.setup();
- } catch {
- thisObj.provideFallback();
- }
- }
- fetchTranslations(thisObj);
- };
-
- AblePlayer.nextIndex = 0;
-
- AblePlayer.prototype.setup = function() {
-
- var thisObj = this;
- this.initializing = true;
-
- this.reinitialize().then(function () {
- if (!thisObj.player) {
- thisObj.provideFallback();
- } else {
- thisObj.setupInstance().then(function () {
- thisObj.setupInstancePlaylist();
- if (thisObj.hasPlaylist) {
- } else {
- thisObj.recreatePlayer().then(function() {
- thisObj.initializing = false;
- thisObj.playerCreated = true;
- });
- }
- });
- }
- });
- };
-
- AblePlayer.getActiveDOMElement = function () {
- var activeElement = document.activeElement;
-
- while (activeElement.shadowRoot && activeElement.shadowRoot.activeElement) {
- activeElement = activeElement.shadowRoot.activeElement;
- }
-
- return activeElement;
- };
-
- AblePlayer.localGetElementById = function(element, id) {
- if (element.getRootNode) {
- return $(element.getRootNode().querySelector('#' + id));
- } else {
- return $(document.getElementById(id));
- }
- };
-
- AblePlayer.youTubeIframeAPIReady = false;
- AblePlayer.loadingYouTubeIframeAPI = false;
-})(jQuery);
-
-(function ($) {
- AblePlayer.prototype.setDefaults = function () {
-
- this.playerCreated = false;
- this.playing = false;
- this.paused = true;
- this.clickedPlay = false;
- this.fullscreen = false;
- this.swappingSrc = false;
- this.initializing = false;
- this.cueingPlaylistItems = false;
- this.buttonWithFocus = null;
- this.speechEnabled = null;
-
- this.setIconColor();
- this.setButtonImages();
- };
-
- AblePlayer.prototype.getRootPath = function() {
-
- var scripts, i, scriptSrc, scriptFile, fullPath, ablePath, parentFolderIndex, rootPath;
- scripts= document.getElementsByTagName('script');
- for (i=0; i < scripts.length; i++) {
- scriptSrc = scripts[i].src;
- scriptFile = scriptSrc.substring(scriptSrc.lastIndexOf('/'));
- if (scriptFile.indexOf('ableplayer') !== -1) {
- fullPath = scriptSrc.split('?')[0];
- break;
- }
- }
- ablePath= fullPath.split('/').slice(0, -1).join('/');
- parentFolderIndex = ablePath.lastIndexOf('/');
- rootPath = ablePath.substring(0, parentFolderIndex) + '/';
- return rootPath;
- }
-
- AblePlayer.prototype.setIconColor = function() {
-
-
-
- var $elements, i, $el, bgColor, rgb, red, green, blue, luminance, iconColor;
-
- $elements = ['controller', 'toolbar'];
- for (i=0; i<$elements.length; i++) {
- if ($elements[i] == 'controller') {
- $el = $('', {
- 'class': 'able-controller'
- }).hide();
- } else if ($elements[i] === 'toolbar') {
- $el = $('
', {
- 'class': 'able-window-toolbar'
- }).hide();
- }
- $('body').append($el);
- bgColor = $el.css('background-color');
- rgb = bgColor.replace(/[^\d,]/g, '').split(',');
- red = rgb[0];
- green = rgb[1];
- blue = rgb[2];
- luminance = (0.2126 * red) + (0.7152 * green) + (0.0722 * blue);
- iconColor = (luminance < 125) ? 'white' : 'black';
-
- if ($elements[i] === 'controller') {
- this.iconColor = iconColor;
- } else if ($elements[i] === 'toolbar') {
- this.toolbarIconColor = iconColor;
- }
- $el.remove();
- }
- };
-
- AblePlayer.prototype.setButtonImages = function() {
-
- this.imgPath = this.rootPath + 'button-icons/' + this.iconColor + '/';
- this.playButtonImg = this.imgPath + 'play.png';
- this.pauseButtonImg = this.imgPath + 'pause.png';
- this.restartButtonImg = this.imgPath + 'restart.png';
- this.rewindButtonImg = this.imgPath + 'rewind.png';
- this.forwardButtonImg = this.imgPath + 'forward.png';
- this.previousButtonImg = this.imgPath + 'previous.png';
- this.nextButtonImg = this.imgPath + 'next.png';
-
- if (this.speedIcons === 'arrows') {
- this.fasterButtonImg = this.imgPath + 'slower.png';
- this.slowerButtonImg = this.imgPath + 'faster.png';
- } else if (this.speedIcons === 'animals') {
- this.fasterButtonImg = this.imgPath + 'rabbit.png';
- this.slowerButtonImg = this.imgPath + 'turtle.png';
- }
-
- this.captionsButtonImg = this.imgPath + 'captions.png';
- this.chaptersButtonImg = this.imgPath + 'chapters.png';
- this.signButtonImg = this.imgPath + 'sign.png';
- this.transcriptButtonImg = this.imgPath + 'transcript.png';
- this.descriptionsButtonImg = this.imgPath + 'descriptions.png';
- this.fullscreenExpandButtonImg = this.imgPath + 'fullscreen-expand.png';
- this.fullscreenCollapseButtonImg = this.imgPath + 'fullscreen-collapse.png';
- this.prefsButtonImg = this.imgPath + 'preferences.png';
- this.helpButtonImg = this.imgPath + 'help.png';
- };
-
- AblePlayer.prototype.getIconData = function(button) {
-
- var svg = Array();
-
- switch (button) {
-
- case 'play':
- svg[0] = '0 0 16 20';
- svg[1] = 'M0 18.393v-16.429q0-0.29 0.184-0.402t0.441 0.033l14.821 8.237q0.257 0.145 0.257 0.346t-0.257 0.346l-14.821 8.237q-0.257 0.145-0.441 0.033t-0.184-0.402z';
- svg[2] = 'icon-play';
- svg[3] = this.playButtonImg;
- break;
-
- case 'pause':
- svg[0] = '0 0 20 20';
- svg[1] = 'M0 18.036v-15.714q0-0.29 0.212-0.502t0.502-0.212h5.714q0.29 0 0.502 0.212t0.212 0.502v15.714q0 0.29-0.212 0.502t-0.502 0.212h-5.714q-0.29 0-0.502-0.212t-0.212-0.502zM10 18.036v-15.714q0-0.29 0.212-0.502t0.502-0.212h5.714q0.29 0 0.502 0.212t0.212 0.502v15.714q0 0.29-0.212 0.502t-0.502 0.212h-5.714q-0.29 0-0.502-0.212t-0.212-0.502z';
- svg[2] = 'icon-pause';
- svg[3] = this.pauseButtonImg;
- break;
-
- case 'restart':
- svg[0] = '0 0 20 20';
- svg[1] = 'M18 8h-6l2.243-2.243c-1.133-1.133-2.64-1.757-4.243-1.757s-3.109 0.624-4.243 1.757c-1.133 1.133-1.757 2.64-1.757 4.243s0.624 3.109 1.757 4.243c1.133 1.133 2.64 1.757 4.243 1.757s3.109-0.624 4.243-1.757c0.095-0.095 0.185-0.192 0.273-0.292l1.505 1.317c-1.466 1.674-3.62 2.732-6.020 2.732-4.418 0-8-3.582-8-8s3.582-8 8-8c2.209 0 4.209 0.896 5.656 2.344l2.344-2.344v6z';
- svg[2] = 'icon-restart';
- svg[3] = this.restartButtonImg;
- break;
-
- case 'rewind':
- svg[0] = '0 0 20 20';
- svg[1] = 'M11.25 3.125v6.25l6.25-6.25v13.75l-6.25-6.25v6.25l-6.875-6.875z';
- svg[2] = 'icon-rewind';
- svg[3] = this.rewindButtonImg;
- break;
-
- case 'forward':
- svg[0] = '0 0 20 20';
- svg[1] = 'M10 16.875v-6.25l-6.25 6.25v-13.75l6.25 6.25v-6.25l6.875 6.875z';
- svg[2] = 'icon-forward';
- svg[3] = this.forwardButtonImg;
- break;
-
- case 'previous':
- svg[0] = '0 0 20 20';
- svg[1] = 'M5 17.5v-15h2.5v6.875l6.25-6.25v13.75l-6.25-6.25v6.875z';
- svg[2] = 'icon-previous';
- svg[3] = this.previousButtonImg;
- break;
-
- case 'next':
- svg[0] = '0 0 20 20';
- svg[1] = 'M15 2.5v15h-2.5v-6.875l-6.25 6.25v-13.75l6.25 6.25v-6.875z';
- svg[2] = 'icon-next';
- svg[3] = this.nextButtonImg;
- break;
-
- case 'slower':
- svg[0] = '0 0 11 20';
- svg[1] = 'M0 7.321q0-0.29 0.212-0.502t0.502-0.212h10q0.29 0 0.502 0.212t0.212 0.502-0.212 0.502l-5 5q-0.212 0.212-0.502 0.212t-0.502-0.212l-5-5q-0.212-0.212-0.212-0.502z';
- svg[2] = 'icon-slower';
- svg[3] = this.slowerButtonImg;
- break;
-
- case 'faster':
- svg[0] = '0 0 11 20';
- svg[1] = 'M0 12.411q0-0.29 0.212-0.502l5-5q0.212-0.212 0.502-0.212t0.502 0.212l5 5q0.212 0.212 0.212 0.502t-0.212 0.502-0.502 0.212h-10q-0.29 0-0.502-0.212t-0.212-0.502z';
- svg[2] = 'icon-faster';
- svg[3] = this.fasterButtonImg;
- break;
-
- case 'turtle':
- svg[0] = '0 0 20 20';
- svg[1] = 'M17.212 3.846c-0.281-0.014-0.549 0.025-0.817 0.144-1.218 0.542-1.662 2.708-2.163 3.942-1.207 2.972-7.090 4.619-11.755 5.216-0.887 0.114-1.749 0.74-2.428 1.466 0.82-0.284 2.126-0.297 2.74 0.144 0.007 0.488-0.376 1.062-0.625 1.37-0.404 0.5-0.398 0.793 0.12 0.793 0.473 0 0.752 0.007 1.635 0 0.393-0.003 0.618-0.16 1.49-1.49 3.592 0.718 5.986-0.264 5.986-0.264s0.407 1.755 1.418 1.755h1.49c0.633 0 0.667-0.331 0.625-0.433-0.448-1.082-0.68-1.873-0.769-2.5-0.263-1.857 0.657-3.836 2.524-5.457 0.585 0.986 2.253 0.845 2.909-0.096s0.446-2.268-0.192-3.221c-0.49-0.732-1.345-1.327-2.188-1.37zM8.221 4.663c-0.722-0.016-1.536 0.111-2.5 0.409-4.211 1.302-4.177 4.951-3.51 5.745 0 0-0.955 0.479-0.409 1.274 0.448 0.652 3.139 0.191 5.409-0.529s4.226-1.793 5.312-2.692c0.948-0.785 0.551-2.106-0.505-1.947-0.494-0.98-1.632-2.212-3.798-2.26zM18.846 5.962c0.325 0 0.577 0.252 0.577 0.577s-0.252 0.577-0.577 0.577c-0.325 0-0.577-0.252-0.577-0.577s0.252-0.577 0.577-0.577z';
- svg[2] = 'icon-turtle';
- svg[3] = this.slowerButtonImg;
- break;
-
- case 'rabbit':
- svg[0] = '0 0 20 20';
- svg[1] = 'M10.817 0c-2.248 0-1.586 0.525-1.154 0.505 1.551-0.072 5.199 0.044 6.851 2.428 0 0-1.022-2.933-5.697-2.933zM10.529 0.769c-2.572 0-2.837 0.51-2.837 1.106 0 0.545 1.526 0.836 2.524 0.697 2.778-0.386 4.231-0.12 5.264 0.865-1.010 0.779-0.75 1.401-1.274 1.851-1.093 0.941-2.643-0.673-4.976-0.673-2.496 0-4.712 1.92-4.712 4.76-0.157-0.537-0.769-0.913-1.442-0.913-0.974 0-1.514 0.637-1.514 1.49 0 0.769 1.13 1.791 2.861 0.938 0.499 1.208 2.265 1.364 2.452 1.418 0.538 0.154 1.875 0.098 1.875 0.865 0 0.794-1.034 1.094-1.034 1.707 0 1.070 1.758 0.873 2.284 1.034 1.683 0.517 2.103 1.214 2.788 2.212 0.771 1.122 2.572 1.408 2.572 0.625 0-3.185-4.413-4.126-4.399-4.135 0.608-0.382 2.139-1.397 2.139-3.534 0-1.295-0.703-2.256-1.755-2.861 1.256 0.094 2.572 1.205 2.572 2.74 0 1.877-0.653 2.823-0.769 2.957 1.975-1.158 3.193-3.91 3.029-6.37 0.61 0.401 1.27 0.577 1.971 0.625 0.751 0.052 1.475-0.225 1.635-0.529 0.38-0.723 0.162-2.321-0.12-2.837-0.763-1.392-2.236-1.73-3.606-1.683-1.202-1.671-3.812-2.356-5.529-2.356zM1.37 3.077l-0.553 1.538h3.726c0.521-0.576 1.541-1.207 2.284-1.538h-5.457zM18.846 5.192c0.325 0 0.577 0.252 0.577 0.577s-0.252 0.577-0.577 0.577c-0.325 0-0.577-0.252-0.577-0.577s0.252-0.577 0.577-0.577zM0.553 5.385l-0.553 1.538h3.197c0.26-0.824 0.586-1.328 0.769-1.538h-3.413z';
- svg[2] = 'icon-rabbit';
- svg[3] = this.fasterButtonImg;
- break;
-
- case 'ellipsis':
- svg[0] = '0 0 20 20';
- svg[1] = 'M10.001 7.8c-1.215 0-2.201 0.985-2.201 2.2s0.986 2.2 2.201 2.2c1.215 0 2.199-0.985 2.199-2.2s-0.984-2.2-2.199-2.2zM3.001 7.8c-1.215 0-2.201 0.985-2.201 2.2s0.986 2.2 2.201 2.2c1.215 0 2.199-0.986 2.199-2.2s-0.984-2.2-2.199-2.2zM17.001 7.8c-1.215 0-2.201 0.985-2.201 2.2s0.986 2.2 2.201 2.2c1.215 0 2.199-0.985 2.199-2.2s-0.984-2.2-2.199-2.2z';
- svg[2] = 'icon-ellipsis';
- svg[3] = false;
- break;
-
- case 'pipe':
- svg[0] = '0 0 20 20';
- svg[1] = 'M10.15 0.179h0.623c0.069 0 0.127 0.114 0.127 0.253v19.494c0 0.139-0.057 0.253-0.127 0.253h-1.247c-0.069 0-0.126-0.114-0.126-0.253v-19.494c0-0.139 0.057-0.253 0.126-0.253h0.623z';
- svg[2] = 'icon-pipe';
- svg[3] = false;
- break;
-
- case 'captions':
- svg[0] = '0 0 20 20';
- svg[1] = 'M0.033 3.624h19.933v12.956h-19.933v-12.956zM18.098 10.045c-0.025-2.264-0.124-3.251-0.743-3.948-0.112-0.151-0.322-0.236-0.496-0.344-0.606-0.386-3.465-0.526-6.782-0.526s-6.313 0.14-6.907 0.526c-0.185 0.108-0.396 0.193-0.519 0.344-0.607 0.697-0.693 1.684-0.731 3.948 0.037 2.265 0.124 3.252 0.731 3.949 0.124 0.161 0.335 0.236 0.519 0.344 0.594 0.396 3.59 0.526 6.907 0.547 3.317-0.022 6.176-0.151 6.782-0.547 0.174-0.108 0.384-0.183 0.496-0.344 0.619-0.697 0.717-1.684 0.743-3.949v0 0zM9.689 9.281c-0.168-1.77-1.253-2.813-3.196-2.813-1.773 0-3.168 1.387-3.168 3.617 0 2.239 1.271 3.636 3.372 3.636 1.676 0 2.851-1.071 3.035-2.852h-2.003c-0.079 0.661-0.397 1.168-1.068 1.168-1.059 0-1.253-0.91-1.253-1.876 0-1.33 0.442-2.010 1.174-2.010 0.653 0 1.068 0.412 1.13 1.129h1.977zM16.607 9.281c-0.167-1.77-1.252-2.813-3.194-2.813-1.773 0-3.168 1.387-3.168 3.617 0 2.239 1.271 3.636 3.372 3.636 1.676 0 2.851-1.071 3.035-2.852h-2.003c-0.079 0.661-0.397 1.168-1.068 1.168-1.059 0-1.253-0.91-1.253-1.876 0-1.33 0.441-2.010 1.174-2.010 0.653 0 1.068 0.412 1.13 1.129h1.976z';
- svg[2] = 'icon-captions';
- svg[3] = this.captionsButtonImg;
- break;
-
- case 'descriptions':
- svg[0] = '0 0 20 20';
- svg[1] = 'M17.623 3.57h-1.555c1.754 1.736 2.763 4.106 2.763 6.572 0 2.191-0.788 4.286-2.189 5.943h1.484c1.247-1.704 1.945-3.792 1.945-5.943-0-2.418-0.886-4.754-2.447-6.572v0zM14.449 3.57h-1.55c1.749 1.736 2.757 4.106 2.757 6.572 0 2.191-0.788 4.286-2.187 5.943h1.476c1.258-1.704 1.951-3.792 1.951-5.943-0-2.418-0.884-4.754-2.447-6.572v0zM11.269 3.57h-1.542c1.752 1.736 2.752 4.106 2.752 6.572 0 2.191-0.791 4.286-2.181 5.943h1.473c1.258-1.704 1.945-3.792 1.945-5.943 0-2.418-0.876-4.754-2.447-6.572v0zM10.24 9.857c0 3.459-2.826 6.265-6.303 6.265v0.011h-3.867v-12.555h3.896c3.477 0 6.274 2.806 6.274 6.279v0zM6.944 9.857c0-1.842-1.492-3.338-3.349-3.338h-0.876v6.686h0.876c1.858 0 3.349-1.498 3.349-3.348v0z';
- svg[2] = 'icon-descriptions';
- svg[3] = this.descriptionsButtonImg;
- break;
-
- case 'sign':
- svg[0] = '0 0 20 20';
- svg[1] = 'M10.954 10.307c0.378 0.302 0.569 1.202 0.564 1.193 0.697 0.221 1.136 0.682 1.136 0.682 1.070-0.596 1.094-0.326 1.558-0.682 0.383-0.263 0.366-0.344 0.567-1.048 0.187-0.572-0.476-0.518-1.021-1.558-0.95 0.358-1.463 0.196-1.784 0.167-0.145-0.020-0.12 0.562-1.021 1.247zM14.409 17.196c-0.133 0.182-0.196 0.218-0.363 0.454-0.28 0.361 0.076 0.906 0.253 0.82 0.206-0.076 0.341-0.488 0.567-0.623 0.115-0.061 0.422-0.513 0.709-0.82 0.211-0.238 0.363-0.344 0.564-0.594 0.341-0.422 0.412-0.744 0.709-1.193 0.184-0.236 0.312-0.307 0.481-0.594 0.886-1.679 0.628-2.432 1.475-3.629 0.26-0.353 0.552-0.442 0.964-0.653 0.383-2.793-0.888-4.356-0.879-4.361-1.067 0.623-1.644 0.879-2.751 0.82-0.417-0.005-0.636-0.182-1.048-0.145-0.385 0.015-0.582 0.159-0.964 0.29-0.589 0.182-0.91 0.344-1.529 0.535-0.393 0.11-0.643 0.115-1.050 0.255-0.348 0.147-0.182 0.029-0.427 0.312-0.317 0.348-0.238 0.623-0.535 1.222-0.371 0.785-0.326 0.891-0.115 0.987-0.14 0.402-0.174 0.672-0.14 1.107 0.039 0.331-0.101 0.562 0.255 0.825 0.483 0.361 1.499 1.205 1.757 1.217 0.39-0.012 1.521 0.029 2.096-0.368 0.13-0.081 0.167-0.162 0.056 0.145-0.022 0.037-1.433 1.136-1.585 1.131-1.794 0.056-1.193 0.157-1.303 0.115-0.091 0-0.955-1.055-1.477-0.682-0.196 0.12-0.287 0.236-0.363 0.452 0.066 0.137 0.383 0.358 0.675 0.54 0.422 0.27 0.461 0.552 0.881 0.653 0.513 0.115 1.060 0.039 1.387 0.081 0.125 0.034 1.256-0.297 1.961-0.675 0.65-0.336-0.898 0.648-1.276 1.131-1.141 0.358-0.82 0.373-1.362 0.483-0.503 0.115-0.479 0.086-0.822 0.196-0.356 0.086-0.648 0.572-0.312 0.825 0.201 0.167 0.827-0.066 1.445-0.086 0.275-0.005 1.391-0.518 1.644-0.653 0.633-0.339 1.099-0.81 1.472-1.077 0.518-0.361-0.584 0.991-1.050 1.558zM8.855 9.799c-0.378-0.312-0.569-1.212-0.564-1.217-0.697-0.206-1.136-0.667-1.136-0.653-1.070 0.582-1.099 0.312-1.558 0.653-0.388 0.277-0.366 0.363-0.567 1.045-0.187 0.594 0.471 0.535 1.021 1.561 0.95-0.344 1.463-0.182 1.784-0.142 0.145 0.010 0.12-0.572 1.021-1.247zM5.4 2.911c0.133-0.191 0.196-0.228 0.368-0.454 0.27-0.371-0.081-0.915-0.253-0.849-0.211 0.096-0.346 0.508-0.599 0.653-0.093 0.052-0.4 0.503-0.682 0.82-0.211 0.228-0.363 0.334-0.564 0.599-0.346 0.407-0.412 0.729-0.709 1.161-0.184 0.258-0.317 0.324-0.481 0.621-0.886 1.669-0.631 2.422-1.475 3.6-0.26 0.38-0.552 0.461-0.964 0.682-0.383 2.788 0.883 4.346 0.879 4.336 1.068-0.609 1.639-0.861 2.751-0.825 0.417 0.025 0.636 0.201 1.048 0.174 0.385-0.025 0.582-0.169 0.964-0.285 0.589-0.196 0.91-0.358 1.499-0.54 0.422-0.12 0.672-0.125 1.080-0.285 0.348-0.128 0.182-0.010 0.427-0.282 0.312-0.358 0.238-0.633 0.508-1.217 0.398-0.8 0.353-0.906 0.142-0.991 0.135-0.412 0.174-0.677 0.14-1.107-0.044-0.336 0.101-0.572-0.255-0.82-0.483-0.375-1.499-1.22-1.752-1.222-0.395 0.002-1.526-0.039-2.101 0.339-0.13 0.101-0.167 0.182-0.056-0.11 0.022-0.052 1.433-1.148 1.585-1.163 1.794-0.039 1.193-0.14 1.303-0.088 0.091-0.007 0.955 1.045 1.477 0.682 0.191-0.13 0.287-0.245 0.368-0.452-0.071-0.147-0.388-0.368-0.68-0.537-0.422-0.282-0.464-0.564-0.881-0.655-0.513-0.125-1.065-0.049-1.387-0.11-0.125-0.015-1.256 0.317-1.956 0.68-0.66 0.351 0.893-0.631 1.276-1.136 1.136-0.339 0.81-0.353 1.36-0.479 0.501-0.101 0.476-0.071 0.82-0.172 0.351-0.096 0.648-0.577 0.312-0.849-0.206-0.152-0.827 0.081-1.44 0.086-0.28 0.020-1.396 0.533-1.649 0.677-0.633 0.329-1.099 0.8-1.472 1.048-0.523 0.38 0.584-0.967 1.050-1.529z';
- svg[2] = 'icon-sign';
- svg[3] = this.signButtonImg;
- break;
-
- case 'mute':
- case 'volume-mute':
- svg[0] = '0 0 20 20';
- svg[1] = 'M7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714zM18.75 12.093v1.657h-1.657l-2.093-2.093-2.093 2.093h-1.657v-1.657l2.093-2.093-2.093-2.093v-1.657h1.657l2.093 2.093 2.093-2.093h1.657v1.657l-2.093 2.093z';
- svg[2] = 'icon-volume-mute';
- svg[3] = this.imgPath + 'volume-mute.png';
- break;
-
- case 'volume-soft':
- svg[0] = '0 0 20 20';
- svg[1] = 'M10.723 14.473c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 1.584-1.584 1.584-4.161 0-5.745-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c2.315 2.315 2.315 6.082 0 8.397-0.183 0.183-0.423 0.275-0.663 0.275zM7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714z';
- svg[2] = 'icon-volume-soft';
- svg[3] = this.imgPath + 'volume-soft.png';
- break;
-
- case 'volume-medium':
- svg[0] = '0 0 20 20';
- svg[1] = 'M14.053 16.241c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 2.559-2.559 2.559-6.722 0-9.281-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c1.594 1.594 2.471 3.712 2.471 5.966s-0.878 4.373-2.471 5.966c-0.183 0.183-0.423 0.275-0.663 0.275zM10.723 14.473c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 1.584-1.584 1.584-4.161 0-5.745-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c2.315 2.315 2.315 6.082 0 8.397-0.183 0.183-0.423 0.275-0.663 0.275zM7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714z';
- svg[2] = 'icon-volume-medium';
- svg[3] = this.imgPath + 'volume-medium.png';
- break;
-
- case 'volume-loud':
- svg[0] = '0 0 21 20';
- svg[1] = 'M17.384 18.009c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 1.712-1.712 2.654-3.988 2.654-6.408s-0.943-4.696-2.654-6.408c-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c2.066 2.066 3.204 4.813 3.204 7.734s-1.138 5.668-3.204 7.734c-0.183 0.183-0.423 0.275-0.663 0.275zM14.053 16.241c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 2.559-2.559 2.559-6.722 0-9.281-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c1.594 1.594 2.471 3.712 2.471 5.966s-0.878 4.373-2.471 5.966c-0.183 0.183-0.423 0.275-0.663 0.275zM10.723 14.473c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 1.584-1.584 1.584-4.161 0-5.745-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c2.315 2.315 2.315 6.082 0 8.397-0.183 0.183-0.423 0.275-0.663 0.275zM7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714z';
- svg[2] = 'icon-volume-loud';
- svg[3] = this.imgPath + 'volume-loud.png';
- break;
-
- case 'chapters':
- svg[0] = '0 0 20 20';
- svg[1] = 'M5 2.5v17.5l6.25-6.25 6.25 6.25v-17.5zM15 0h-12.5v17.5l1.25-1.25v-15h11.25z';
- svg[2] = 'icon-chapters';
- svg[3] = this.chaptersButtonImg;
- break;
-
- case 'transcript':
- svg[0] = '0 0 20 20';
- svg[1] = 'M0 19.107v-17.857q0-0.446 0.313-0.759t0.759-0.313h8.929v6.071q0 0.446 0.313 0.759t0.759 0.313h6.071v11.786q0 0.446-0.313 0.759t-0.759 0.312h-15q-0.446 0-0.759-0.313t-0.313-0.759zM4.286 15.536q0 0.156 0.1 0.257t0.257 0.1h7.857q0.156 0 0.257-0.1t0.1-0.257v-0.714q0-0.156-0.1-0.257t-0.257-0.1h-7.857q-0.156 0-0.257 0.1t-0.1 0.257v0.714zM4.286 12.679q0 0.156 0.1 0.257t0.257 0.1h7.857q0.156 0 0.257-0.1t0.1-0.257v-0.714q0-0.156-0.1-0.257t-0.257-0.1h-7.857q-0.156 0-0.257 0.1t-0.1 0.257v0.714zM4.286 9.821q0 0.156 0.1 0.257t0.257 0.1h7.857q0.156 0 0.257-0.1t0.1-0.257v-0.714q0-0.156-0.1-0.257t-0.257-0.1h-7.857q-0.156 0-0.257 0.1t-0.1 0.257v0.714zM11.429 5.893v-5.268q0.246 0.156 0.402 0.313l4.554 4.554q0.156 0.156 0.313 0.402h-5.268z';
- svg[2] = 'icon-transcript';
- svg[3] = this.transcriptButtonImg;
- break;
-
- case 'preferences':
- svg[0] = '0 0 20 20';
- svg[1] = 'M18.238 11.919c-1.049-1.817-0.418-4.147 1.409-5.205l-1.965-3.404c-0.562 0.329-1.214 0.518-1.911 0.518-2.1 0-3.803-1.714-3.803-3.828h-3.931c0.005 0.653-0.158 1.314-0.507 1.919-1.049 1.818-3.382 2.436-5.212 1.382l-1.965 3.404c0.566 0.322 1.056 0.793 1.404 1.396 1.048 1.815 0.42 4.139-1.401 5.2l1.965 3.404c0.56-0.326 1.209-0.513 1.902-0.513 2.094 0 3.792 1.703 3.803 3.808h3.931c-0.002-0.646 0.162-1.3 0.507-1.899 1.048-1.815 3.375-2.433 5.203-1.387l1.965-3.404c-0.562-0.322-1.049-0.791-1.395-1.391zM10 14.049c-2.236 0-4.050-1.813-4.050-4.049s1.813-4.049 4.050-4.049 4.049 1.813 4.049 4.049c-0 2.237-1.813 4.049-4.049 4.049z';
- svg[2] = 'icon-preferences';
- svg[3] = this.prefsButtonImg;
- break;
-
- case 'close':
- svg[0] = '0 0 16 20';
- svg[1] = 'M1.228 14.933q0-0.446 0.312-0.759l3.281-3.281-3.281-3.281q-0.313-0.313-0.313-0.759t0.313-0.759l1.518-1.518q0.313-0.313 0.759-0.313t0.759 0.313l3.281 3.281 3.281-3.281q0.313-0.313 0.759-0.313t0.759 0.313l1.518 1.518q0.313 0.313 0.313 0.759t-0.313 0.759l-3.281 3.281 3.281 3.281q0.313 0.313 0.313 0.759t-0.313 0.759l-1.518 1.518q-0.313 0.313-0.759 0.313t-0.759-0.313l-3.281-3.281-3.281 3.281q-0.313 0.313-0.759 0.313t-0.759-0.313l-1.518-1.518q-0.313-0.313-0.313-0.759z';
- svg[2] = 'icon-close';
- svg[3] = null;
- break;
-
- case 'fullscreen-expand':
- svg[0] = '0 0 20 20';
- svg[1] = 'M0 18.036v-5q0-0.29 0.212-0.502t0.502-0.212 0.502 0.212l1.607 1.607 3.705-3.705q0.112-0.112 0.257-0.112t0.257 0.112l1.272 1.272q0.112 0.112 0.112 0.257t-0.112 0.257l-3.705 3.705 1.607 1.607q0.212 0.212 0.212 0.502t-0.212 0.502-0.502 0.212h-5q-0.29 0-0.502-0.212t-0.212-0.502zM8.717 8.393q0-0.145 0.112-0.257l3.705-3.705-1.607-1.607q-0.212-0.212-0.212-0.502t0.212-0.502 0.502-0.212h5q0.29 0 0.502 0.212t0.212 0.502v5q0 0.29-0.212 0.502t-0.502 0.212-0.502-0.212l-1.607-1.607-3.705 3.705q-0.112 0.112-0.257 0.112t-0.257-0.112l-1.272-1.272q-0.112-0.112-0.112-0.257z';
- svg[2] = 'icon-fullscreen-expand';
- svg[3] = this.fullscreenExpandButtonImg;
- break;
-
- case 'fullscreen-collapse':
- svg[0] = '0 0 20 20';
- svg[1] = 'M0.145 16.964q0-0.145 0.112-0.257l3.705-3.705-1.607-1.607q-0.212-0.212-0.212-0.502t0.212-0.502 0.502-0.212h5q0.29 0 0.502 0.212t0.212 0.502v5q0 0.29-0.212 0.502t-0.502 0.212-0.502-0.212l-1.607-1.607-3.705 3.705q-0.112 0.112-0.257 0.112t-0.257-0.112l-1.272-1.272q-0.112-0.112-0.112-0.257zM8.571 9.464v-5q0-0.29 0.212-0.502t0.502-0.212 0.502 0.212l1.607 1.607 3.705-3.705q0.112-0.112 0.257-0.112t0.257 0.112l1.272 1.272q0.112 0.112 0.112 0.257t-0.112 0.257l-3.705 3.705 1.607 1.607q0.212 0.212 0.212 0.502t-0.212 0.502-0.502 0.212h-5q-0.29 0-0.502-0.212t-0.212-0.502z';
- svg[2] = 'icon-fullscreen-collapse';
- svg[3] = this.fullscreenCollapseButtonImg;
- break;
- }
-
- return svg;
- };
-
- AblePlayer.prototype.reinitialize = function () {
-
- var deferred, promise, thisObj;
-
- deferred = new this.defer();
- promise = deferred.promise();
- thisObj = this;
-
- this.startedPlaying = false;
- this.autoScrollTranscript = true;
-
- this.$media = $(this.media).first();
- this.media = this.$media[0];
-
- if (this.$media.is('audio')) {
- this.mediaType = 'audio';
- } else if (this.$media.is('video')) {
- this.mediaType = 'video';
- } else {
- this.provideFallback();
- deferred.reject();
- return promise;
- }
-
- this.$sources = this.$media.find('source');
-
- this.player = this.getPlayer();
- if (!this.player) {
- this.provideFallback();
- }
- this.setIconType();
-
- deferred.resolve();
- return promise;
- };
-
- AblePlayer.prototype.setPlayerSize = function(width, height) {
-
- if (this.mediaType !== 'audio' && width > 0 && height > 0) {
- this.playerWidth = width;
- this.playerHeight = height;
- this.aspectRatio = height / width;
- }
- };
-
- AblePlayer.prototype.setIconType = function() {
-
- if (this.forceIconType) {
- return false;
- }
-
- this.iconType = 'svg';
- };
-
- AblePlayer.prototype.setupInstance = function () {
-
- var deferred = new this.defer();
- var promise = deferred.promise();
-
- if (this.$media.attr('id')) {
- this.mediaId = this.$media.attr('id');
- } else {
- this.mediaId = "ableMediaId_" + this.ableIndex;
- this.$media.attr('id', this.mediaId);
- }
- deferred.resolve();
- return promise;
- };
-
- AblePlayer.prototype.setupInstancePlaylist = function() {
-
- var thisObj = this;
-
- this.hasPlaylist = false;
-
- $('.able-playlist').each(function() {
- if ($(this).data('player') === thisObj.mediaId) {
- thisObj.hasPlaylist = true;
- thisObj.$playlist = $(this).find('li');
-
- var $youTubeVideos = $(this).find('li[data-youtube-id]');
- $youTubeVideos.each(function() {
- var youTubeId = DOMPurify.sanitize( $(this).attr('data-youtube-id') );
- var youTubePoster = thisObj.getYouTubePosterUrl(youTubeId,'120');
- var $youTubeImg = $('
',{
- 'src': youTubePoster,
- 'alt': ''
- });
- $(this).find('button').prepend($youTubeImg);
- });
-
- var $vimeoVideos = $(this).find('li[data-vimeo-id]');
- $vimeoVideos.each(function() {
- var vimeoId = $(this).attr('data-vimeo-id');
- var vimeoPoster = thisObj.getVimeoPosterUrl(vimeoId,'120');
- var $vimeoImg = $('
',{
- 'src': vimeoPoster,
- 'alt': ''
- });
- $(this).find('button').prepend($vimeoImg);
- });
-
- $(this).find('li span').attr('aria-hidden','true');
- thisObj.playlistIndex = 0;
- var dataEmbedded = $(this).data('embedded');
- thisObj.playlistEmbed = (typeof dataEmbedded !== 'undefined' && dataEmbedded !== false) ? true : false;
- }
- });
-
- if (this.hasPlaylist && this.loop) {
- this.media.removeAttribute('loop');
- }
- if (this.hasPlaylist && this.playlistEmbed) {
- var parent = this.$playlist.parent();
- this.$playlistDom = parent.clone();
- parent.remove();
- }
- if (this.hasPlaylist && this.$sources.length === 0) {
- this.cuePlaylistItem(0);
- this.$sources = this.$media.find('source');
- }
- };
-
- AblePlayer.prototype.recreatePlayer = function () {
-
-
- if (!this.player) {
- console.log("Can't create player; no appropriate player type detected.");
- return;
- }
-
- var deferred, promise, thisObj, prefsGroups, i;
-
- deferred = new this.defer();
- promise = deferred.promise();
- thisObj = this;
-
- this.playerDeleted = false;
-
- this.recreatingPlayer = true;
-
- if (!this.playerCreated) {
- this.loadCurrentPreferences();
- this.injectPlayerCode();
- this.resizePlayer(this.media.videoWidth,this.media.videoHeight);
- }
-
- this.getSampleDescriptionText();
-
- this.initSignLanguage();
-
- this.initPlayer().then(function() {
-
- thisObj.getTracks().then(function() {
-
- thisObj.initDescription().then(function() {
-
- thisObj.setupTracks().then(function() {
- if (thisObj.hasClosedDesc) {
- if (!thisObj.$descDiv || (thisObj.$descDiv && !($.contains(thisObj.$ableDiv[0], thisObj.$descDiv[0])))) {
- thisObj.injectTextDescriptionArea();
- }
- }
- thisObj.initSpeech('init');
-
- thisObj.setupTranscript().then(function() {
-
- thisObj.initStenoFrame().then(function() {
-
- if (thisObj.stenoMode && thisObj.$stenoFrame) {
- thisObj.stenoFrameContents = thisObj.$stenoFrame.contents();
- }
- thisObj.getMediaTimes().then(function(mediaTimes) {
-
- thisObj.duration = mediaTimes['duration'];
- thisObj.elapsed = mediaTimes['elapsed'];
-
- if (typeof thisObj.volume === 'undefined') {
- thisObj.volume = thisObj.defaultVolume;
- }
- if (thisObj.volume) {
- thisObj.setVolume(thisObj.volume);
- }
- if (thisObj.transcriptType) {
- thisObj.addTranscriptAreaEvents();
- thisObj.updateTranscript();
- }
- if (thisObj.captions.length) {
- thisObj.initDefaultCaption();
- }
-
- thisObj.setMediaAttributes();
- thisObj.addControls();
- thisObj.addEventListeners();
-
- prefsGroups = thisObj.getPreferencesGroups();
- for (i = 0; i < prefsGroups.length; i++) {
- thisObj.injectPrefsForm(prefsGroups[i]);
- }
- thisObj.setupPopups();
- thisObj.updateCaption();
- thisObj.injectVTS();
- thisObj.populateChaptersDiv();
- thisObj.showSearchResults();
-
- if (thisObj.player === 'html5') {
- if (!thisObj.loadingMedia) {
- thisObj.$media[0].load();
- thisObj.loadingMedia = true;
- }
- }
- setTimeout(function() {
- thisObj.refreshControls();
- deferred.resolve();
- },100);
- });
- });
- });
- });
- });
- });
- },
- function() {
- thisObj.provideFallback();
- });
- return promise;
- };
-
- AblePlayer.prototype.initPlayer = function () {
-
- var thisObj = this;
- var playerPromise;
- if (this.player === 'html5') {
- playerPromise = this.initHtml5Player();
- } else if (this.player === 'youtube') {
- playerPromise = this.initYouTubePlayer();
- } else if (this.player === 'vimeo') {
- playerPromise = this.initVimeoPlayer();
- }
- var deferred = new this.defer();
- var promise = deferred.promise();
- playerPromise.then(
- function () {
- if (thisObj.useFixedSeekInterval) {
- if (!thisObj.seekInterval) {
- thisObj.seekInterval = thisObj.defaultSeekInterval;
- }
- thisObj.seekIntervalCalculated = true;
- } else {
- thisObj.setSeekInterval();
- }
- deferred.resolve();
- }
- ).finally(function () {
- deferred.reject();
- }
- );
-
- return promise;
- };
-
- AblePlayer.prototype.initStenoFrame = function() {
-
- var deferred, promise;
- deferred = new this.defer();
- promise = deferred.promise();
-
- if (this.stenoMode && this.$stenoFrame) {
-
- if (this.$stenoFrame[0].contentWindow,document.readyState == 'complete') {
- deferred.resolve();
- } else {
- this.$stenoFrame.on('load',function() {
- deferred.resolve();
- });
- }
- } else {
- deferred.resolve();
- }
- return promise;
- };
-
- AblePlayer.prototype.setSeekInterval = function () {
-
- var thisObj, duration;
- thisObj = this;
- this.seekInterval = this.defaultSeekInterval;
- duration = (this.useChapterTimes) ? this.chapterDuration : this.duration;
-
- if (typeof duration === 'undefined' || duration < 1) {
- this.seekIntervalCalculated = false;
- return;
- } else {
- if (duration <= 20) {
- this.seekInterval = 5;
- } else if (duration <= 30) {
- this.seekInterval = 6;
- } else if (duration <= 40) {
- this.seekInterval = 8;
- } else if (duration <= 100) {
- this.seekInterval = 10;
- } else {
- this.seekInterval = Math.round(duration / 10, 0);
- }
- this.seekIntervalCalculated = true;
- }
- };
-
- AblePlayer.prototype.initDefaultCaption = function () {
-
- var captions, i;
-
- captions = this.captions;
- if (captions.length > 0) {
- for (i=0; i
',{
- 'class': 'able-prefs-form '
- });
- var customClass = 'able-prefs-form-' + form;
- $prefsDiv.addClass(customClass);
-
- if (form == 'captions') {
- formTitle = this.translate( 'prefTitleCaptions', 'Captions Preferences' );
- } else if (form == 'descriptions') {
- formTitle = this.translate( 'prefTitleDescriptions', 'Audio Description Preferences' );
- var $prefsIntro = $('',{
- text: this.translate( 'prefIntroDescription1', 'This media player supports audio description in two ways: ' )
- });
- var $prefsIntroUL = $('
');
- var $prefsIntroLI1 = $('',{
- text: this.translate( 'prefDescFormatOption1', 'alternative described version of video' )
- });
- var $prefsIntroLI2 = $(' ',{
- text: this.translate( 'prefDescFormatOption2', 'text-based description, announced by screen reader' )
- });
-
- $prefsIntroUL.append($prefsIntroLI1,$prefsIntroLI2);
- if (this.hasOpenDesc && this.hasClosedDesc) {
- currentDescState = this.translate( 'prefIntroDescription2', 'The current video has ' ) + ' ';
- currentDescState += '' + this.translate( 'prefDescFormatOption1b', 'an alternative described version' ) + ' ';
- currentDescState += ' ' + this.translate( 'and', 'and' ) + ' ' + this.translate( 'prefDescFormatOption2b', 'text-based description, announced by screen reader' ) + ' .';
- } else if (this.hasOpenDesc) {
- currentDescState = this.translate( 'prefIntroDescription2', 'The current video has ' );
- currentDescState += ' ' + this.translate( 'prefDescFormatOption1b', 'an alternative described version' ) + ' .';
- } else if (this.hasClosedDesc) {
- currentDescState = this.translate( 'prefIntroDescription2', 'The current video has ' );
- currentDescState += ' ' + this.translate( 'prefDescFormatOption2b', 'text-based description, announced by screen reader' ) + ' .';
- } else {
- currentDescState = this.translate( 'prefIntroDescriptionNone', 'The current video has no audio description in either format.' );
- }
- $prefsIntroP2 = $('',{
- html: currentDescState
- });
-
- p3Text = this.translate( 'prefIntroDescription3', 'Use the following form to set your preferences related to text-based audio description.' );
- if (this.hasOpenDesc || this.hasClosedDesc) {
- p3Text += ' ' + this.translate( 'prefIntroDescription4', 'After you save your settings, audio description can be toggled on/off using the Description button.' );
- }
- $prefsIntroP3 = $('
',{
- text: p3Text
- });
-
- $prefsDiv.append( $prefsIntro, $prefsIntroUL, $prefsIntroP2, $prefsIntroP3 );
- } else if (form == 'keyboard') {
- formTitle = this.translate( 'prefTitleKeyboard', 'Keyboard Preferences' );
- introText = this.translate( 'prefIntroKeyboard1', 'The media player on this web page can be operated from anywhere on the page using keyboard shortcuts (see below for a list).' );
- introText += ' ' + this.translate( 'prefIntroKeyboard2', 'Modifier keys (Shift, Alt, and Control) can be assigned below.' );
- introText += ' ' + this.translate( 'prefIntroKeyboard3', 'NOTE: Some key combinations might conflict with keys used by your browser and/or other software applications. Try various combinations of modifier keys to find one that works for you.' );
- $prefsIntro = $('
',{
- text: introText
- });
- $prefsDiv.append($prefsIntro);
- } else if (form == 'transcript') {
- formTitle = this.translate( 'prefTitleTranscript', 'Transcript Preferences' );
- }
-
- $fieldset = $('
').attr('role','group');
- fieldsetClass = 'able-prefs-' + form;
- fieldsetId = this.mediaId + '-prefs-' + form;
- legendId = fieldsetId + '-legend';
- $fieldset.addClass(fieldsetClass).attr('id',fieldsetId);
- if (form === 'keyboard') {
- $legend = $('
' + this.translate( 'prefHeadingKeyboard1', 'Modifier keys used for shortcuts' ) + ' ');
- $legend.attr('id',legendId);
- $fieldset.attr('aria-labelledby',legendId);
- $fieldset.append($legend);
- } else if (form === 'descriptions') {
- $legend = $('
' + this.translate( 'prefHeadingTextDescription', 'Text-based audio description' ) + ' ');
- $legend.attr('id',legendId);
- $fieldset.attr('aria-labelledby',legendId);
- $fieldset.append($legend);
- }
- for (i=0; i
').addClass(thisClass);
-
- if (form === 'captions') {
- $thisLabel = $(' ' + available[i]['label'] + ' ');
- $thisField = $('',{
- name: thisPref,
- id: thisId,
- });
- if (thisPref !== 'prefCaptions' && thisPref !== 'prefCaptionsStyle') {
- $thisField.on( 'change', function() {
- changedPref = $(this).attr('name');
- thisObj.stylizeCaptions(thisObj.$sampleCapsDiv,changedPref);
- });
- }
- options = this.getCaptionsOptions(thisPref);
- for (j=0; j < options.length; j++) {
- if (thisPref === 'prefCaptionsPosition') {
- optionValue = options[j];
- if (optionValue === 'overlay') {
- optionText = this.translate( 'captionsPositionOverlay', 'Overlay' );
- } else if (optionValue === 'below') {
- optionValue = options[j];
- optionText = this.translate( 'captionsPositionBelow', 'Below video' );
- }
- } else if (thisPref === 'prefCaptionsFont' || thisPref === 'prefCaptionsColor' || thisPref === 'prefCaptionsBGColor') {
- optionValue = options[j][0];
- optionText = options[j][1];
- } else if (thisPref === 'prefCaptionsOpacity') {
- optionValue = options[j];
- optionText = options[j];
- optionText += (optionValue === '0%') ? ' (' + this.translate( 'transparent', 'transparent' ) + ')' : ' (' + this.translate( 'solid', 'solid' ) + ')';
- } else {
- optionValue = options[j];
- optionText = options[j];
- }
- $thisOption = $('',{
- value: optionValue,
- text: optionText
- });
- if (this[thisPref] === optionValue) {
- $thisOption.prop('selected',true);
- }
- $thisField.append($thisOption);
- }
- $thisDiv.append($thisLabel,$thisField);
- } else if (form === 'descriptions') {
- $thisLabel = $(' ' + available[i]['label'] + ' ');
- if (thisPref === 'prefDescPause' || thisPref === 'prefDescVisible') {
- $thisDiv.addClass('able-prefs-checkbox');
- $thisField = $(' ',{
- type: 'checkbox',
- name: thisPref,
- id: thisId,
- value: 'true'
- });
- if (this[thisPref] === 1) {
- $thisField.prop('checked',true);
- }
- $thisDiv.append($thisField,$thisLabel);
- } else if (this.synth) {
- $thisDiv.addClass('able-prefs-select');
- $thisField = $('',{
- name: thisPref,
- id: thisId,
- });
- if (thisPref === 'prefDescVoice' && this.descVoices.length) {
- prefDescVoice = this.getPrefDescVoice();
- for (j=0; j < this.descVoices.length; j++) {
- optionValue = this.descVoices[j].name;
- optionLang = this.descVoices[j].lang.substring(0,2).toLowerCase();
- optionText = optionValue + ' (' + this.descVoices[j].lang + ')';
- $thisOption = $('',{
- 'value': optionValue,
- 'data-lang': optionLang,
- text: optionText
- });
- if (prefDescVoice === optionValue) {
- $thisOption.prop('selected',true);
- }
- $thisField.append($thisOption);
- }
- this.$voiceSelectField = $thisField;
- } else {
- if (thisPref == 'prefDescPitch') {
- options = [0,0.5,1,1.5,2];
- } else if (thisPref == 'prefDescRate') {
-
- options = [0.7,0.8,0.9,1,1.1,1.2,1.5,2,2.5,3];
- } else if (thisPref == 'prefDescVolume') {
- options = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1];
- }
- if (typeof options !== 'undefined') {
- for (j=0; j < options.length; j++) {
- optionValue = options[j];
- optionText = this.makePrefsValueReadable(thisPref,optionValue);
- $thisOption = $(' ',{
- value: optionValue,
- text: optionText
- });
- if (this[thisPref] == optionValue) {
- $thisOption.prop('selected',true);
- }
- $thisField.append($thisOption);
- $thisDiv.append($thisLabel,$thisField);
- }
- }
- }
- $thisField.on('change',function() {
- thisObj.announceDescriptionText('sample',thisObj.currentSampleText);
- });
- $thisDiv.append($thisLabel,$thisField);
- }
- } else {
- $thisLabel = $(' ' + available[i]['label'] + ' ');
- $thisField = $(' ',{
- type: 'checkbox',
- name: thisPref,
- id: thisId,
- value: 'true'
- });
- if (this[thisPref] === 1) {
- $thisField.prop('checked',true);
- }
- if (form === 'keyboard') {
- $thisField.on('change',function() {
- changedPref = $(this).attr('name');
- if (changedPref === 'prefAltKey') {
- changedSpan = '.able-modkey-alt';
- changedText = thisObj.tt.prefAltKey + ' + ';
- } else if (changedPref === 'prefCtrlKey') {
- changedSpan = '.able-modkey-ctrl';
- changedText = thisObj.tt.prefCtrlKey + ' + ';
- } else if (changedPref === 'prefShiftKey') {
- changedSpan = '.able-modkey-shift';
- changedText = thisObj.tt.prefShiftKey + ' + ';
- }
- if ( changedPref !== 'prefNoKeyShortcuts' ) {
- if ($(this).is(':checked')) {
- $(changedSpan).text(changedText);
- } else {
- $(changedSpan).text('');
- }
- } else {
- if ($(this).is(':checked')) {
- $('.able-modkey-item').addClass('hidden');
- } else {
- $('.able-modkey-item').removeClass('hidden');
- }
- }
- });
- }
- $thisDiv.append($thisField,$thisLabel);
- }
- if (thisPref === 'prefDescVoice' && !this.descVoices.length) {
- } else {
- $fieldset.append($thisDiv);
- }
- }
- }
- $prefsDiv.append($fieldset);
-
- if (form === 'captions') {
- if (!this.usingYouTubeCaptions) {
- this.$sampleCapsDiv = $('',{
- 'class': 'able-captions-sample'
- }).text( this.translate( 'sampleCaptionText', 'Sample caption text' ) );
- $prefsDiv.append(this.$sampleCapsDiv);
- this.stylizeCaptions(this.$sampleCapsDiv);
- }
- } else if (form === 'descriptions') {
- if (this.synth) {
- this.$sampleDescDiv = $('
',{
- 'class': 'able-desc-sample'
- }).text( this.translate( 'sampleDescriptionText', 'Adjust settings to hear this sample text.' ) );
- $prefsDiv.append(this.$sampleDescDiv);
- this.currentSampleText = this.translate( 'sampleDescriptionText', 'Adjust settings to hear this sample text.' );
- }
- } else if (form === 'keyboard') {
- let shortcutClass = (this.prefNoKeyShortcuts === 1 ) ? 'able-modkey-item hidden' : 'able-modkey-item';
-
- $kbHeading = $('
',{
- text: this.translate( 'prefHeadingKeyboard2', 'Current keyboard shortcuts' )
- });
- $kbList = $('');
- kbLabels = [];
- keys = [];
- for (i=0; i ' + this.translate( 'or', 'or' ) + ' ' + this.translate( 'spacebar', 'spacebar' ));
- } else if (this.controls[i] === 'restart') {
- kbLabels.push(this.translate( 'restart', 'Restart' ));
- keys.push('s');
- } else if (this.controls[i] === 'previous') {
- kbLabels.push( this.translate( 'prevTrack', 'Previous track' ) );
- keys.push('b');
- } else if (this.controls[i] === 'next') {
- kbLabels.push( this.translate( 'nextTrack', 'Next track' ) );
- keys.push('n');
- } else if (this.controls[i] === 'rewind') {
- kbLabels.push(this.translate( 'rewind', 'Rewind' ));
- keys.push('r');
- } else if (this.controls[i] === 'forward') {
- kbLabels.push(this.translate( 'forward', 'Forward' ));
- keys.push('f');
- } else if (this.controls[i] === 'volume') {
- kbLabels.push(this.translate( 'volume', 'Volume' ));
- keys.push('v ' + this.translate( 'or', 'or' ) + ' 1-9');
- kbLabels.push(this.translate( 'mute', 'Mute' ) + '/' + this.translate( 'unmute', 'Unmute' ));
- keys.push('m');
- } else if (this.controls[i] === 'captions') {
- if (this.captions.length > 1) {
- kbLabels.push(this.translate( 'captions', 'Captions' ));
- } else {
- if (this.captionsOn) {
- kbLabels.push(this.translate( 'hideCaptions', 'Hide captions' ));
- } else {
- kbLabels.push(this.translate( 'showCaptions', 'Show captions' ));
- }
- }
- keys.push('c');
- } else if (this.controls[i] === 'descriptions') {
- if (this.descOn) {
- kbLabels.push(this.translate( 'turnOffDescriptions', 'Turn off descriptions' ));
- } else {
- kbLabels.push(this.translate( 'turnOnDescriptions', 'Turn on descriptions' ));
- }
- keys.push('d');
- } else if (this.controls[i] === 'prefs') {
- kbLabels.push(this.translate( 'preferences', 'Preferences' ));
- keys.push('e');
- }
- }
- for (i=0; i';
- kbListText += '';
- if (this.prefCtrlKey === 1) {
- kbListText += this.translate( 'prefCtrlKey', 'Control' ) + ' + ';
- }
- kbListText += ' ';
- kbListText += '';
- if (this.prefShiftKey === 1) {
- kbListText += this.translate( 'prefShiftKey', 'Shift' ) + ' + ';
- }
- kbListText += ' ';
- kbListText += '' + keys[i] + ' ';
- kbListText += ' = ' + kbLabels[i];
- $kbListItem = $('',{
- 'class': shortcutClass,
- html: kbListText,
- });
- $kbList.append($kbListItem);
- }
- kbListText = '' + this.translate( 'escapeKey', 'Escape' ) + ' ';
- kbListText += ' = ' + this.translate( 'escapeKeyFunction', 'Close current dialog or popup menu' );
- $kbListItem = $(' ',{
- html: kbListText
- });
- $kbList.append($kbListItem);
- $prefsDiv.append($kbHeading,$kbList);
- }
-
- $('body').append($prefsDiv);
- dialog = new AccessibleDialog(
- $prefsDiv,
- this.$prefsButton,
- formTitle,
- thisObj.tt.closeButtonLabel
- );
-
- $buttonContainer = $( '
' );
- $saveButton = $('' + this.translate( 'save', 'Save' ) + ' ');
- $cancelButton = $('' + this.translate( 'cancel', 'Cancel' ) + ' ');
- $saveButton.on( 'click', function () {
- dialog.hide();
- thisObj.savePrefsFromForm();
- });
- $cancelButton.on( 'click', function () {
- dialog.hide();
- thisObj.resetPrefsForm();
- });
- $buttonContainer.append( $saveButton,$cancelButton );
- $prefsDiv.append($buttonContainer);
- if (form === 'captions' || form === 'transcript') {
- $fieldset.attr('aria-labelledby',dialog.titleH1.attr('id'));
- }
-
- if (form === 'captions') {
- this.captionPrefsDialog = dialog;
- } else if (form === 'descriptions') {
- this.descPrefsDialog = dialog;
- } else if (form === 'keyboard') {
- this.keyboardPrefsDialog = dialog;
- } else if (form === 'transcript') {
- this.transcriptPrefsDialog = dialog;
- }
-
- $('div.able-prefs-form button.modalCloseButton').on( 'click', function() {
- thisObj.resetPrefsForm();
- })
- $('div.able-prefs-form').on( 'keydown', function(e) {
- if (e.key === 'Escape') {
- thisObj.resetPrefsForm();
- }
- });
- };
-
- AblePlayer.prototype.getPrefDescVoice = function () {
-
- var lang, preferences, i;
-
- if (this.selectedDescriptions) {
- lang = this.selectedDescriptions.language;
- } else if (this.captionLang) {
- lang = this.captionLang;
- } else {
- lang = this.lang;
- }
- preferences = this.getPref();
- if (preferences.voices) {
- for (i=0; i < preferences.voices.length; i++) {
- if (preferences.voices[i].lang === lang) {
- return preferences.voices[i].name;
- }
- }
- }
- return null;
- }
-
- AblePlayer.prototype.rebuildDescPrefsForm = function () {
-
-
- var i, optionValue, optionText, $thisOption;
-
- this.$voiceSelectField = $('#' + this.mediaId + '_prefDescVoice');
- this.$voiceSelectField.empty();
- for (i=0; i < this.descVoices.length; i++) {
- optionValue = this.descVoices[i].name;
- optionText = optionValue + ' (' + this.descVoices[i].lang + ')';
- $thisOption = $('',{
- 'value': optionValue,
- 'data-lang': this.descVoices[i].lang.substring(0,2).toLowerCase(),
- text: optionText
- });
- if (this.prefDescVoice == optionValue) {
- $thisOption.prop('selected',true);
- }
- this.$voiceSelectField.append($thisOption);
- }
- };
-
- AblePlayer.prototype.makePrefsValueReadable = function(pref,value) {
-
-
- if (pref === 'prefDescPitch') {
- if (value === 0) {
- return this.translate( 'prefDescPitch1', 'Very low' );
- } else if (value === 0.5) {
- return this.translate( 'prefDescPitch2', 'Low' );
- } else if (value === 1) {
- return this.translate( 'prefDescPitch3', 'Default' );
- } else if (value === 1.5) {
- return this.translate( 'prefDescPitch4', 'High' );
- } else if (value === 2) {
- return this.translate( 'prefDescPitch5', 'Very high' );
- }
- } else if (pref === 'prefDescRate') {
- if (value === 0.7) {
- return 1;
- } else if (value === 0.8) {
- return 2;
- } else if (value === 0.9) {
- return 3;
- } else if (value === 1) {
- return 4;
- } else if (value === 1.1) {
- return 5;
- } else if (value === 1.2) {
- return 6;
- } else if (value === 1.5) {
- return 7;
- } else if (value === 2) {
- return 8;
- } else if (value === 2.5) {
- return 9;
- } else if (value === 3) {
- return 10;
- }
- } else if (pref === 'prefDescVolume') {
- return value * 10;
- }
- return value;
- };
-
- AblePlayer.prototype.resetPrefsForm = function () {
-
-
- var thisObj, preferences, available, i, prefName;
-
- thisObj = this;
- preferences = this.getPref();
- available = this.getAvailablePreferences();
- for (i=0; i 0) {
- this.setPrefs(preferences);
- this.showAlert( this.translate( 'prefSuccess', 'Your changes have been saved.' ) );
- } else {
- this.showAlert( this.translate( 'prefNoChange', "You didn't make any changes" ) );
- }
- if (this.player === 'youtube' &&
- (typeof this.usingYouTubeCaptions !== 'undefined' && this.usingYouTubeCaptions) &&
- capSizeChanged) {
- this.youTubePlayer.setOption('captions','fontSize',this.translatePrefs('size',capSizeValue,'youtube'));
- }
- if (AblePlayerInstances.length > 1) {
- for (var i=0; i 0) {
- AblePlayerInstances[i].stylizeCaptions(AblePlayerInstances[i].$captionsDiv);
- if (typeof AblePlayerInstances[i].$descDiv !== 'undefined') {
- AblePlayerInstances[i].stylizeCaptions(AblePlayerInstances[i].$descDiv);
- }
- }
- }
- } else {
- this.updatePlayerPrefs();
- if (numCapChanges > 0) {
- this.stylizeCaptions(this.$captionsDiv);
- if (typeof this.$descDiv !== 'undefined') {
- this.stylizeCaptions(this.$descDiv);
- }
- }
- }
- }
-
- AblePlayer.prototype.updatePlayerPrefs = function () {
-
- if (this.$transcriptDiv) {
- if (this.prefTabbable === 1) {
- this.$transcriptDiv.find('span.able-transcript-seekpoint').attr('tabindex','0');
- } else {
- this.$transcriptDiv.find('span.able-transcript-seekpoint').removeAttr('tabindex');
- }
-
- if (this.prefHighlight === 0) {
- this.$transcriptDiv.find('span').removeClass('able-highlight');
- }
- }
-
- this.updateCaption();
- this.initDescription();
- };
-
- AblePlayer.prototype.usingModifierKeys = function(e) {
-
- if ((this.prefAltKey === 1) && !e.altKey) {
- return false;
- }
- if ((this.prefCtrlKey === 1) && !e.ctrlKey) {
- return false;
- }
- if ((this.prefShiftKey === 1) && !e.shiftKey) {
- return false;
- }
- return true;
- };
-
-})(jQuery);
-
-(function ($) {
- AblePlayer.prototype.parseWebVTT = function(data) {
-
- let srcFile = data.src;
- let text = data.text;
- text = text.replace(/(\r\n|\n|\r)/g,'\n');
-
- var parserState = {
- src: srcFile,
- text: text,
- error: null,
- metadata: {},
- cues: [],
- line: 1,
- column: 1
- };
-
- try {
- act(parserState, parseFileBody);
- }
- catch (err) {
- var errString = 'Invalid WebVTT file: ' + parserState.src + '\n';
- errString += 'Line: ' + parserState.line + ', ';
- errString += 'Column: ' + parserState.column + '\n';
- errString += err;
- if (console.warn) {
-
- } else if (console.log) {
-
- }
- }
- return parserState;
- }
-
- function actList(state, list) {
- var results = [];
- for (var ii = 0; ii < list.length; ii++) {
- results.push(act(state, list[ii]));
- }
- return results;
- }
-
- function act(state, action) {
- var val = action(state);
- if (state.error !== null) {
- throw state.error;
- }
- return val;
- }
-
- function updatePosition(state, cutText) {
- for (var ii = 0; ii < cutText.length; ii++) {
- if (cutText[ii] === '\n') {
- state.column = 1;
- state.line += 1;
- } else {
- state.column += 1;
- }
- }
- }
-
- function cut(state, length) {
- var returnText = state.text.substring(0, length);
- updatePosition(state, returnText);
- state.text = state.text.substring(length);
- return returnText;
- }
-
- function cutLine(state, length) {
- var nextEOL = state.text.indexOf('\n');
- var returnText;
- if (nextEOL === -1) {
- returnText = state.text;
- updatePosition(state, returnText);
- state.text = '';
- } else {
- returnText = state.text.substring(0, nextEOL);
- updatePosition(state, returnText + '\n');
- state.text = state.text.substring(nextEOL + 1);
- }
- return returnText;
- }
-
- function peekLine(state) {
- var nextEOL = state.text.indexOf('\n');
- return (nextEOL === -1) ? state.text : state.text.substring(0, nextEOL);
- }
-
- function parseFileBody(state) {
- actList(state, [
- eatOptionalBOM,
- eatSignature]);
- var c = state.text[0];
- if (c === ' ' || c === '\t' || c === '\n') {
- actList(state, [
- eatUntilEOLInclusive,
- parseMetadataHeaders,
- eatAtLeast1EmptyLines,
- parseCuesAndComments]);
- } else {
- state.error = "WEBVTT signature not followed by whitespace.";
- }
- }
-
- function parseMetadataHeaders(state) {
- while (true) {
- var nextLine = peekLine(state);
- if (nextLine.indexOf('-->') !== -1) {
- return;
- } else if (nextLine.length === 0) {
- return;
- } else {
- var keyValue = act(state, getMetadataKeyValue);
- state.metadata[keyValue[0]] = keyValue[1];
- act(state, eatUntilEOLInclusive);
- }
- }
- }
-
- function nextSpaceOrNewline(s) {
- var possible = [];
- var spaceIndex = s.indexOf(' ');
- if (spaceIndex >= 0) {
- possible.push(spaceIndex);
- }
- var tabIndex = s.indexOf('\t');
- if (tabIndex >= 0) {
- possible.push(tabIndex);
- }
- var lineIndex = s.indexOf('\n');
- if (lineIndex >= 0) {
- possible.push(lineIndex);
- }
-
- return Math.min.apply(null, possible);
- }
-
- function getMetadataKeyValue(state) {
- var next = state.text.indexOf('\n');
- var pair = cut(state, next);
- var colon = pair.indexOf(':');
- if (colon === -1) {
- state.error = 'Missing colon.';
- return;
- } else {
- var pairName = pair.substring(0, colon);
- var pairValue = pair.substring(colon + 1);
- return [pairName, pairValue];
- }
- }
-
- function getSettingsKeyValue(state) {
- var next = nextSpaceOrNewline(state.text);
- var pair = cut(state, next);
- var colon = pair.indexOf(':');
- if (colon === -1) {
- state.error = 'Missing colon.';
- return;
- } else {
- var pairName = pair.substring(0, colon);
- var pairValue = pair.substring(colon + 1);
- return [pairName, pairValue];
- }
- }
-
- function parseCuesAndComments(state) {
- while (true) {
- var nextLine = peekLine(state);
- if (nextLine.indexOf('NOTE') === 0 && ((nextLine.length === 4) || (nextLine[4] === ' ') || (nextLine[4] === '\t'))) {
- actList(state, [eatComment, eatEmptyLines]);
- } else if (nextLine.trim().length === 0 && state.text.length > 0) {
- act(state, eatEmptyLines);
- } else if (nextLine.trim().length > 0) {
- act(state, parseCue);
- } else {
- return;
- }
- }
- }
-
- function parseCue(state) {
-
- var nextLine = peekLine(state);
- var cueId;
- var errString;
-
- if(nextLine.indexOf('-->') === -1) {
- cueId = cutLine(state);
- nextLine = peekLine(state);
- if(nextLine.indexOf('-->') === -1) {
- errString = 'Invalid WebVTT file: ' + state.src + '\n';
- errString += 'Line: ' + state.line + ', ';
- errString += 'Column: ' + state.column + '\n';
- errString += 'Expected cue timing for cueId \''+cueId+'\' but found: ' + nextLine + '\n';
- if (console.warn) {
-
- } else if (console.log) {
-
- }
- return;
- }
- }
-
- var cueTimings = actList(state, [getTiming,
- eatAtLeast1SpacesOrTabs,
- eatArrow,
- eatAtLeast1SpacesOrTabs,
- getTiming]);
-
- var startTime = cueTimings[0];
- var endTime = cueTimings[4];
- if (startTime >= endTime) {
- state.error = 'Start time is not sooner than end time.';
- return;
- }
-
- act(state, eatSpacesOrTabs);
- var cueSettings = act(state, getCueSettings);
- cut(state, 1);
- var components = act(state, getCuePayload);
-
- if (typeof cueId === 'undefined') {
- cueId = state.cues.length + 1;
- }
- state.cues.push({
- id: cueId,
- start: startTime,
- end: endTime,
- settings: cueSettings,
- components: components
- });
- }
-
- function getCueSettings(state) {
- var cueSettings = {};
- while (state.text.length > 0 && state.text[0] !== '\n') {
- var keyValue = act(state, getSettingsKeyValue);
- cueSettings[keyValue[0]] = keyValue[1];
- act(state, eatSpacesOrTabs);
- }
- return cueSettings;
- }
-
- function getCuePayload(state) {
- var result = {type: 'internal', tagName: '', value: '', classes: [], annotation: '', parent: null, children: [], language: ''};
- var current = result;
- var languageStack = [];
- while (state.text.length > 0) {
- var nextLine = peekLine(state);
- if (nextLine.indexOf('-->') !== -1 || /^\s+$/.test(nextLine)) {
- break;
- }
- if (state.text.length >= 2 && state.text[0] === '\n' && state.text[1] === '\n') {
- cut(state, 2);
- break;
- }
-
- var token = getCueToken(state);
- if (token.type === 'string') {
- current.children.push(token);
- } else if (token.type === 'startTag') {
- token.type = token.tagName;
- token.parent = current;
- if ($.inArray(token.tagName, ['i', 'b', 'u', 'ruby']) !== -1) {
- if (languageStack.length > 0) {
- current.language = languageStack[languageStack.length - 1];
- }
- current.children.push(token);
- current = token;
- } else if (token.tagName === 'rt' && current.tagName === 'ruby') {
- if (languageStack.length > 0) {
- current.language = languageStack[languageStack.length - 1];
- }
- current.children.push(token);
- current = token;
- } else if (token.tagName === 'c') {
- token.value = token.annotation;
- if (languageStack.length > 0) {
- current.language = languageStack[languageStack.length - 1];
- }
- current.children.push(token);
- current = token;
- } else if (token.tagName === 'v') {
- token.value = token.annotation;
- if (languageStack.length > 0) {
- current.language = languageStack[languageStack.length - 1];
- }
- current.children.push(token);
- current = token;
- } else if (token.tagName === 'lang') {
- languageStack.push(token.annotation);
- if (languageStack.length > 0) {
- current.language = languageStack[languageStack.length - 1];
- }
- current.children.push(token);
- current = token;
- }
- } else if (token.type === 'endTag') {
- if (token.tagName === current.type && $.inArray(token.tagName, ['c', 'i', 'b', 'u', 'ruby', 'rt', 'v']) !== -1) {
- current = current.parent;
- } else if (token.tagName === 'lang' && current.type === 'lang') {
- current = current.parent;
- languageStack.pop();
- } else if (token.tagName === 'ruby' && current.type === 'rt') {
- current = current.parent.parent;
- }
- } else if (token.type === 'timestampTag') {
- var tempState = {
- text: token.value,
- error: null,
- metadata: {},
- cues: [],
- line: 1,
- column: 1
- };
- try {
- var timing = act(tempState, getTiming);
- if (tempState.text.length === 0) {
- token.value = timing;
- current.push(token);
- }
- }
- catch (err) {
- }
- }
- }
- return result;
- }
-
- function getCueToken(state) {
- var tokenState = 'data';
- var result = [];
- var buffer = '';
- var token = {type: '', tagName: '', value: '', classes: [], annotation: '', children: []}
-
- while (true) {
- var c;
- if (state.text.length >= 2 && state.text[0] === '\n' && state.text[1] === '\n') {
- c = '\u0004';
- } else if (state.text.length > 0) {
- c = state.text[0];
- } else {
- c = '\u0004';
- }
- if (tokenState === 'data') {
- if (c === '&') {
- buffer = '&';
- tokenState = 'escape';
- } else if (c === '<') {
- if (result.length === 0) {
- tokenState = 'tag';
- } else {
- token.type = 'string';
- token.value = result.join('');
- return token;
- }
- } else if (c === '\u0004') {
- return {type: 'string', value: result.join('')};
- } else {
- result.push(c);
- }
- } else if (tokenState === 'escape') {
- if (c === '&') {
- result.push(buffer);
- buffer = '&';
- } else if (c.match(/[0-9a-z]/)) {
- buffer += c;
- } else if (c === ';') {
- if (buffer === '&') {
- result.push('&');
- } else if (buffer === '<') {
- result.push('<');
- } else if (buffer === '>') {
- result.push('>');
- } else if (buffer === '&lrm') {
- result.push('\u200e');
- } else if (buffer === '&rlm') {
- result.push('\u200f');
- } else if (buffer === ' ') {
- result.push('\u00a0');
- } else {
- result.push(buffer);
- result.push(';');
- }
- tokenState = 'data';
- } else if (c === '<' || c === '\u0004') {
- result.push(buffer);
- token.type = 'string';
- token.value = result.join('');
- return token;
- } else if (c === '\t' || c === '\n' || c === '\u000c' || c === ' ') {
- result.push(buffer);
- token.type = 'string';
- token.value = result.join('');
- return token;
- } else {
- result.push(buffer);
- tokenState = 'data';
- }
- } else if (tokenState === 'tag') {
- if (c === '\t' || c === '\n' || c === '\u000c' || c === ' ') {
- tokenState = 'startTagAnnotation';
- } else if (c === '.') {
- tokenState = 'startTagClass';
- } else if (c === '/') {
- tokenState = 'endTag';
- } else if (c.match('[0-9]')) {
- tokenState = 'timestampTag';
- result.push(c);
- } else if (c === '>') {
- cut(state, 1);
- break;
- } else if (c === '\u0004') {
- token.tagName = '';
- token.type = 'startTag';
- return token;
- } else {
- result.push(c);
- tokenState = 'startTag';
- }
- } else if (tokenState === 'startTag') {
- if (c === '\t' || c === '\u000c' || c === ' ') {
- tokenState = 'startTagAnnotation';
- } else if (c === '\n') {
- buffer = c;
- tokenState = 'startTagAnnotation';
- } else if (c === '.') {
- tokenState = 'startTagClass';
- } else if (c === '>') {
- cut(state, 1);
- token.tagName = result.join('');
- token.type = 'startTag';
- return token;
- } else if (c === '\u0004') {
- token.tagName = result.join('');
- token.type = 'startTag';
- return token;
- } else {
- result.push(c);
- }
- } else if (tokenState === 'startTagClass') {
- if (c === '\t' || c === '\u000c' || c === ' ') {
- token.classes.push(buffer);
- buffer = '';
- tokenState = 'startTagAnnotation';
- } else if (c === '\n') {
- token.classes.push(buffer);
- buffer = c;
- tokenState = 'startTagAnnotation';
- } else if (c === '.') {
- token.classes.push(buffer);
- buffer = "";
- } else if (c === '>') {
- cut(state, 1);
- token.classes.push(buffer);
- token.type = 'startTag';
- token.tagName = result.join('');
- return token;
- } else if (c === '\u0004') {
- token.classes.push(buffer);
- token.type = 'startTag';
- token.tagName = result.join('');
- return token;
- } else {
- buffer += 'c';
- }
- } else if (tokenState === 'startTagAnnotation') {
- if (c === '>') {
- cut(state, 1);
- buffer = buffer.trim().replace(/ +/, ' ');
- token.type = 'startTag';
- token.tagName = result.join('');
- token.annotation = buffer;
- return token;
- } else if (c === '\u0004') {
- buffer = buffer.trim().replace(/ +/, ' ');
- token.type = 'startTag';
- token.tagName = result.join('');
- token.annotation = buffer;
- return token;
- } else {
- buffer += c;
- }
- } else if (tokenState === 'endTag') {
- if (c === '>') {
- cut(state, 1);
- token.type = 'endTag';
- token.tagName = result.join('');
- return token;
- } else if (c === '\u0004') {
- token.type = 'endTag';
- token.tagName = result.join('');
- return token;
- } else {
- result.push(c);
- }
- } else if (tokenState === 'timestampTag') {
- if (c === '>') {
- cut(state, 1);
- token.type = 'timestampTag';
- token.name = result.join('');
- return token;
- } else if (c === '\u0004') {
- token.type = 'timestampTag';
- token.name = result.join('');
- return token;
- } else {
- result.push(c);
- }
- } else {
- throw 'Unknown tokenState ' + tokenState;
- }
-
- cut(state, 1);
- }
- }
-
- function eatComment(state) {
- var noteLine = cutLine(state);
- if (noteLine.indexOf('-->') !== -1) {
- state.error = 'Invalid syntax: --> in NOTE line.';
- return;
- }
- while (true) {
- var nextLine = peekLine(state);
- if ( nextLine.trim().length === 0) {
- return;
- } else if (nextLine.indexOf('-->') !== -1) {
- state.error = 'Invalid syntax: --> in comment.';
- return;
- } else {
- cutLine(state);
- }
- }
- }
-
- function eatOptionalBOM(state) {
- if (state.text[0] === '\ufeff') {
- cut(state, 1);
- }
-
- }
-
- function eatSignature(state) {
- if (state.text.substring(0,6) === 'WEBVTT') {
- cut(state, 6);
- } else {
- state.error = 'Invalid signature.';
- }
- }
-
- function eatArrow(state) {
- if (state.text.length < 3 || state.text.substring(0,3) !== '-->') {
- state.error = 'Missing -->';
- } else {
- cut(state, 3);
- }
- }
-
- function eatSingleSpaceOrTab(state) {
- if (state.text[0] === '\t' || state.text[0] === ' ') {
- cut(state, 1);
- } else {
- state.error = 'Missing space.';
- }
- }
-
- function eatSpacesOrTabs(state) {
- while (state.text[0] === '\t' || state.text[0] === ' ') {
- cut(state, 1);
- }
- }
-
- function eatAtLeast1SpacesOrTabs(state) {
- var numEaten = 0;
- while (state.text[0] === '\t' || state.text[0] === ' ') {
- cut(state, 1);
- numEaten += 1;
- }
- if (numEaten === 0) {
- state.error = 'Missing space.';
- }
- }
-
- function eatUntilEOLInclusive(state) {
- var nextEOL = state.text.indexOf('\n');
- if (nextEOL === -1) {
- state.error = 'Missing EOL.';
- } else {
- cut(state, nextEOL + 1);
- }
- }
-
- function eatEmptyLines(state) {
- while (state.text.length > 0) {
- var nextLine = peekLine(state);
- if ( nextLine.trim().length === 0) {
- cutLine(state);
- } else {
- break;
- }
- }
- }
-
- function eatAtLeast1EmptyLines(state) {
- var linesEaten = 0;
- while (state.text.length > 0) {
- var nextLine = peekLine(state);
- if ( nextLine.trim().length === 0) {
- cutLine(state);
- linesEaten += 1;
- } else {
- break;
- }
- }
- if (linesEaten === 0) {
- state.error = 'Missing empty line.';
- }
- }
-
- function getTiming(state) {
- var nextSpace = nextSpaceOrNewline(state.text);
- if (nextSpace === -1) {
- state.error('Missing timing.');
- return;
- }
- var timestamp = cut(state, nextSpace);
-
- var results = /((\d+):)?((\d\d):)(\d\d).(\d\d\d)|(\d+).(\d\d\d)/.exec(timestamp);
-
- if (!results) {
- state.error = 'Unable to parse timestamp';
- return;
- }
- var time = 0;
- var hours = results[2];
- var minutes = results[4];
-
- if (minutes) {
- if (parseInt(minutes, 10) > 59) {
- state.error = 'Invalid minute range';
- return;
- }
- if (hours) {
- time += 3600 * parseInt(hours, 10);
- }
- time += 60 * parseInt(minutes, 10);
- var seconds = results[5];
- if (parseInt(seconds, 10) > 59) {
- state.error = 'Invalid second range';
- return;
- }
-
- time += parseInt(seconds, 10);
- time += parseInt(results[6], 10) / 1000;
- } else {
- time += parseInt(results[7], 10);
- time += parseInt(results[8], 10) / 1000;
- }
-
- return time;
- }
-})(jQuery);
-
-(function ($) {
-
- AblePlayer.prototype.injectPlayerCode = function() {
-
-
- var captionsContainer;
- 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') {
- if (this.iconType != 'image' && (this.player !== 'youtube' || this.hasPoster)) {
- this.injectBigPlayButton();
- }
- }
-
- captionsContainer = $('');
- if (this.mediaType === 'video') {
- captionsContainer.addClass('able-vidcap-container');
- } else if (this.mediaType === 'audio') {
- captionsContainer.addClass('able-audcap-container');
- captionsContainer.addClass('captions-off');
- }
-
- this.injectPlayerControlArea();
- this.$captionsContainer = this.$mediaContainer.wrap(captionsContainer).parent();
- this.injectAlert(this.$ableDiv);
- this.injectPlaylist();
- this.injectAudioPoster();
- this.injectOffscreenHeading();
- };
-
- AblePlayer.prototype.injectAudioPoster = function() {
- if ( this.mediaType === 'audio' && this.hasPoster ) {
- audioPoster = DOMPurify.sanitize(this.audioPoster);
- 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 () {
-
- var headingType;
- if (this.playerHeadingLevel == '0') {
- } else {
- if (typeof this.playerHeadingLevel === 'undefined') {
- this.playerHeadingLevel = this.getNextHeadingLevel(this.$ableDiv);
- }
- 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 = $('
', {
- 'class': 'able-big-play-button',
- 'aria-hidden': false,
- 'aria-label': this.translate( 'play', 'Play' ),
- 'type': 'button',
- 'tabindex': 0
- });
-
- this.getIcon( this.$bigPlayButton, 'play' );
-
- this.$bigPlayButton.on( 'click', function () {
- thisObj.handlePlay();
- });
-
- this.$mediaContainer.append(this.$bigPlayButton);
- };
-
- AblePlayer.prototype.injectPlayerControlArea = function () {
-
- this.$playerDiv = $('', {
- 'class' : 'able-player',
- 'role' : 'region',
- 'aria-label' : ( 'audio' === this.mediaType ) ? this.translate( 'audioPlayer', 'audio player' ) : this.translate( 'videoPlayer', 'video player' )
- });
- this.$playerDiv.addClass('able-' + this.mediaType);
- if (this.hasPlaylist && this.showNowPlaying) {
- this.$nowPlayingDiv = $('
',{
- 'class' : 'able-now-playing',
- 'aria-live' : 'assertive',
- 'aria-atomic': 'true'
- });
- }
- this.$controllerDiv = $('
',{
- 'class' : 'able-controller'
- });
- this.$controllerDiv.addClass('able-' + this.iconColor + '-controls');
-
- this.$statusBarDiv = $('
',{
- 'class' : 'able-status-bar'
- });
- this.$timer = $('
',{
- 'class' : 'able-timer'
- });
- this.$elapsedTimeContainer = $('',{
- 'class': 'able-elapsedTime',
- text: '0:00'
- });
- this.$durationContainer = $('',{
- 'class': 'able-duration'
- });
- this.$timer.append(this.$elapsedTimeContainer).append(this.$durationContainer);
-
- this.$speed = $('',{
- 'class' : 'able-speed',
- 'aria-live' : 'assertive',
- 'aria-atomic' : 'true'
- }).text(this.translate( 'speed', 'Speed' ) + ': 1x');
-
- this.$status = $('',{
- 'class' : 'able-status',
- 'aria-live' : 'polite'
- });
-
- this.$statusBarDiv.append(this.$timer, this.$speed, this.$status);
- if (this.showNowPlaying) {
- this.$playerDiv.append(this.$nowPlayingDiv, this.$controllerDiv, this.$statusBarDiv);
- } else {
- this.$playerDiv.append(this.$controllerDiv, this.$statusBarDiv);
- }
-
- if (this.mediaType === 'video') {
- this.$ableDiv.append(this.$playerDiv);
- } else {
- this.$ableDiv.prepend(this.$playerDiv);
- }
- };
-
- AblePlayer.prototype.injectTextDescriptionArea = function () {
-
- this.$descDiv = $('',{
- 'class': 'able-descriptions'
- });
- this.$descDiv.attr({
- 'aria-live': 'assertive',
- 'aria-atomic': 'true'
- });
- this.$descDiv.hide();
- this.$ableDiv.append(this.$descDiv);
- };
-
- AblePlayer.prototype.getDefaultWidth = function(which) {
- let viewportMaxwidth = window.innerWidth;
- if (which === 'transcript') {
- return ( viewportMaxwidth <= 450 ) ? viewportMaxwidth : 450;
- } else if (which === 'sign') {
- return ( viewportMaxwidth <= 400 ) ? viewportMaxwidth : 400;
- }
- };
-
- AblePlayer.prototype.rePositionDraggableWindow = function (which) {
-
- let preferences, $window;
- preferences = this.getPref();
- $window = ( which === 'transcript' ) ? this.$transcriptArea : this.$signWindow;
-
- if ( which === 'transcript' && $window ) {
- if (typeof preferences.transcript !== 'undefined') {
- this.prevTranscriptPosition = preferences.transcript;
- }
- $window.css({
- 'top': 0,
- 'left': 0
- });
- } else if ( 'sign' === which && $window ) {
- if (typeof preferences.sign !== 'undefined') {
- this.prevSignPosition = preferences.sign;
- }
- $window.css({
- 'top': 0,
- 'right': 0,
- 'left': 'auto'
- });
- }
- }
-
- AblePlayer.prototype.positionDraggableWindow = function (which, width) {
-
- var preferences, preferencePos, $window, windowPos, viewportWidth, windowWidth;
-
- preferences = this.getPref();
- $window = ( which === 'transcript' ) ? this.$transcriptArea : this.$signWindow;
- if ( ! $window ) {
- return;
- }
- if (which === 'transcript') {
- if (typeof preferences.transcript !== 'undefined') {
- preferencePos = preferences.transcript;
- }
- if ( this.prevTranscriptPosition ) {
- preferencePos = this.prevTranscriptPosition;
- this.prevTranscriptPosition = false;
- }
- } else if (which === 'sign') {
- if (typeof preferences.sign !== 'undefined') {
- preferencePos = preferences.sign;
- }
- if ( this.prevSignPosition ) {
- preferencePos = this.prevSignPosition;
- this.prevSignPosition = false;
- }
- }
- if (typeof preferencePos !== 'undefined' && !($.isEmptyObject(preferencePos))) {
- $window.css({
- 'position': preferencePos['position'],
- 'width': preferencePos['width'],
- 'z-index': preferencePos['zindex']
- });
- if (preferencePos['position'] === 'absolute') {
- $window.css({
- 'top': preferencePos['top'],
- 'left': preferencePos['left']
- });
- topPosition = $window.offset().top;
- leftPosition = $window.offset().left;
- viewportWidth = window.innerWidth;
- windowWidth = $window.width();
- if ( topPosition < 0 ) {
- $window.css({
- 'top': preferencePos['top'] - topPosition
- });
- }
- if ( leftPosition < 0 && ! this.restoringAfterFullscreen ) {
-
- $window.css({
- 'left': preferencePos['left'] - leftPosition
- });
- }
- if ( viewportWidth - leftPosition < 30 ) {
- $window.css({
- 'left': viewportWidth - windowWidth
- });
- }
- }
- this.updateZIndex(which);
- } else {
- windowPos = this.getOptimumPosition(which, width);
- if (typeof width === 'undefined') {
- width = this.getDefaultWidth(which);
- }
- $window.css({
- 'position': windowPos[0],
- 'width': width,
- 'z-index': windowPos[3]
- });
- if (windowPos[0] === 'absolute') {
- $window.css({
- 'top': windowPos[1] + 'px',
- 'left': windowPos[2] + 'px',
- });
- }
- }
- };
-
- AblePlayer.prototype.getOptimumPosition = function (targetWindow, targetWidth) {
-
-
- var gap, position, ableWidth, ableOffset, ableLeft, windowWidth, otherWindowWidth;
-
- if (typeof targetWidth === 'undefined') {
- targetWidth = this.getDefaultWidth(targetWindow);
- }
-
- gap = 5;
- position = [];
-
- ableWidth = this.$ableDiv.width();
- ableOffset = this.$ableDiv.offset();
- ableLeft = ableOffset.left;
- windowWidth = $(window).width();
- otherWindowWidth = 0;
-
- if (targetWindow === 'transcript') {
- if (typeof this.$signWindow !== 'undefined' && (this.$signWindow.is(':visible'))) {
- otherWindowWidth = this.$signWindow.width() + gap;
- }
- } else if (targetWindow === 'sign') {
- if (typeof this.$transcriptArea !== 'undefined' && (this.$transcriptArea.is(':visible'))) {
- otherWindowWidth = this.$transcriptArea.width() + gap;
- }
- }
- if (targetWidth < (windowWidth - (ableLeft + ableWidth + gap + otherWindowWidth))) {
- position[0] = 'absolute';
- position[1] = 0;
- position[2] = ableWidth + otherWindowWidth + gap;
- } else if (targetWidth + gap < ableLeft) {
- position[0] = 'absolute';
- position[1] = 0;
- position[2] = ableLeft - targetWidth - gap;
- } else {
- position[0] = 'relative';
- }
- return position;
- };
-
- AblePlayer.prototype.injectAlert = function ($container) {
- this.$alertBox = $('
');
- this.$alertBox.addClass('able-alert');
- this.$alertBox.hide();
-
- var $alertText = $( '
' );
- $alertText.appendTo(this.$alertBox);
-
- var $alertDismiss = $('
' );
- $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) {
- var playlistClone = this.$playlistDom.clone();
- playlistClone.insertBefore(this.$statusBarDiv);
- this.$playlist = playlistClone.find('li');
- }
- };
-
- AblePlayer.prototype.createPopup = function (which, tracks) {
-
-
- var thisObj, $menu, includeMenuItem, i, $menuItem, prefCat, whichPref, hasDefault, track,
- windowOptions, $thisItem, $prevItem, $nextItem, hasDescription, hasTranscript;
-
- thisObj = this;
-
- $menu = $('
',{
- 'id': this.mediaId + '-' + which + '-menu',
- 'class': 'able-popup',
- 'role': 'menu'
- }).hide();
-
- if (which === 'captions') {
- $menu.addClass('able-popup-captions');
- }
-
- if (which === 'prefs') {
- if (this.prefCats.length > 1) {
- for (i = 0; i < this.prefCats.length; i++) {
- prefCat = this.prefCats[i];
- hasDescription = ( thisObj.hasDescTracks || thisObj.hasOpenDesc || thisObj.hasClosedDesc ) ? true : false;
- hasTranscript = ( thisObj.transcriptType === null ) ? false : true;
-
- if ( prefCat === 'descriptions' && ! hasDescription || prefCat === 'transcript' && ! hasTranscript ) {
- continue;
- }
- $menuItem = $(' ',{
- 'role': 'menuitem',
- 'tabindex': '-1'
- });
- if (prefCat === 'captions') {
- $menuItem.text( this.translate( 'prefMenuCaptions', 'Captions' ) );
- } else if (prefCat === 'descriptions') {
- $menuItem.text( this.translate( 'prefMenuDescriptions', 'Descriptions' ) );
- } else if (prefCat === 'keyboard') {
- $menuItem.text( this.translate( 'prefMenuKeyboard', 'Keyboard' ) );
- } else if (prefCat === 'transcript') {
- $menuItem.text( this.translate( 'prefMenuTranscript', 'Transcript' ) );
- }
- $menuItem.on('click',function() {
- whichPref = $(this).text();
- thisObj.showingPrefsDialog = true;
- thisObj.setFullscreen(false);
- if (whichPref === thisObj.tt.prefMenuCaptions) {
- thisObj.captionPrefsDialog.show();
- } else if (whichPref === thisObj.tt.prefMenuDescriptions) {
- thisObj.descPrefsDialog.show();
- } else if (whichPref === thisObj.tt.prefMenuKeyboard) {
- thisObj.keyboardPrefsDialog.show();
- } else if (whichPref === thisObj.tt.prefMenuTranscript) {
- thisObj.transcriptPrefsDialog.show();
- }
- thisObj.closePopups();
- thisObj.showingPrefsDialog = false;
- });
- $menu.append($menuItem);
- }
- this.$prefsButton.attr('data-prefs-popup','menu');
- } else if (this.prefCats.length == 1) {
- this.$prefsButton.attr('data-prefs-popup',this.prefCats[0]);
- }
- } else if (which === 'captions' || which === 'chapters') {
- hasDefault = false;
- for (i = 0; i < tracks.length; i++) {
- track = tracks[i];
- if (which === 'captions' && this.player === 'html5' && typeof track.cues === 'undefined') {
- includeMenuItem = false;
- } else {
- includeMenuItem = true;
- }
- if (includeMenuItem) {
- $menuItem = $(' ',{
- 'role': 'menuitemradio',
- 'tabindex': '-1',
- 'lang': track.language
- });
- if (track.def && this.prefCaptions == 1) {
- $menuItem.attr('aria-checked','true');
- hasDefault = true;
- } else {
- $menuItem.attr('aria-checked','false');
- }
- if (which == 'captions') {
- $menuItem.text(track.label);
- $menuItem.on('click',this.getCaptionClickFunction(track));
- } else if (which == 'chapters') {
- $menuItem.text(this.flattenCueForCaption(track) + ' - ' + this.formatSecondsAsColonTime(track.start));
- $menuItem.on('click',this.getChapterClickFunction(track.start));
- }
- $menu.append($menuItem);
- }
- }
- if (which === 'captions') {
- $menuItem = $(' ',{
- 'role': 'menuitemradio',
- 'tabindex': '-1',
- }).text( this.translate( 'captionsOff', 'Captions off' ) );
- if (this.prefCaptions === 0) {
- $menuItem.attr('aria-checked','true');
- hasDefault = true;
- } else {
- $menuItem.attr('aria-checked','false');
- }
- $menuItem.on('click',this.getCaptionOffFunction());
- $menu.append($menuItem);
- }
- } else if (which === 'transcript-window' || which === 'sign-window') {
- windowOptions = [];
- windowOptions.push({
- 'name': 'move',
- 'label': this.translate( 'windowMove', 'Move' )
- });
- windowOptions.push({
- 'name': 'resize',
- 'label': this.translate( 'windowResize', 'Resize' )
- });
- windowOptions.push({
- 'name': 'close',
- 'label': this.translate( 'windowClose', 'Close' )
- });
- for (i = 0; i < windowOptions.length; i++) {
- $menuItem = $(' ',{
- 'role': 'menuitem',
- 'tabindex': '-1',
- 'data-choice': windowOptions[i].name
- });
- $menuItem.text(windowOptions[i].label);
- $menuItem.on('click',function(e) {
- e.stopPropagation();
- if (typeof e.button !== 'undefined' && e.button !== 0) {
- return false;
- }
- if (!thisObj.windowMenuClickRegistered && !thisObj.finishingDrag) {
- thisObj.windowMenuClickRegistered = true;
- thisObj.handleMenuChoice(which.substring(0, which.indexOf('-')), $(this).attr('data-choice'), e);
- }
- });
- $menu.append($menuItem);
- }
- }
- if (which === 'captions' && !hasDefault) {
- if ($menu.find('li[lang=' + this.captionLang + ']')) {
- $menu.find('li[lang=' + this.captionLang + ']').attr('aria-checked','true');
- } else {
- $menu.find('li').last().attr('aria-checked','true');
- }
- } else if (which === 'chapters') {
- if ($menu.find('li:contains("' + this.defaultChapter + '")')) {
- $menu.find('li:contains("' + this.defaultChapter + '")').attr('aria-checked','true').addClass('able-focus');
- } else {
- $menu.find('li').first().attr('aria-checked','true').addClass('able-focus');
- }
- }
- $menu.on('keydown',function (e) {
-
- $thisItem = $(this).find('li:focus');
- if ($thisItem.is(':first-child')) {
- $prevItem = $(this).find('li').last();
- $nextItem = $thisItem.next();
- } else if ($thisItem.is(':last-child')) {
- $prevItem = $thisItem.prev();
- $nextItem = $(this).find('li').first();
- } else {
- $prevItem = $thisItem.prev();
- $nextItem = $thisItem.next();
- }
- if (e.key === 'Tab') {
- if (e.shiftKey) {
- $thisItem.removeClass('able-focus');
- $prevItem.trigger('focus').addClass('able-focus');
- } else {
- $thisItem.removeClass('able-focus');
- $nextItem.trigger('focus').addClass('able-focus');
- }
- } else if (e.key === 'ArrowDown' || e.key === 'ArrowRight') {
- $thisItem.removeClass('able-focus');
- $nextItem.trigger('focus').addClass('able-focus');
- } else if (e.key == 'ArrowUp' || e.key === 'ArrowLeft') {
- $thisItem.removeClass('able-focus');
- $prevItem.trigger('focus').addClass('able-focus');
- } else if (e.key === ' ' || e.key === 'Enter') {
- $thisItem.trigger( 'click' );
- } else if (e.key === 'Escape') {
- $thisItem.removeClass('able-focus');
- thisObj.closePopups();
- e.stopPropagation;
- }
- e.preventDefault();
- });
- this.$controllerDiv.append($menu);
- return $menu;
- };
-
- AblePlayer.prototype.closePopups = function () {
-
- var thisObj = this;
-
- if (this.chaptersPopup && this.chaptersPopup.is(':visible')) {
- this.chaptersPopup.hide();
- this.$chaptersButton.attr('aria-expanded','false').trigger('focus');
- }
- if (this.captionsPopup && this.captionsPopup.is(':visible')) {
- this.captionsPopup.hide();
- this.$ccButton.attr('aria-expanded', 'false');
- this.waitThenFocus(this.$ccButton);
- }
- if (this.prefsPopup && this.prefsPopup.is(':visible') && !this.hidingPopup) {
- this.hidingPopup = true;
- this.prefsPopup.hide();
- this.prefsPopup.find('li').removeClass('able-focus').attr('tabindex','-1');
- this.$prefsButton.attr('aria-expanded', 'false');
- if (!this.showingPrefsDialog) {
- this.waitThenFocus(thisObj.$prefsButton);
- }
- setTimeout(function() {
- thisObj.hidingPopup = false;
- },100);
- }
- if (this.$volumeSlider && this.$volumeSlider.is(':visible')) {
- this.$volumeSlider.hide().attr('aria-hidden','true');
- this.$volumeButton.attr('aria-expanded', 'false').trigger('focus');
- }
- if (this.$transcriptPopup && this.$transcriptPopup.is(':visible')) {
- this.hidingPopup = true;
- this.$transcriptPopup.hide();
- this.$transcriptPopup.find('li').removeClass('able-focus').attr('tabindex','-1');
- this.$transcriptPopupButton.attr('aria-expanded','false').trigger('focus');
- setTimeout(function() {
- thisObj.hidingPopup = false;
- },100);
- }
- if (this.$signPopup && this.$signPopup.is(':visible')) {
- this.$signPopup.hide();
- this.$signPopup.find('li').removeClass('able-focus').attr('tabindex','-1');
- this.$signPopupButton.attr('aria-expanded','false').trigger('focus');
- }
- };
-
- AblePlayer.prototype.setupPopups = function (which) {
-
- var popups, thisObj, i, tracks;
-
- popups = [];
- if (typeof which === 'undefined') {
- popups.push('prefs');
- }
-
- if (which === 'captions' || (typeof which === 'undefined')) {
- if (this.captions.length > 0) {
- popups.push('captions');
- }
- }
- if (which === 'chapters' || (typeof which === 'undefined')) {
- if (this.chapters.length > 0 && this.useChaptersButton) {
- popups.push('chapters');
- }
- }
- if (which === 'transcript-window' && this.transcriptType === 'popup') {
- popups.push('transcript-window');
- }
- if (which === 'sign-window' && this.hasSignLanguage) {
- popups.push('sign-window');
- }
- if (popups.length > 0) {
- thisObj = this;
- for (var i=0; i= 1) {
- tracks = this.chapters[0].cues;
- } else {
- tracks = [];
- }
- if (typeof this.chaptersPopup === 'undefined' || !this.chaptersPopup) {
- this.chaptersPopup = this.createPopup('chapters',tracks);
- }
- } else if (popup == 'transcript-window') {
- return this.createPopup('transcript-window');
- } else if (popup == 'sign-window') {
- return this.createPopup('sign-window');
- }
- }
- }
- };
-
- AblePlayer.prototype.provideFallback = function() {
-
-
- var i, $fallback;
-
- if (this.usingFallback) {
- return;
- } else {
- this.usingFallback = true;
- }
-
- if (!this.testFallback) {
- this.testFallback = 1;
- }
-
- if (typeof this.$media === 'undefined') {
- this.$media = $(this.media);
- }
-
- if (this.$media.attr('id')) {
- this.mediaId = this.$media.attr('id');
- } else {
- this.mediaId = 'media' + Math.floor(Math.random() * 1000000000).toString();
- }
-
- this.hasFallback = false;
- if (this.$media.children().length) {
- i = 0;
- while (i < this.$media.children().length && !this.hasFallback) {
- if (!(this.$media.children()[i].tagName === 'SOURCE' ||
- this.$media.children()[i].tagName === 'TRACK')) {
- this.hasFallback = true;
- }
- i++;
- }
- }
- if (!this.hasFallback) {
- $fallback = $('').text('Media player unavailable.');
- this.$media.append($fallback);
- }
-
- if (this.$media.attr('width')) {
- this.$media.css('width',this.$media.attr('width') + 'px');
- }
- if (this.$media.attr('height')) {
- this.$media.css('height',this.$media.attr('height') + 'px');
- }
- this.$media.removeAttr('data-able-player');
-
- this.$media.prop('controls',true);
-
- if (this.testFallback == 2) {
-
- $(this.$media).replaceWith($(''));
- this.$newFallbackElement = $('#foobar-' + this.mediaId);
-
- if (this.$media.children().length) {
- i = this.$media.children().length - 1;
- while (i >= 0) {
- this.$newFallbackElement.prepend($(this.$media.children()[i]));
- i--;
- }
- }
- if (!this.hasFallback) {
- this.$newFallbackElement.append($fallback);
- }
- }
- return;
- };
-
- AblePlayer.prototype.calculateControlLayout = function () {
-
-
- var controlLayout, playbackSupported, numA11yButtons;
-
- controlLayout = [];
- controlLayout[0] = [];
- controlLayout[1] = [];
- if (this.skin === 'legacy') {
- controlLayout[2] = [];
- controlLayout[3] = [];
- }
-
- controlLayout[0].push('play');
- controlLayout[0].push('restart');
- controlLayout[0].push('rewind');
- controlLayout[0].push('forward');
-
- if (this.skin === 'legacy') {
- controlLayout[1].push('seek');
- }
-
- if (this.hasPlaylist) {
- if (this.skin === 'legacy') {
- controlLayout[0].push('previous');
- controlLayout[0].push('next');
- } else {
- controlLayout[0].push('previous');
- controlLayout[0].push('next');
- }
- }
-
- if (this.isPlaybackRateSupported()) {
- playbackSupported = true;
- if (this.skin === 'legacy') {
- controlLayout[2].push('slower');
- controlLayout[2].push('faster');
- }
- } else {
- playbackSupported = false;
- }
-
- numA11yButtons = 0;
- if (this.hasCaptions) {
- numA11yButtons++;
- if (this.skin === 'legacy') {
- controlLayout[2].push('captions');
- } else {
- controlLayout[1].push('captions');
- }
- }
- if (this.hasSignLanguage) {
- numA11yButtons++;
- if (this.skin === 'legacy') {
- controlLayout[2].push('sign');
- } else {
- controlLayout[1].push('sign');
- }
- }
- if (this.mediaType === 'video') {
- if (this.hasOpenDesc || this.hasClosedDesc) {
- numA11yButtons++;
- if (this.skin === 'legacy') {
- controlLayout[2].push('descriptions');
- } else {
- controlLayout[1].push('descriptions');
- }
- }
- }
- if (this.transcriptType !== null && !(this.hideTranscriptButton)) {
- numA11yButtons++;
- if (this.skin === 'legacy') {
- controlLayout[2].push('transcript');
- } else {
- controlLayout[1].push('transcript');
- }
- }
- if (this.hasChapters && this.useChaptersButton) {
- numA11yButtons++;
- if (this.skin === 'legacy') {
- controlLayout[2].push('chapters');
- } else {
- controlLayout[1].push('chapters');
- }
- }
-
- if (this.skin == '2020' && numA11yButtons > 0) {
- controlLayout[1].push('pipe');
- }
-
- if (playbackSupported && this.skin === '2020') {
- controlLayout[1].push('faster');
- controlLayout[1].push('slower');
- controlLayout[1].push('pipe');
- }
-
- if (this.skin === 'legacy') {
- controlLayout[3].push('preferences');
- } else {
- controlLayout[1].push('preferences');
- }
-
- if (this.mediaType === 'video' && this.allowFullscreen && this.nativeFullscreenSupported() ) {
- if (this.skin === 'legacy') {
- controlLayout[3].push('fullscreen');
- } else {
- controlLayout[1].push('fullscreen');
- }
- }
-
- if (this.browserSupportsVolume()) {
- this.volumeButton = 'volume-' + this.getVolumeName(this.volume);
- if (this.skin === 'legacy') {
- controlLayout[1].push('volume');
- } else {
- controlLayout[1].push('volume');
- }
- } else {
- this.volume = false;
- }
- return controlLayout;
- };
-
- AblePlayer.prototype.addControls = function() {
-
-
- var thisObj, baseSliderWidth, controlLayout, numSections,
- i, j, controls, $controllerSpan, $sliderDiv, sliderLabel, $pipe, control,
- buttonTitle, $newButton, buttonText, position, buttonHeight,
- buttonWidth, buttonSide, controllerWidth, tooltipId, tooltipY, tooltipX,
- tooltipWidth, tooltipStyle, tooltip, tooltipTimerId, captionLabel, popupMenuId;
-
- thisObj = this;
-
- baseSliderWidth = 100;
-
- controlLayout = this.calculateControlLayout();
- numSections = controlLayout.length;
-
- tooltipId = this.mediaId + '-tooltip';
- this.$tooltipDiv = $('',{
- 'id': tooltipId,
- 'class': 'able-tooltip'
- }).hide();
- this.$controllerDiv.append(this.$tooltipDiv);
-
- if (this.skin == '2020') {
- $sliderDiv = $('
');
- sliderLabel = this.mediaType + ' ' + this.translate( 'seekbarLabel', 'timeline' );
- this.$controllerDiv.append($sliderDiv);
- this.seekBar = new AccessibleSlider($sliderDiv, 'horizontal', baseSliderWidth, 0, this.duration, this.seekInterval, sliderLabel, 'seekbar', true, 'visible');
- }
-
- let $controlRow = $('
');
- this.$controllerDiv.append($controlRow);
-
- for (i = 0; i < numSections; i++) {
- controls = controlLayout[i];
- if ((i % 2) === 0) {
- $controllerSpan = $('
',{
- 'class': 'able-left-controls'
- });
- } else {
- $controllerSpan = $('
',{
- 'class': 'able-right-controls'
- });
- }
- $controlRow.append($controllerSpan);
-
- for (j=0; j
');
- sliderLabel = this.mediaType + ' ' + this.translate( 'seekbarLabel', 'timeline' );
- $controllerSpan.append($sliderDiv);
- if (typeof this.duration === 'undefined' || this.duration === 0) {
- this.duration = 60;
- this.elapsed = 0;
- }
- this.seekBar = new AccessibleSlider($sliderDiv, 'horizontal', baseSliderWidth, 0, this.duration, this.seekInterval, sliderLabel, 'seekbar', true, 'visible');
- } else if (control === 'pipe') {
- $pipe = $('
', {
- 'tabindex': '-1',
- 'aria-hidden': 'true',
- 'class': 'able-pipe',
- });
- $pipe.append('|');
- $controllerSpan.append($pipe);
- } else {
- buttonTitle = this.getButtonTitle(control);
-
-
- $newButton = $('',{
- 'role': 'button',
- 'tabindex': '0',
- 'class': 'able-button-handler-' + control
- });
-
- if (control === 'volume' || control === 'preferences' || control === 'captions') {
- if (control == 'preferences') {
- this.prefCats = this.getPreferencesGroups();
- if (this.prefCats.length > 1) {
- popupMenuId = this.mediaId + '-prefs-menu';
- $newButton.attr({
- 'aria-controls': popupMenuId,
- 'aria-haspopup': 'menu',
- 'aria-expanded': 'false'
- });
- } else if (this.prefCats.length === 1) {
- $newButton.attr({
- 'aria-haspopup': 'dialog'
- });
- }
- } else if (control === 'volume') {
- popupMenuId = this.mediaId + '-volume-slider';
- $newButton.attr({
- 'aria-controls': popupMenuId,
- 'aria-expanded': 'false'
- });
- } else if (control === 'captions' && this.captions) {
- if (this.captions.length > 1) {
- $newButton.attr('aria-expanded', 'false')
- } else {
- $newButton.attr('aria-pressed', 'false')
- }
- }
- }
- var getControl = control;
- if ( control === 'faster' && this.speedIcons === 'animals' ) {
- getControl = 'rabbit';
- }
- if ( control === 'slower' && this.speedIcons === 'animals' ) {
- getControl = 'turtle';
- }
- if ( control === 'volume' ) {
- this.getIcon( $newButton, this.volumeButton );
- } else {
- if ( 'fullscreen' === getControl ) {
- getControl = ( this.fullscreen ) ? 'fullscreen-collapse' : 'fullscreen-expand';
- }
- this.getIcon( $newButton, getControl );
- }
-
- this.setText($newButton,buttonTitle);
- $newButton.on('mouseenter focus',function(e) {
-
- clearTimeout(tooltipTimerId);
-
- buttonText = $(this).attr('aria-label');
- position = $(this).position();
- buttonHeight = $(this).height();
- buttonWidth = $(this).width();
- controllerWidth = thisObj.$controllerDiv.width();
- position.right = controllerWidth - position.left - buttonWidth;
-
- tooltipY = position.top + buttonHeight + 5;
-
- if ($(this).parent().hasClass('able-right-controls')) {
- buttonSide = 'right';
- } else {
- buttonSide = 'left';
- }
- tooltipWidth = AblePlayer.localGetElementById($newButton[0], tooltipId).text(buttonText).width();
- if (buttonSide == 'left') {
- tooltipX = position.left - tooltipWidth/2;
- if (tooltipX < 0) {
- tooltipX = 2;
- }
- tooltipStyle = {
- left: tooltipX + 'px',
- right: '',
- top: tooltipY + 'px'
- };
- } else {
- tooltipX = position.right - tooltipWidth/2;
- if (tooltipX < 0) {
- tooltipX = 2;
- }
- tooltipStyle = {
- left: '',
- right: tooltipX + 'px',
- top: tooltipY + 'px'
- };
- }
- tooltip = AblePlayer.localGetElementById($newButton[0], tooltipId).text(buttonText).css(tooltipStyle);
- thisObj.showTooltip(tooltip);
- $(this).on('mouseleave blur',function() {
-
-
- clearTimeout(tooltipTimerId);
- tooltipTimerId = setTimeout(function() {
- AblePlayer.localGetElementById($newButton[0], tooltipId).text('').hide();
- }, 500);
-
- thisObj.$tooltipDiv.on('mouseenter focus', function() {
- clearTimeout(tooltipTimerId);
- });
-
- thisObj.$tooltipDiv.on('mouseleave blur', function() {
- AblePlayer.localGetElementById($newButton[0], tooltipId).text('').hide();
- });
-
- });
- });
-
- if (control === 'captions') {
- if (!this.prefCaptions || this.prefCaptions !== 1) {
- if (this.captions.length > 1) {
- captionLabel = this.translate( 'captions', 'Captions' );
- } else {
- captionLabel = this.translate( 'showCaptions', 'Show captions' );
- }
- $newButton.addClass('buttonOff').attr('title',captionLabel);
- $newButton.attr('aria-pressed', 'false');
- }
- } else if (control === 'descriptions') {
- if (!this.prefDesc || this.prefDesc !== 1) {
- $newButton.addClass('buttonOff').attr( 'title', this.translate( 'turnOnDescriptions', 'Turn on descriptions' ) );
- }
- }
-
- $controllerSpan.append($newButton);
-
- if (control === 'play') {
- this.$playpauseButton = $newButton;
- } else if (control == 'previous') {
- this.$prevButton = $newButton;
- if (this.buttonWithFocus == 'previous') {
- this.$prevButton.trigger('focus');
- this.buttonWithFocus = null;
- }
- } else if (control == 'next') {
- this.$nextButton = $newButton;
- if (this.buttonWithFocus == 'next') {
- this.$nextButton.trigger('focus');
- this.buttonWithFocus = null;
- }
- } else if (control === 'captions') {
- this.$ccButton = $newButton;
- } else if (control === 'sign') {
- this.$signButton = $newButton;
- if (!(this.$signWindow.is(':visible'))) {
- this.$signButton.addClass('buttonOff');
- }
- } else if (control === 'descriptions') {
- this.$descButton = $newButton;
- } else if (control === 'mute') {
- this.$muteButton = $newButton;
- } else if (control === 'transcript') {
- this.$transcriptButton = $newButton;
- if (!(this.$transcriptDiv.is(':visible'))) {
- this.$transcriptButton.addClass('buttonOff').attr( 'title', this.translate( 'showTranscript', 'Show transcript' ) );
- }
- } else if (control === 'fullscreen') {
- this.$fullscreenButton = $newButton;
- } else if (control === 'chapters') {
- this.$chaptersButton = $newButton;
- } else if (control === 'preferences') {
- this.$prefsButton = $newButton;
- } else if (control === 'volume') {
- this.$volumeButton = $newButton;
- }
- }
- if (control === 'volume') {
- this.addVolumeSlider($controllerSpan);
- }
- }
- if ((i % 2) == 1) {
- this.$controllerDiv.append('
');
- }
- }
-
- if (typeof this.$captionsDiv !== 'undefined') {
- this.stylizeCaptions(this.$captionsDiv);
- }
- if (typeof this.$descDiv !== 'undefined') {
- this.stylizeCaptions(this.$descDiv);
- }
-
- this.controls = [];
- for (var sec in controlLayout) if (controlLayout.hasOwnProperty(sec)) {
- this.controls = this.controls.concat(controlLayout[sec]);
- }
-
- this.refreshControls();
- };
-
- AblePlayer.prototype.cuePlaylistItem = function(sourceIndex) {
-
-
- var $newItem, prevPlayer, newPlayer, itemTitle, itemLang, nowPlayingSpan;
-
- var thisObj = this;
-
- prevPlayer = this.player;
-
- if (this.initializing) {
- } else {
- if (this.playerCreated) {
- this.deletePlayer('playlist');
- }
- }
-
- this.swappingSrc = true;
-
- if (this.startedPlaying) {
- this.okToPlay = true;
- } else {
- this.okToPlay = false;
- }
-
- this.loadingMedia = false;
-
- $newItem = this.$playlist.eq(sourceIndex);
- if (this.hasAttr($newItem,'data-youtube-id')) {
- this.youTubeId = this.getYouTubeId($newItem.attr('data-youtube-id'));
- if (this.hasAttr($newItem,'data-youtube-desc-id')) {
- this.youTubeDescId = this.getYouTubeId($newItem.attr('data-youtube-desc-id'));
- }
- newPlayer = 'youtube';
- } else if (this.hasAttr($newItem,'data-vimeo-id')) {
- this.vimeoId = this.getVimeoId($newItem.attr('data-vimeo-id'));
- if (this.hasAttr($newItem,'data-vimeo-desc-id')) {
- this.vimeoDescId = this.getVimeoId($newItem.attr('data-vimeo-desc-id'));
- }
- newPlayer = 'vimeo';
- } else {
- newPlayer = 'html5';
- }
- if (newPlayer === 'youtube') {
- if (prevPlayer === 'html5') {
- if (this.playing) {
- this.pauseMedia();
- }
- this.$media.hide();
- }
- } else {
- this.youTubeId = false;
- if (prevPlayer === 'youtube') {
- this.$media.show();
- }
- }
- this.player = newPlayer;
-
- this.$media.empty();
-
- if (this.hasAttr($newItem,'data-poster')) {
- this.$media.attr('poster',$newItem.attr('data-poster'));
- }
- if (this.hasAttr($newItem,'data-youtube-desc-id')) {
- this.$media.attr('data-youtube-desc-id',$newItem.attr('data-youtube-desc-id'));
- }
- if (this.youTubeId) {
- this.$media.attr('data-youtube-id',$newItem.attr('data-youtube-id'));
- }
-
- var $sourceSpans = $newItem.children('span.able-source');
- if ($sourceSpans.length) {
- $sourceSpans.each(function() {
- const $this = $(this);
-
- if (thisObj.hasAttr($this, "data-src")) {
- const sanitizedSrc = DOMPurify.sanitize($this.attr("data-src"));
-
- if (validate.isProtocolSafe(sanitizedSrc)) {
- const $newSource = $("
", { src: sanitizedSrc });
-
- const optionalAttributes = [
- "data-type",
- "data-desc-src",
- "data-sign-src",
- ];
-
- optionalAttributes.forEach((attr) => {
- if (thisObj.hasAttr($this, attr)) {
- const attrValue = $this.attr(attr);
- const sanitizedValue = DOMPurify.sanitize(attrValue);
-
- if (attr.endsWith("-src") && validate.isProtocolSafe(sanitizedValue)) {
- $newSource.attr(attr, sanitizedValue);
- } else if (!attr.endsWith("-src")) {
- $newSource.attr(attr, sanitizedValue);
- }
- }
- });
-
- thisObj.$media.append($newSource);
- }
- }
- });
- }
-
- var $trackSpans = $newItem.children('span.able-track');
- if ($trackSpans.length) {
- $trackSpans.each(function() {
- const $this = $(this);
- if (thisObj.hasAttr($this, "data-src") && thisObj.hasAttr($this, "data-kind") && thisObj.hasAttr($this, "data-srclang")) {
- const sanitizedSrc = DOMPurify.sanitize($this.attr("data-src"));
- if (validate.isProtocolSafe(sanitizedSrc)) {
- const $newTrack = $("", {
- src: sanitizedSrc,
- kind: $this.attr("data-kind"),
- srclang: $this.attr("data-srclang"),
- });
- const optionalAttributes = [
- "data-label",
- "data-desc",
- "data-default",
- ];
- optionalAttributes.forEach((attr) => {
- if (thisObj.hasAttr($this, attr)) {
- $newTrack.attr(attr, DOMPurify.sanitize($this.attr(attr)));
- }
- });
- thisObj.$media.append($newTrack);
- }
- }
- });
- }
-
- itemTitle = DOMPurify.sanitize( $newItem.text() );
- if (this.hasAttr($newItem,'lang')) {
- itemLang = $newItem.attr('lang');
- }
- this.$sources = this.$media.find('source');
-
- if (this.recreatingPlayer) {
- return;
- }
- this.recreatePlayer().then(function() {
-
- thisObj.$playlist.removeClass('able-current')
- .children('button').removeAttr('aria-current');
- thisObj.$playlist.eq(sourceIndex).addClass('able-current')
- .children('button').attr('aria-current','true');
-
- if (thisObj.showNowPlaying === true) {
- if (typeof thisObj.$nowPlayingDiv !== 'undefined') {
- nowPlayingSpan = $('');
- if (typeof itemLang !== 'undefined') {
- nowPlayingSpan.attr('lang',itemLang);
- }
- nowPlayingSpan.html('' + thisObj.tt.selectedTrack + ': ' + itemTitle);
- thisObj.$nowPlayingDiv.html(nowPlayingSpan);
- }
- }
-
- if (thisObj.initializing) {
- thisObj.swappingSrc = false;
- } else {
- if (thisObj.player === 'html5') {
- if (!thisObj.loadingMedia) {
- thisObj.media.load();
- thisObj.loadingMedia = true;
- }
- } else if (thisObj.player === 'youtube') {
- thisObj.okToPlay = true;
- }
- }
- thisObj.initializing = false;
- thisObj.playerCreated = true;
- });
- };
-
- AblePlayer.prototype.deletePlayer = function(context) {
-
-
-
- if (this.player === 'youtube' && this.youTubePlayer) {
- this.youTubePlayer.destroy();
- }
-
- if (this.player === 'vimeo' && this.vimeoPlayer) {
- this.vimeoPlayer.destroy();
- }
-
- this.$controllerDiv.empty();
- this.$elapsedTimeContainer.empty().text('0:00');
- this.$durationContainer.empty();
-
- if (this.$signWindow) {
- this.$signWindow.remove();
- }
- if (this.$transcriptArea) {
- this.$transcriptArea.remove();
- }
- $('.able-modal-dialog').remove();
-
- if (this.$captionsWrapper) {
- this.$captionsWrapper.remove();
- }
- if (this.$descDiv) {
- this.$descDiv.remove();
- }
-
- this.hasCaptions = false;
- this.hasChapters = false;
- this.hasDescTracks = false;
- this.hasOpenDesc = false;
- this.hasClosedDesc = false;
-
- this.captionsPopup = null;
- this.chaptersPopup = null;
- this.transcriptType = null;
-
- this.playerDeleted = true;
- };
-
- AblePlayer.prototype.getButtonTitle = function(control) {
-
- if (control === 'playpause') {
- return this.translate( 'play', 'Play' );
- } else if (control === 'play') {
- return this.translate( 'play', 'Play' );
- } else if (control === 'pause') {
- return this.translate( 'pause', 'Pause' );
- } else if (control === 'restart') {
- return this.translate( 'restart', 'Restart' );
- } else if (control === 'previous') {
- return this.translate( 'prevTrack', 'Previous track' );
- } else if (control === 'next') {
- return this.translate( 'nextTrack', 'Next track' );
- } else if (control === 'rewind') {
- return this.translate( 'rewind', 'Rewind' );
- } else if (control === 'forward') {
- return this.translate( 'forward', 'Forward' );
- } else if (control === 'captions') {
- if (this.captions.length > 1) {
- return this.translate( 'captions', 'Captions' );
- } else {
- return (this.captionsOn) ? this.translate( 'hideCaptions', 'Hide captions' ) : this.translate( 'showCaptions', 'Show captions' );
- }
- } else if (control === 'descriptions') {
- return (this.descOn) ? this.translate( 'turnOffDescriptions', 'Turn off descriptions' ) : this.translate( 'turnOnDescriptions', 'Turn on descriptions' );
- } else if (control === 'transcript') {
- return (this.$transcriptDiv.is(':visible')) ? this.translate( 'hideTranscript', 'Hide transcript' ) : this.translate( 'showTranscript', 'Show transcript' );
- } else if (control === 'chapters') {
- return this.translate( 'chapters', 'Chapters' );
- } else if (control === 'sign') {
- return this.translate( 'sign', 'Sign language' );
- } else if (control === 'volume') {
- return this.translate( 'volume', 'Volume' );
- } else if (control === 'faster') {
- return this.translate( 'faster', 'Faster' );
- } else if (control === 'slower') {
- return this.translate( 'slower', 'Slower' );
- } else if (control === 'preferences') {
- return this.translate( 'preferences', 'Preferences' );
- } else if (control === 'fullscreen') {
- return ( !this.fullscreen ) ? this.translate( 'enterFullScreen', 'Enter full screen' ) : this.translate( 'exitFullScreen', 'Exit full screen' );
- } else {
- if (this.debug) {
-
- }
- return this.capitalizeFirstLetter( control );
- }
- };
-})(jQuery);
-
-
-var preProcessing = {
- transformCSSClasses: function (vttContent) {
- if ( vttContent.length > 1000 ) {
- throw new Error( "Input too long" );
- }
- return vttContent.replace(
- /<(v|c|b|i|u|lang|ruby)\.([\w\.]+)([^>]*)>/g,
- function (_, tag, cssClasses, otherAttrs) {
- var classAttr = cssClasses.replace(/\./g, " ");
- return `<${tag} class="${classAttr}"${otherAttrs}>`;
- }
- );
- },
-
- transformLangTags: function (content) {
- return content.replace(
- /]*)>/g,
- function (_, langCode, otherAttrs) {
- return '";
- }
- );
- },
-
- transformVTags: function (content) {
- return content.replace(/]*?)>/g, function (_, tagAttributes) {
- var classMatch = tagAttributes.match(/class="([^"]*)"/);
- var classAttr = classMatch ? classMatch[0] : "";
- var nonClassAttributes = tagAttributes
- .replace(/class="[^"]*"/, "")
- .trim()
- .split(/\s+/);
-
- var attributes = [];
- var titleParts = [];
-
- nonClassAttributes.forEach(function (token) {
- if (token.indexOf("=") !== -1) {
- attributes.push(token);
+ AblePlayer.prototype.getCaptionClickFunction = function (track) {
+ // Returns the function used when a caption is clicked in the captions menu.
+ // Not called if user clicks "Captions off". Instead, that triggers getCaptionOffFunction()
+
+ var thisObj = this;
+ return function () {
+ thisObj.selectedCaptions = track;
+ thisObj.captionLang = track.language;
+ thisObj.currentCaption = -1;
+ if (thisObj.usingYouTubeCaptions) {
+ if (thisObj.captionsOn) {
+ // Two things must be true in order for setOption() to work:
+ // The YouTube caption module must be loaded
+ // and the video must have started playing
+ if (
+ thisObj.youTubePlayer.getOptions("captions") &&
+ thisObj.startedPlaying
+ ) {
+ thisObj.youTubePlayer.setOption("captions", "track", {
+ languageCode: thisObj.captionLang,
+ });
+ } else {
+ // the two conditions were not met
+ // try again to set the language after onApiChange event is triggered
+ // meanwhile, the following variable will hold the value
+ thisObj.captionLangPending = thisObj.captionLang;
+ }
+ } else {
+ if (thisObj.youTubePlayer.getOptions("captions")) {
+ thisObj.youTubePlayer.setOption("captions", "track", {
+ languageCode: thisObj.captionLang,
+ });
+ } else {
+ thisObj.youTubePlayer.loadModule("captions");
+ thisObj.captionLangPending = thisObj.captionLang;
+ }
+ }
+ } else if (thisObj.usingVimeoCaptions) {
+ thisObj.vimeoPlayer
+ .enableTextTrack(thisObj.captionLang)
+ .catch(function (error) {
+ switch (error.name) {
+ }
+ });
} else {
- titleParts.push(token);
+ // using local track elements for captions/subtitles
+ thisObj.syncTrackLanguages("captions", thisObj.captionLang);
+ if (!thisObj.swappingSrc) {
+ thisObj.updateCaption(thisObj.elapsed);
+ thisObj.showDescription(thisObj.elapsed);
+ }
}
- });
-
- var title = titleParts.join(" ");
- var newTag = " 0) {
- newTag += " " + attributes.join(" ");
- }
+ // Returns the function used when the "Captions Off" button is clicked in the captions tooltip.
+ AblePlayer.prototype.getCaptionOffFunction = function () {
+ var thisObj = this;
+ return function () {
+ if (thisObj.player == "youtube") {
+ thisObj.youTubePlayer.unloadModule("captions");
+ } else if (thisObj.usingVimeoCaptions) {
+ thisObj.vimeoPlayer.disableTextTrack();
+ }
+ thisObj.captionsOn = false;
+ thisObj.currentCaption = -1;
- if (classAttr) {
- newTag += " " + classAttr;
- }
+ if (thisObj.mediaType === "audio") {
+ thisObj.$captionsContainer.addClass("captions-off");
+ }
- newTag += ">";
- return newTag;
- });
- },
-};
+ // stopgap to prevent spacebar in Firefox from reopening popup
+ // immediately after closing it (used in handleCaptionToggle())
+ thisObj.hidingPopup = true;
+ thisObj.captionsPopup.hide();
+ thisObj.$ccButton.attr("aria-expanded", "false");
+ // Ensure stopgap gets cancelled if handleCaptionToggle() isn't called
+ // e.g., if user triggered button with Enter or mouse click, not spacebar
+ setTimeout(function () {
+ thisObj.hidingPopup = false;
+ }, 100);
+ thisObj.updateCaptionsMenu();
+ thisObj.waitThenFocus(thisObj.$ccButton);
+
+ // save preference to cookie
+ thisObj.prefCaptions = 0;
+ thisObj.updatePreferences("prefCaptions");
+ if (!this.swappingSrc) {
+ thisObj.refreshControls("captions");
+ thisObj.updateCaption();
+ }
+ };
+ };
-var postProcessing = {
- postprocessCTag: function (vttContent) {
- return vttContent.replace(
- //g,
- function (_, classNames) {
- var classes = classNames.replace(/ /g, ".");
- return "";
+ AblePlayer.prototype.showCaptions = function (now) {
+ var c, thisCaption, nextCaption, captionText, announceText, announcement, availableTime, rate, cueLength, estimatedTime;
+ var cues;
+ if (null !== this.selectedCaptions.cues && this.selectedCaptions.cues.length) {
+ cues = this.selectedCaptions.cues;
+ } else if (this.captions.length >= 1) {
+ cues = this.captions[0].cues;
+ } else {
+ cues = [];
}
- );
- },
-
- postprocessVTag: function (vttContent) {
- return vttContent.replace(
- /]*)class="([\w\s]+)"([^>]*)>/g,
- function (_, beforeClass, classNames, afterClass) {
- var classes = classNames.trim().split(/\s+/).join(".");
- var attrs = (beforeClass + afterClass)
- .replace(/\s*class="[\w\s]+"/, "")
- .trim();
- return "";
+ for (c = 0; c < cues.length; c++) {
+ if (cues[c].start <= now && cues[c].end > now) {
+ thisCaption = c;
+ nextCaption = cues[ c + 1 ];
+ break;
+ }
}
- );
- },
- postprocessLangTag: function (vttContent) {
- return vttContent.replace(
- /]*)>/g,
- function (_, langCode, otherAttrs) {
- return "";
+ if (typeof thisCaption !== "undefined") {
+ if (this.currentCaption !== thisCaption) {
+ // it's time to load the new caption into the container div
+ captionText = this.flattenCueForCaption(cues[thisCaption]).replace( /\n/g, " " );
+ // If preference enabled to voice captions, send to synthesizer.
+ if ( this.speechEnabled && this.prefCaptionsSpeak == 1 ) {
+ announceText = new DOMParser().parseFromString( captionText, 'text/html' );
+ announcement = announceText.body.textContent || '';
+ availableTime = ( thisCaption ) ? nextCaption.start - cues[thisCaption].start : 0;
+ rate = false;
+ if ( availableTime ) {
+ cueLength = announcement.trim().split(/\W+/).length;
+ estimatedTime = Math.round( ( ( cueLength ) / 135 ) * 60 );
+ rate = ( estimatedTime / availableTime );
+ }
+ // use browser's built-in speech synthesis
+ this.announceText( 'caption', announcement, rate );
+ }
+ this.$captionsDiv.html(captionText);
+ this.currentCaption = thisCaption;
+ if (captionText.length === 0) {
+ // hide captionsDiv; otherwise background-color is visible due to padding
+ this.$captionsDiv.css("display", "none");
+ } else {
+ this.$captionsDiv.css("display", "inline-block");
+ }
+ }
+ } else {
+ this.$captionsDiv.html("").css("display", "none");
+ this.currentCaption = -1;
}
- );
- },
-};
-
-var validate = {
- preProcessVttContent: function (vttContent) {
- var processedCSS = preProcessing.transformCSSClasses(vttContent);
- var processedLang = preProcessing.transformLangTags(processedCSS);
- var processedVTags = preProcessing.transformVTags(processedLang);
- return processedVTags;
- },
+ };
- postProcessVttContent: function (sanitizedVttContent, originalVttContent) {
- var processedCTags = postProcessing.postprocessCTag(sanitizedVttContent);
- var processedVTags = postProcessing.postprocessVTag(processedCTags);
- var processedLangTags = postProcessing.postprocessLangTag(processedVTags);
+ AblePlayer.prototype.flattenCueForCaption = function (cue) {
+ // Takes a cue and returns the caption text to display
+ // Also used for chapters
+
+ // Support for 'i' and 'b' tags added in 2.3.66
+ // TODO: Add support for 'c' (class) and 'ruby'
+
+ // c (class): Some text
+ // Classes can be used to modify other tags too (e.g., )
+ // If tag, should be rendered as a
+
+ // ruby: http://www.w3schools.com/tags/tag_ruby.asp
+
+ // WebVTT also supports 'u' (underline)
+ // I see no reason to support that in Able Player.
+ // If it's available authors are likely to use it incorrectly
+ // where or should be used instead
+ // Here are the rare use cases where an underline is appropriate on the web:
+ // http://html5doctor.com/u-element/
+
+ var result = [];
+
+ var flattenComponent = function (component) {
+ var result = [],
+ ii;
+ if (component.type === "string") {
+ result.push(component.value);
+ } else if (component.type === "v") {
+ result.push("(" + component.value + ")");
+ for (ii = 0; ii < component.children.length; ii++) {
+ result.push(flattenComponent(component.children[ii]));
+ }
+ } else if (component.type === "i") {
+ result.push("");
+ for (ii = 0; ii < component.children.length; ii++) {
+ result.push(flattenComponent(component.children[ii]));
+ }
+ result.push(" ");
+ } else if (component.type === "b") {
+ result.push("");
+ for (ii = 0; ii < component.children.length; ii++) {
+ result.push(flattenComponent(component.children[ii]));
+ }
+ result.push(" ");
+ } else {
+ for (ii = 0; ii < component.children.length; ii++) {
+ result.push(flattenComponent(component.children[ii]));
+ }
+ }
+ return result.join("");
+ };
- var arrowReplaced = processedLangTags.replace(/-->/g, "-->");
- var timestampTagReplaced = arrowReplaced.replace(/<([\d:.]+)>/g, '<$1>');
+ if (typeof cue.components !== "undefined") {
+ for (var ii = 0; ii < cue.components.children.length; ii++) {
+ result.push(flattenComponent(cue.components.children[ii]));
+ }
+ }
+ return result.join("");
+ };
- var finalContent = timestampTagReplaced.replace(
- /<\/v>/g,
- function (match, offset) {
- return originalVttContent.indexOf(match, offset) !== -1 ? match : "";
+ AblePlayer.prototype.getCaptionsOptions = function (pref) {
+ var options = [];
+
+ switch (pref) {
+ case "prefCaptionsFont":
+ options[0] = ["serif", this.translate( 'serif', 'serif' )];
+ options[1] = ["sans-serif", this.translate( 'sans', 'sans-serif' )];
+ options[2] = ["cursive", this.translate( 'cursive', 'cursive' )];
+ options[3] = ["fantasy", this.translate( 'fantasy', 'fantasy' )];
+ options[4] = ["monospace", this.translate( 'monospace', 'monospace' )];
+ break;
+
+ case "prefCaptionsColor":
+ case "prefCaptionsBGColor":
+ // HTML color values must be in English
+ options[0] = ["white", this.translate( 'white', 'white' )];
+ options[1] = ["yellow", this.translate( 'yellow', 'yellow' )];
+ options[2] = ["green", this.translate( 'green', 'green' )];
+ options[3] = ["cyan", this.translate( 'cyan', 'cyan' )];
+ options[4] = ["blue", this.translate( 'blue', 'blue' )];
+ options[5] = ["magenta", this.translate( 'magenta', 'magenta' )];
+ options[6] = ["red", this.translate( 'red', 'red' )];
+ options[7] = ["black", this.translate( 'black', 'black' )];
+ break;
+
+ case "prefCaptionsSize":
+ options[0] = "75%";
+ options[1] = "100%";
+ options[2] = "125%";
+ options[3] = "150%";
+ options[4] = "200%";
+ break;
+
+ case "prefCaptionsOpacity":
+ options[0] = "0%";
+ options[1] = "25%";
+ options[2] = "50%";
+ options[3] = "75%";
+ options[4] = "100%";
+ break;
+
+ case "prefCaptionsStyle":
+ options[0] = this.translate( 'captionsStylePopOn', 'Pop-on' );
+ options[1] = this.translate( 'captionsStyleRollUp', 'Roll-up' );
+ break;
+
+ case "prefCaptionsPosition":
+ options[0] = "overlay";
+ options[1] = "below";
+ break;
+
+ case "prefCaptionsSpeak":
+ options[0] = ["0", this.translate( 'off', 'Off' ) ];
+ options[1] = ["1", this.translate( 'on', 'On' ) ];
+ break;
+
+ case "prefCaptionsVoice":
+ options[0] = null; // set later.
+ break;
+
+ case "prefCaptionsPitch":
+ options[0] = null; // set later.
+ break;
+
+ case "prefCaptionsRate":
+ options[0] = null; // set later.
+ break;
+
+ case "prefCaptionsVolume":
+ options[0] = null; // set later.
+ break;
}
- );
- return finalContent;
- },
+ return options;
+ };
- sanitizeVttContent: function (vttContent) {
- if (vttContent === null || vttContent === undefined) {
- return "";
- }
- var preSanitizedVttContent = validate.preProcessVttContent(vttContent);
+ AblePlayer.prototype.translatePrefs = function (pref, value, outputFormat) {
+ // translate current value of pref to a value supported by outputformat
+ if (outputFormat == "youtube") {
+ if (pref === "size") {
+ // YouTube font sizes are a range from -1 to 3 (0 = default)
+ switch (value) {
+ case "75%":
+ return -1;
+ case "100%":
+ return 0;
+ case "125%":
+ return 1;
+ case "150%":
+ return 2;
+ case "200%":
+ return 3;
+ }
+ }
+ }
+ return false;
+ };
- var config = {
- ALLOWED_TAGS: ["b", "i", "u", "v", "c", "lang", "ruby", "rt", "rp"],
- ALLOWED_ATTR: ["title", "class", "lang"],
- KEEP_CONTENT: true,
+ AblePlayer.prototype.stylizeCaptions = function ($element, pref) {
+ // $element is the jQuery element containing the captions
+ // this function handles stylizing of the sample caption text in the Prefs dialog
+ // plus the actual production captions
+ // TODO: consider applying the same user prefs to visible text-based description
+ var property, newValue, opacity;
+
+ if (typeof $element !== "undefined") {
+ if (pref == "prefCaptionsPosition") {
+ this.positionCaptions();
+ } else if (typeof pref !== "undefined") {
+ // just change the one property that user just changed
+ if (pref === "prefCaptionsFont") {
+ property = "font-family";
+ } else if (pref === "prefCaptionsSize") {
+ property = "font-size";
+ } else if (pref === "prefCaptionsColor") {
+ property = "color";
+ } else if (pref === "prefCaptionsBGColor") {
+ property = "background-color";
+ } else if (pref === "prefCaptionsOpacity") {
+ property = "opacity";
+ }
+ if (pref === "prefCaptionsOpacity") {
+ newValue =
+ parseFloat($("#" + this.mediaId + "_" + pref).val()) / 100.0;
+ } else {
+ newValue = $("#" + this.mediaId + "_" + pref).val();
+ }
+ $element.css(property, newValue);
+ } else {
+ // no property was specified, update all styles with current saved prefs
+ opacity = parseFloat(this.prefCaptionsOpacity) / 100.0;
+ $element.css({
+ "font-family": this.prefCaptionsFont,
+ color: this.prefCaptionsColor,
+ "background-color": this.prefCaptionsBGColor,
+ opacity: opacity,
+ });
+ if ($element === this.$captionsDiv) {
+ if (typeof this.$captionsDiv !== "undefined") {
+ this.$captionsDiv.css({
+ "font-size": this.prefCaptionsSize,
+ });
+ }
+ }
+ if (this.prefCaptionsPosition === "below") {
+ // also need to add the background color to the wrapper div
+ if (typeof this.$captionsWrapper !== "undefined") {
+ this.$captionsWrapper.css({
+ "background-color": this.prefCaptionsBGColor,
+ opacity: "1",
+ });
+ }
+ } else if (this.prefCaptionsPosition === "overlay") {
+ // no background color for overlay wrapper, captions are displayed in-line
+ if (typeof this.$captionsWrapper !== "undefined") {
+ this.$captionsWrapper.css({
+ "background-color": "transparent",
+ opacity: "",
+ });
+ }
+ }
+ this.positionCaptions();
+ }
+ }
+ };
+ AblePlayer.prototype.positionCaptions = function (position) {
+ // set caption position to either 'overlay' or 'below'
+ // if position parameter was passed to this function, use that
+ // otherwise use user preference
+ if (typeof position === "undefined") {
+ position = this.prefCaptionsPosition;
+ }
+ if (typeof this.$captionsWrapper !== "undefined") {
+ if (position == "below") {
+ this.$captionsWrapper
+ .removeClass("able-captions-overlay")
+ .addClass("able-captions-below");
+ // also need to update in-line styles
+ this.$captionsWrapper.css({
+ "background-color": this.prefCaptionsBGColor,
+ opacity: "1",
+ });
+ } else {
+ this.$captionsWrapper
+ .removeClass("able-captions-below")
+ .addClass("able-captions-overlay");
+ this.$captionsWrapper.css({
+ "background-color": "transparent",
+ opacity: "",
+ });
+ }
+ }
};
+ }
- var sanitizedVttContent = DOMPurify.sanitize(
- preSanitizedVttContent,
- config
- );
+ function addChaptersFunctions(AblePlayer) {
+
+ AblePlayer.prototype.populateChaptersDiv = function() {
+
+ var headingLevel, headingType, headingId, $chaptersHeading;
+ if ( ! this.chaptersDivLocation ) {
+ return;
+ }
+ if ($('#' + this.chaptersDivLocation)) {
+
+ this.$chaptersDiv = $('#' + this.chaptersDivLocation);
+ this.$chaptersDiv.addClass('able-chapters-div');
+
+ // empty content from previous build before starting fresh
+ this.$chaptersDiv.empty();
+
+ // add optional header
+ if (this.chaptersTitle) {
+ headingLevel = this.getNextHeadingLevel(this.$chaptersDiv);
+ headingType = 'h' + headingLevel.toString();
+ headingId = this.mediaId + '-chapters-heading';
+ $chaptersHeading = $('<' + headingType + '>', {
+ 'class': 'able-chapters-heading',
+ 'id': headingId
+ }).text(this.chaptersTitle);
+ this.$chaptersDiv.append($chaptersHeading);
+ }
+
+ this.$chaptersNav = $('');
+ if (this.chaptersTitle) {
+ this.$chaptersNav.attr( 'aria-labelledby', headingId );
+ } else {
+ this.$chaptersNav.attr( 'aria-label', this.translate( 'chapters', 'Chapters' ) );
+ }
+ this.$chaptersDiv.append(this.$chaptersNav);
+
+ // populate this.$chaptersNav with a list of chapters
+ this.updateChaptersList();
+ }
+ };
+
+ AblePlayer.prototype.updateChaptersList = function() {
+
+ var thisObj, cues, $chaptersList, c, thisChapter,
+ $chapterItem, $chapterButton, hasDefault,
+ getClickFunction, $clickedItem;
+
+ thisObj = this;
+
+ // TODO: Update this so it can change the chapters popup menu
+ // currently it only works if chapters are in an external container
+ if (!this.$chaptersNav) {
+ return false;
+ }
+
+ if (typeof this.useChapterTimes === 'undefined') {
+ this.useChapterTimes = (this.seekbarScope === 'chapter' && this.selectedChapters.cues.length) ? true : false;
+ }
+ if (this.useChapterTimes) {
+ cues = this.selectedChapters.cues;
+ } else if (this.chapters.length >= 1) {
+ cues = this.chapters[0].cues;
+ } else {
+ cues = [];
+ }
+ if (cues.length > 0) {
+ $chaptersList = $('');
+ for (c = 0; c < cues.length; c++) {
+ thisChapter = c;
+ $chapterItem = $(' ');
+ $chapterButton = $('',{
+ 'type': 'button',
+ 'val': thisChapter
+ }).text(this.flattenCueForCaption(cues[thisChapter]));
+
+ // add event listeners
+ getClickFunction = function (time) {
+ return function () {
+ thisObj.seekTrigger = 'chapter';
+ $clickedItem = $(this).closest('li');
+ $chaptersList = $(this).closest('ul').find('li');
+ $chaptersList.removeClass('able-current-chapter')
+ .children('button').removeAttr('aria-current');
+ $clickedItem.addClass('able-current-chapter')
+ .children('button').attr('aria-current','true');
+ // Need to updateChapter before seeking to it
+ // Otherwise seekBar is redrawn with wrong chapterDuration and/or chapterTime
+ thisObj.updateChapter(time);
+ thisObj.seekTo(time);
+ }
+ };
+ $chapterButton.on('click',getClickFunction(cues[thisChapter].start)); // works with Enter too
+ $chapterButton.on('focus',function() {
+ $(this).closest('ul').find('li').removeClass('able-focus');
+ $(this).closest('li').addClass('able-focus');
+ });
+ $chapterItem.on('hover',function() {
+ $(this).closest('ul').find('li').removeClass('able-focus');
+ $(this).addClass('able-focus');
+ });
+ $chapterItem.on('mouseleave',function() {
+ $(this).removeClass('able-focus');
+ });
+ $chapterButton.on('blur',function() {
+ $(this).closest('li').removeClass('able-focus');
+ });
+
+ // put it all together
+ $chapterItem.append($chapterButton);
+ $chaptersList.append($chapterItem);
+ if (this.defaultChapter === cues[thisChapter].id) {
+ $chapterButton.attr('aria-current','true').parent('li').addClass('able-current-chapter');
+ this.currentChapter = cues[thisChapter];
+ hasDefault = true;
+ }
+ }
+ if (!hasDefault) {
+ // select the first chapter
+ this.currentChapter = cues[0];
+ $chaptersList.find('button').first().attr('aria-current','true')
+ .parent('li').addClass('able-current-chapter');
+ }
+ this.$chaptersNav.html($chaptersList);
+ }
+ return false;
+ };
+
+ AblePlayer.prototype.seekToChapter = function(chapterId) {
+
+ // step through chapters looking for matching ID
+ var i=0;
+ while (i < this.selectedChapters.cues.length) {
+ if (this.selectedChapters.cues[i].id == chapterId) {
+ // found the target chapter! Seek to it
+ this.seekTo(this.selectedChapters.cues[i].start);
+ this.updateChapter(this.selectedChapters.cues[i].start);
+ break;
+ }
+ i++;
+ }
+ };
+
+ AblePlayer.prototype.updateChapter = function (now) {
+
+ // as time-synced chapters change during playback, track changes in current chapter
+ if (typeof this.selectedChapters === 'undefined') {
+ return;
+ }
+
+ var chapters, i, thisChapterIndex;
+
+ chapters = this.selectedChapters.cues;
+ for (i = 0; i < chapters.length; i++) {
+ if ((chapters[i].start <= now) && (chapters[i].end > now)) {
+ thisChapterIndex = i;
+ break;
+ }
+ }
+ if (typeof thisChapterIndex !== 'undefined') {
+ if (this.currentChapter !== chapters[thisChapterIndex]) {
+ // this is a new chapter
+ this.currentChapter = chapters[thisChapterIndex];
+ if (this.useChapterTimes) {
+ this.chapterDuration = this.getChapterDuration();
+ this.seekIntervalCalculated = false; // will be recalculated in setSeekInterval()
+ }
+ if (typeof this.$chaptersDiv !== 'undefined') {
+ // chapters are listed in an external container
+ this.$chaptersDiv.find('ul').find('li')
+ .removeClass('able-current-chapter')
+ .children('button').removeAttr('aria-current');
+ this.$chaptersDiv.find('ul').find('li').eq(thisChapterIndex)
+ .addClass('able-current-chapter')
+ .children('button').attr('aria-current','true');
+ }
+ }
+ }
+ };
+
+ AblePlayer.prototype.getChapterDuration = function () {
+
+ // called if this.seekbarScope === 'chapter'
+ // get duration of the current chapter
+
+ var lastChapterIndex, chapterEnd;
+
+ if (typeof this.currentChapter === 'undefined') {
+ return 0;
+ }
+ if (typeof this.duration === 'undefined') {
+ return 0;
+ }
+ lastChapterIndex = this.selectedChapters.cues.length-1;
+ if (this.selectedChapters.cues[lastChapterIndex] == this.currentChapter) {
+ // this is the last chapter
+ if (this.currentChapter.end !== this.duration) {
+ // chapter ends before or after video ends, adjust chapter end to match video end
+ chapterEnd = this.duration;
+ this.currentChapter.end = this.duration;
+ } else {
+ chapterEnd = this.currentChapter.end;
+ }
+ } else { // this is not the last chapter
+ chapterEnd = this.currentChapter.end;
+ }
+ return chapterEnd - this.currentChapter.start;
+ };
+
+ AblePlayer.prototype.getChapterElapsed = function () {
+ // called if this.seekbarScope === 'chapter'
+ // get current elapsed time, relative to the current chapter duration
+
+ if (typeof this.currentChapter === 'undefined') {
+ return 0;
+ }
+
+ if (this.elapsed > this.currentChapter.start) {
+ return this.elapsed - this.currentChapter.start;
+ } else {
+ return 0;
+ }
+ };
+
+ AblePlayer.prototype.convertChapterTimeToVideoTime = function (chapterTime) {
+
+ // chapterTime is the time within the current chapter
+ // return the same time, relative to the entire video
+ if (typeof this.currentChapter !== 'undefined') {
+ var newTime = this.currentChapter.start + chapterTime;
+ if (newTime > this.currentChapter.end) {
+ return this.currentChapter.end;
+ } else {
+ return newTime;
+ }
+ } else {
+ return chapterTime;
+ }
+ };
+
+ AblePlayer.prototype.getChapterClickFunction = function (time) {
+
+ // Returns the function used when a chapter is clicked in the chapters menu.
+ var thisObj = this;
+ return function () {
+ thisObj.seekTrigger = 'chapter';
+ thisObj.seekTo(time);
+ // stopgap to prevent spacebar in Firefox from reopening popup
+ // immediately after closing it (used in handleChapters())
+ thisObj.hidingPopup = true;
+ thisObj.chaptersPopup.hide();
+ // Ensure stopgap gets cancelled if handleChapters() isn't called
+ // e.g., if user triggered button with Enter or mouse click, not spacebar
+ setTimeout(function() {
+ thisObj.hidingPopup = false;
+ }, 100);
+ thisObj.$chaptersButton.trigger('focus');
+ }
+ };
- return validate.postProcessVttContent(sanitizedVttContent, vttContent);
- },
- isProtocolSafe: function (url) {
- try {
- const parsedUrl = new URL(url, window.location.origin);
- return ["http:", "https:"].includes(parsedUrl.protocol);
- } catch (e) {
- return false;
- }
- },
-};
+ }
-if (typeof module !== "undefined" && module.exports) {
- module.exports = validate;
-}
+ function addControlFunctions(AblePlayer) {
+
+ AblePlayer.prototype.seekTo = function (newTime) {
+
+ var thisObj = this;
+
+ // define variables to be used for analytics
+ // e.g., to measure the extent to which users seek back and forward
+ this.seekFromTime = this.media.currentTime;
+ this.seekToTime = newTime;
+
+ this.seeking = true;
+ this.liveUpdatePending = true;
+
+ if (this.speakingDescription) {
+ this.synth.cancel();
+ }
+
+ this.syncSignVideo( {'time' : this.startTime } );
+
+ if (this.player === 'html5') {
+ var seekable;
+
+ this.startTime = newTime;
+ // Check HTML5 media "seekable" property to be sure media is seekable to startTime
+ seekable = this.media.seekable;
+ if (seekable.length > 0 && this.startTime >= seekable.start(0) && this.startTime <= seekable.end(0)) {
+ // ok to seek to startTime
+ // canplaythrough will be triggered when seeking is complete
+ // this.seeking will be set to false at that point
+ this.media.currentTime = this.startTime;
+ this.seekStatus = 'complete';
+ this.syncSignVideo( { 'time' : this.startTime } );
+ }
+ } else if (this.player === 'youtube') {
+ this.youTubePlayer.seekTo(newTime,true);
+ if (newTime > 0) {
+ if (typeof this.$posterImg !== 'undefined') {
+ this.$posterImg.hide();
+ }
+ }
+ this.syncSignVideo( {'time' : newTime } );
+ } else if (this.player === 'vimeo') {
+ this.vimeoPlayer.setCurrentTime(newTime).then(function() {
+ // seek finished.
+ // successful completion also fires a 'seeked' event (see event.js)
+ thisObj.elapsed = newTime;
+ thisObj.refreshControls('timeline');
+ });
+ }
+ this.refreshControls('timeline');
+ };
+
+ AblePlayer.prototype.getMediaTimes = function (duration, elapsed) {
+
+ // Returns an array with keys 'duration' and 'elapsed'
+ // Vars passed to this function come courtesy of select Vimeo events
+ // Use those if they're available.
+ // Otherwise, will need to call the relevant media API
+ // This function should only be called from onMediaUpdateTime()
+ // If duration and elapsed are needed other times, use this.duration and this.elapsed
+
+ // both values are expressed in seconds, and all player APIs are similar:
+ // they return a value that is rounded to the nearest second before playback begins,
+ // then to the nearest thousandth of a second after playback begins
+ // With HTML5 media API, some browsers are more precise (e.g., Firefox rounds to 6 decimal points)
+ // but inconsistent (values with 9 decimal points have been sporadically observed in Safari)
+ // For standardization, values are rounded to 6 decimal points before they're returned
+
+ var deferred, promise, thisObj, mediaTimes;
+ mediaTimes = {};
+
+ deferred = new this.defer();
+ promise = deferred.promise();
+ thisObj = this;
+ if (typeof duration !== 'undefined' && typeof elapsed !== 'undefined') {
+ mediaTimes['duration'] = duration;
+ mediaTimes['elapsed'] = elapsed;
+ deferred.resolve(mediaTimes);
+ } else {
+ this.getDuration().then(function(duration) {
+ mediaTimes['duration'] = thisObj.roundDown(duration,6);
+ thisObj.getElapsed().then(function(elapsed) {
+ mediaTimes['elapsed'] = thisObj.roundDown(elapsed,6);
+ deferred.resolve(mediaTimes);
+ });
+ });
+ }
+ return promise;
+ };
+
+ AblePlayer.prototype.getDuration = function () {
+
+ // returns duration of the current media, expressed in seconds
+ // function is called by getMediaTimes, and return value is sanitized there
+ var deferred, promise;
+
+ deferred = new this.defer();
+ promise = deferred.promise();
+
+ if (this.player === 'vimeo') {
+ if (this.vimeoPlayer) {
+ this.vimeoPlayer.getDuration().then(function(duration) {
+ if (duration === undefined || isNaN(duration) || duration === -1) {
+ deferred.resolve(0);
+ } else {
+ deferred.resolve(duration);
+ }
+ });
+ } else { // vimeoPlayer hasn't been initialized yet.
+ deferred.resolve(0);
+ }
+ } else {
+ var duration;
+ if (this.player === 'html5') {
+ duration = this.media.duration;
+ } else if (this.player === 'youtube') {
+ if (this.youTubePlayerReady) {
+ if (this.duration > 0) {
+ // duration was already retrieved while checking for captions
+ duration = this.duration;
+ } else {
+ duration = this.youTubePlayer.getDuration();
+ }
+ } else { // the YouTube player hasn't initialized yet
+ duration = 0;
+ }
+ }
+ if (duration === undefined || isNaN(duration) || duration === -1) {
+ deferred.resolve(0);
+ } else {
+ deferred.resolve(duration);
+ }
+ }
+ return promise;
+ };
+
+ AblePlayer.prototype.getElapsed = function () {
+
+ // returns elapsed time of the current media, expressed in seconds
+ // function is called by getMediaTimes, and return value is sanitized there
+
+ var deferred, promise;
+
+ deferred = new this.defer();
+ promise = deferred.promise();
+
+ if (this.player === 'vimeo') {
+ if (this.vimeoPlayer) {
+ this.vimeoPlayer.getCurrentTime().then(function(elapsed) {
+ if (elapsed === undefined || isNaN(elapsed) || elapsed === -1) {
+ deferred.resolve(0);
+ } else {
+ deferred.resolve(elapsed);
+ }
+ });
+ } else { // vimeoPlayer hasn't been initialized yet.
+ deferred.resolve(0);
+ }
+ } else {
+ var elapsed;
+ if (this.player === 'html5') {
+ elapsed = this.media.currentTime;
+ } else if (this.player === 'youtube') {
+ if (this.youTubePlayerReady) {
+ elapsed = this.youTubePlayer.getCurrentTime();
+ } else { // the YouTube player hasn't initialized yet
+ elapsed = 0;
+ }
+ }
+ if (elapsed === undefined || isNaN(elapsed) || elapsed === -1) {
+ deferred.resolve(0);
+ } else {
+ deferred.resolve(elapsed);
+ }
+ }
+ return promise;
+ };
+
+ AblePlayer.prototype.getPlayerState = function () {
+
+ // Returns one of the following states:
+ // - 'stopped' - Not yet played for the first time, or otherwise reset to unplayed.
+ // - 'ended' - Finished playing.
+ // - 'paused' - Not playing, but not stopped or ended.
+ // - 'buffering' - Momentarily paused to load, but will resume once data is loaded.
+ // - 'playing' - Currently playing.
+
+ var deferred, promise, thisObj;
+ deferred = new this.defer();
+ promise = deferred.promise();
+ thisObj = this;
+
+ if (this.player === 'html5') {
+ if (this.media.ended) {
+ deferred.resolve('ended');
+ } else if (this.media.paused) {
+ deferred.resolve('paused');
+ } else if (this.media.readyState !== 4) {
+ deferred.resolve('buffering');
+ } else {
+ deferred.resolve('playing');
+ }
+ } else if (this.player === 'youtube' && this.youTubePlayerReady) {
+ var state = this.youTubePlayer.getPlayerState();
+ if (state === -1 || state === 5) {
+ deferred.resolve('stopped');
+ } else if (state === 0) {
+ deferred.resolve('ended');
+ } else if (state === 1) {
+ deferred.resolve('playing');
+ } else if (state === 2) {
+ deferred.resolve('paused');
+ } else if (state === 3) {
+ deferred.resolve('buffering');
+ }
+ } else if (this.player === 'vimeo' && this.vimeoPlayer) {
+ // curiously, Vimeo's API has no getPlaying(), getBuffering(), or getState() methods
+ // so maybe if it's neither paused nor ended, it must be playing???
+ this.vimeoPlayer.getPaused().then(function(paused) {
+ if (paused) {
+ deferred.resolve('paused');
+ } else {
+ thisObj.vimeoPlayer.getEnded().then(function(ended) {
+ if (ended) {
+ deferred.resolve('ended');
+ } else {
+ deferred.resolve('playing');
+ }
+ });
+ }
+ });
+ }
+ return promise;
+ };
+
+ AblePlayer.prototype.isPlaybackRateSupported = function () {
+
+ if (this.player === 'html5') {
+ return (this.media.playbackRate) ? true : false;
+ } else if (this.player === 'youtube') {
+ // Youtube supports varying playback rates per video.
+ // Only expose controls if more than one playback rate is available.
+ if (this.youTubePlayerReady) {
+ return (this.youTubePlayer.getAvailablePlaybackRates().length > 1) ? true : false;
+ } else {
+ return false;
+ }
+ } else if (this.player === 'vimeo') {
+ // since this takes longer to determine, it was set previously in initVimeoPlayer()
+ return this.vimeoSupportsPlaybackRateChange;
+ }
+ };
+
+ AblePlayer.prototype.setPlaybackRate = function (rate) {
+
+ rate = Math.max(0.5, rate);
+
+ if (this.hasClosedDesc && this.descMethod === 'text') {
+ // keep speech rate in sync with playback rate even if descOn is false
+ this.syncSpeechToPlaybackRate(rate);
+ }
+
+ this.syncSignVideo( {'rate' : rate } );
+
+ if (this.player === 'html5') {
+ this.media.playbackRate = rate;
+ } else if (this.player === 'youtube') {
+ this.youTubePlayer.setPlaybackRate(rate);
+ } else if (this.player === 'vimeo') {
+ this.vimeoPlayer.setPlaybackRate(rate);
+ }
+ this.syncSignVideo( { 'rate' : rate } );
+ this.playbackRate = rate;
+ this.$speed.text( this.translate( 'speed', 'Speed' ) + ': ' + rate.toFixed(2).toString() + 'x');
+ };
+
+ AblePlayer.prototype.getPlaybackRate = function () {
+
+ if (this.player === 'html5') {
+ return this.media.playbackRate;
+ } else if (this.player === 'youtube' && (this.youTubePlayerReady)) {
+ return this.youTubePlayer.getPlaybackRate();
+ }
+ };
+
+ AblePlayer.prototype.isPaused = function () {
+
+ // Note there are three player states that count as paused in this sense,
+ // and one of them is named 'paused'.
+ // A better name would be 'isCurrentlyNotPlayingOrBuffering'
+
+ if (this.player === 'vimeo') {
+ // just rely on value of this.playing
+ return (this.playing) ? false : true;
+ } else {
+ this.getPlayerState().then(function(state) {
+ // if any of the following is true, consider the media 'paused'
+ return state === 'paused' || state === 'stopped' || state === 'ended';
+ });
+ }
+ };
+
+ AblePlayer.prototype.syncSignVideo = function(options) {
+ if (this.hasSignLanguage && ( this.signVideo || this.signYoutube ) ) {
+ if (options && typeof options.time !== 'undefined') {
+ if ( this.signVideo ) {
+ this.signVideo.currentTime = options.time;
+ } else {
+ this.youTubeSignPlayer.seekTo(options.time,true);
+ }
+ }
+ if (options && typeof options.rate !== 'undefined') {
+ if ( this.signVideo ) {
+ this.signVideo.playbackRate = options.rate;
+ } else {
+ this.youTubeSignPlayer.setPlaybackRate(options.rate);
+ }
+ }
+ if (options && typeof options.pause !== 'undefined') {
+ if ( this.signVideo ) {
+ this.signVideo.pause(true);
+ } else {
+ this.youTubeSignPlayer.pauseVideo();
+ }
+ }
+ if (options && typeof options.play !== 'undefined') {
+ if ( this.signVideo ) {
+ this.signVideo.play(true);
+ } else {
+ this.youTubeSignPlayer.playVideo();
+ }
+ }
+ if (options && typeof options.volume !== 'undefined') {
+ if ( this.signVideo ) {
+ this.signVideo.volume = 0;
+ }
+ }
+ }
+ };
+
+ AblePlayer.prototype.pauseMedia = function () {
+
+ this.syncSignVideo( { 'pause' : true } );
+
+ if (this.player === 'html5') {
+ this.media.pause(true);
+ } else if (this.player === 'youtube') {
+ this.youTubePlayer.pauseVideo();
+ } else if (this.player === 'vimeo') {
+ this.vimeoPlayer.pause();
+ }
+ };
+
+ AblePlayer.prototype.playMedia = function () {
+
+ this.syncSignVideo( { 'play' : true } );
+
+ if (this.player === 'html5') {
+ this.media.play(true);
+ } else if (this.player === 'youtube') {
+
+ this.youTubePlayer.playVideo();
+ if (typeof this.$posterImg !== 'undefined') {
+ this.$posterImg.hide();
+ }
+ this.stoppingYouTube = false;
+ } else if (this.player === 'vimeo') {
+ this.vimeoPlayer.play();
+ }
+ this.startedPlaying = true;
+ if (this.hideControls) {
+ // wait briefly after playback begins, then hide controls
+ this.hidingControls = true;
+ this.invokeHideControlsTimeout();
+ }
+ };
+
+ AblePlayer.prototype.fadeControls = function(direction) {
+
+ // Visibly fade controls without hiding them from screen reader users
+ // direction is either 'out' or 'in'
+
+ // After the player fades, it's replaced by an empty space
+ // Would be better if the video and captions expanded to fill the void
+ // replace JS animation with CSS animation in 12/2025.
+
+ if (direction == 'out') {
+ // get the original height of two key components:
+ this.$playerDiv.addClass( 'fade-out' ).removeClass( 'fade-in' );
+ } else if (direction == 'in') {
+ this.$playerDiv.addClass( 'fade-in' ).removeClass( 'fade-out' );
+ }
+ };
+
+ AblePlayer.prototype.invokeHideControlsTimeout = function () {
+
+ // invoke timeout for waiting a few seconds after a mouse move or key down
+ // before hiding controls again
+ var thisObj = this;
+ this.hideControlsTimeout = window.setTimeout(function() {
+ if (typeof thisObj.playing !== 'undefined' && thisObj.playing === true && thisObj.hideControls) {
+ thisObj.fadeControls('out');
+ thisObj.controlsHidden = true;
+ }
+ },5000);
+ this.hideControlsTimeoutStatus = 'active';
+ };
+
+ AblePlayer.prototype.refreshControls = function(context = 'init', duration, elapsed) {
+
+ // context is one of the following:
+ // 'init' - initial build (or subsequent change that requires full rebuild)
+ // 'timeline' - a change may effect time-related controls
+ // 'captions' - a change may effect caption-related controls
+ // 'descriptions' - a change may effect description-related controls
+ // 'transcript' - a change may effect the transcript window or button
+ // 'fullscreen' - a change has been triggered by full screen toggle
+ // 'playpause' - a change triggered by either a 'play' or 'pause' event
+
+ // NOTE: context is not currently supported.
+ // The steps in this function have too many complex interdependencies
+ // The gains in efficiency are offset by the possibility of introducing bugs
+ // For now, executing everything
+ context = 'init';
+
+ // duration and elapsed are passed from callback functions of Vimeo API events
+ // duration is expressed as sss.xxx
+ // elapsed is expressed as sss.xxx
+
+ var thisObj, textByState, timestamp, captionsCount, newTop, statusBarWidthBreakpoint;
+
+ thisObj = this;
+ // wait until new source has loaded before refreshing controls
+ // some critical events won't fire until playback of new media starts
+ if ( this.swappingSrc && this.playing ) {
+ return;
+ }
+
+ if ( context === 'timeline' || context === 'init' ) {
+ // Update timeline controls.
+ var lastChapterIndex, displayElapsed, updateLive, widthUsed,
+ leftControls, rightControls, seekbarWidth, buffered;
+ // all timeline-related functionality requires duration
+ if (typeof this.duration === 'undefined') {
+ // wait until duration is known before proceeding with refresh
+ return;
+ }
+ if (this.useChapterTimes) {
+ this.chapterDuration = this.getChapterDuration();
+ this.chapterElapsed = this.getChapterElapsed();
+ }
+
+ if ( !this.useFixedSeekInterval && !this.seekIntervalCalculated && this.duration > 0) {
+ // couldn't calculate seekInterval previously; try again.
+ this.setSeekInterval();
+ }
+
+ if (this.seekBar) {
+ if (this.useChapterTimes) {
+ lastChapterIndex = this.selectedChapters.cues.length-1;
+ if (this.selectedChapters.cues[lastChapterIndex] == this.currentChapter) {
+ // this is the last chapter
+ if (this.currentChapter.end !== this.duration) {
+ // chapter ends before or after video ends
+ // need to adjust seekbar duration to match video end
+ this.seekBar.setDuration(this.duration - this.currentChapter.start);
+ } else {
+ this.seekBar.setDuration(this.chapterDuration);
+ }
+ } else {
+ // this is not the last chapter
+ this.seekBar.setDuration(this.chapterDuration);
+ }
+ } else if ( !(this.duration === undefined || isNaN(this.duration) || this.duration === -1) ) {
+ this.seekBar.setDuration(this.duration);
+ }
+ if (!(this.seekBar.tracking)) {
+ // Only update the aria live region if we have an update pending
+ // (from a seek button control) or if the seekBar has focus.
+ // We use document.activeElement instead of $(':focus') due to a strange bug:
+ // When the seekHead element is focused, .is(':focus') is failing and $(':focus') is returning an undefined element.
+ updateLive = this.liveUpdatePending || this.seekBar.seekHead.is($(document.activeElement));
+ this.liveUpdatePending = false;
+ if (this.useChapterTimes) {
+ this.seekBar.setPosition(this.chapterElapsed, updateLive);
+ } else {
+ this.seekBar.setPosition(this.elapsed, updateLive);
+ }
+ }
+
+ // When seeking, display the seek bar time instead of the actual elapsed time.
+ if (this.seekBar.tracking) {
+ displayElapsed = this.seekBar.lastTrackPosition;
+ } else {
+ displayElapsed = ( this.useChapterTimes ) ? this.chapterElapsed : this.elapsed;
+ }
+ }
+ // update elapsed & duration
+ if (typeof this.$durationContainer !== 'undefined') {
+ if (this.useChapterTimes) {
+ this.$durationContainer.text( this.formatSecondsAsColonTime(this.chapterDuration));
+ } else {
+ this.$durationContainer.text( this.formatSecondsAsColonTime(this.duration));
+ }
+ }
+ if (typeof this.$elapsedTimeContainer !== 'undefined') {
+ this.$elapsedTimeContainer.text(this.formatSecondsAsColonTime(displayElapsed));
+ }
+
+ if (this.skin === 'legacy') {
+ // Update seekbar width.
+ // To do this, we need to calculate the width of all buttons surrounding it.
+ if (this.seekBar) {
+ let controlWrapper = this.seekBar.wrapperDiv.parent().parent();
+ leftControls = this.seekBar.wrapperDiv.parent().prev('div.able-left-controls');
+ rightControls = leftControls.next('div.able-right-controls');
+ widthUsed = leftControls.outerWidth(true);
+ rightControls.children().each(function () {
+ if ($(this).attr('role')=='button') {
+ widthUsed += $(this).outerWidth(true) + 5;
+ }
+ });
+ if (this.fullscreen) {
+ seekbarWidth = $(window).width() - widthUsed;
+ } else {
+ // seekbar is wide enough to fill the remaining space
+ // include a 10px buffer to account for minor browser differences or custom styles.
+ seekbarWidth = controlWrapper.width() - widthUsed - 10;
+ }
+ // Sometimes some minor fluctuations based on browser weirdness, so set a threshold.
+ if (Math.abs(seekbarWidth - this.seekBar.getWidth()) > 5) {
+ this.seekBar.setWidth(seekbarWidth);
+ }
+ }
+ }
+
+ // Update buffering progress.
+ // TODO: Currently only using the first HTML5 buffered interval,
+ // but this fails sometimes when buffering is split into two or more intervals.
+ if (this.player === 'html5' && this.media.buffered.length > 0) {
+ buffered = this.media.buffered.end(0);
+ if (this.useChapterTimes) {
+ if (buffered > this.chapterDuration) {
+ buffered = this.chapterDuration;
+ }
+ if (this.seekBar) {
+ this.seekBar.setBuffered(buffered / this.chapterDuration);
+ }
+ } else if ( this.seekBar && !isNaN(buffered) ) {
+ this.seekBar.setBuffered(buffered / duration);
+ }
+ } else if (this.player === 'youtube' && this.seekBar && this.youTubePlayerReady ) {
+ this.seekBar.setBuffered(this.youTubePlayer.getVideoLoadedFraction());
+ } else if (this.player === 'vimeo') ;
+ }
+
+ if (context === 'descriptions' || context == 'init') {
+ if (this.$descButton) {
+ this.toggleButtonState(
+ this.$descButton,
+ this.descOn,
+ this.translate( 'turnOffDescriptions', 'Turn off descriptions' ),
+ this.translate( 'turnOnDescriptions', 'Turn on descriptions' ),
+ );
+ }
+ }
+
+ if (context === 'captions' || context == 'init') {
+
+ if (this.$ccButton) {
+
+ captionsCount = this.captions.length;
+ if (captionsCount > 1) {
+ this.$ccButton.attr({
+ 'aria-haspopup': 'true',
+ 'aria-controls': this.mediaId + '-captions-menu'
+ });
+ }
+ var ariaLabelOn = ( captionsCount > 1 ) ? this.translate( 'captions', 'Captions' ) : this.translate( 'showCaptions', 'Show captions' );
+ var ariaLabelOff = ( captionsCount > 1 ) ? this.translate( 'captions', 'Captions' ) : this.translate( 'hideCaptions', 'Hide captions' );
+ var ariaPressed = ( captionsCount > 1 ) ? true : false;
+
+ this.toggleButtonState(
+ this.$ccButton,
+ this.captionsOn,
+ ariaLabelOff,
+ ariaLabelOn,
+ ariaPressed
+ );
+ }
+ }
+
+ if (context === 'fullscreen' || context == 'init'){
+ if (this.$fullscreenButton) {
+ if (!this.fullscreen) {
+ this.$fullscreenButton.attr( 'aria-label', this.translate( 'enterFullScreen', 'Enter full screen' ) );
+ this.getIcon( this.$fullscreenButton, 'fullscreen-expand' );
+ } else {
+ this.$fullscreenButton.attr('aria-label', this.translate( 'exitFullScreen', 'Exit full screen' ) );
+ this.getIcon( this.$fullscreenButton, 'fullscreen-collapse' );
+ }
+ }
+ }
+ if (context === 'playpause' || context == 'init'){
+ if (typeof this.$bigPlayButton !== 'undefined' && typeof this.seekBar !== 'undefined') {
+ // Choose show/hide for big play button and adjust position.
+ if (this.paused && !this.seekBar.tracking) {
+ if (!this.hideBigPlayButton) {
+ this.$bigPlayButton.show();
+ this.$bigPlayButton.attr('aria-hidden', 'false');
+ }
+ } else {
+ this.$bigPlayButton.hide();
+ this.$bigPlayButton.attr('aria-hidden', 'true');
+ }
+ }
+ }
+
+ if (context === 'transcript' || context == 'init'){
+
+ if (this.transcriptType) {
+ // Sync checkbox and autoScrollTranscript with user preference
+ if (this.prefAutoScrollTranscript === 1) {
+ this.autoScrollTranscript = true;
+ this.$autoScrollTranscriptCheckbox.prop('checked',true);
+ } else {
+ this.autoScrollTranscript = false;
+ this.$autoScrollTranscriptCheckbox.prop('checked',false);
+ }
+
+ // If transcript locked, scroll transcript to current highlight location.
+ if (this.autoScrollTranscript && this.currentHighlight) {
+ newTop = Math.floor(this.$transcriptDiv.scrollTop() +
+ $(this.currentHighlight).position().top -
+ (this.$transcriptDiv.height() / 2) +
+ ($(this.currentHighlight).height() / 2));
+ if (newTop !== Math.floor(this.$transcriptDiv.scrollTop())) {
+ // Set a flag to ignore the coming scroll event.
+ // there's no other way I know of to differentiate programmatic and user-initiated scroll events.
+ this.scrollingTranscript = true;
+ // only scroll once after moving a highlight
+ if (this.movingHighlight) {
+ this.$transcriptDiv.scrollTop(newTop);
+ this.movingHighlight = false;
+ }
+ }
+ }
+ }
+ }
+
+ if (context === 'init') {
+
+ if (this.$chaptersButton) {
+ this.$chaptersButton.attr({
+ 'aria-label': this.translate( 'chapters', 'Chapters' ),
+ 'aria-haspopup': 'true',
+ 'aria-controls': this.mediaId + '-chapters-menu'
+ });
+ }
+ }
+
+ if (context === 'timeline' || context === 'playpause' || context === 'init') {
+
+ // update status
+ textByState = {
+ 'stopped': this.translate( 'statusStopped', 'Stopped' ),
+ 'paused': this.translate( 'statusPaused', 'Paused' ),
+ 'playing': this.translate( 'statusPlaying', 'Playing' ),
+ 'buffering': this.translate( 'statusBuffering', 'Buffering' ),
+ 'ended': this.translate( 'statusEnd', 'End of track' )
+ };
+
+ if (this.stoppingYouTube) {
+ // stoppingYouTube is true temporarily while video is paused and seeking to 0
+ // See notes in handleRestart()
+ // this.stoppingYouTube will be reset when seek to 0 is finished (in event.js > onMediaUpdateTime())
+ if (this.$status.text() !== this.translate( 'statusStopped', 'Stopped' ) ) {
+ this.$status.text( this.translate( 'statusStopped', 'Stopped' ) );
+ }
+ this.getIcon( this.$playpauseButton, 'play' );
+ } else if (typeof this.$status !== 'undefined' && typeof this.seekBar !== 'undefined') {
+ // Update the text only if it's changed since it has role="alert";
+ // also don't update while tracking, since this may Pause/Play the player but we don't want to send a Pause/Play update.
+ this.getPlayerState().then(function(currentState) {
+ if (thisObj.$status.text() !== textByState[currentState] && !thisObj.seekBar.tracking) {
+ // Debounce updates; only update after status has stayed steadily different for a while
+ // "A while" is defined differently depending on context
+ if (thisObj.swappingSrc) {
+ // this is where most of the chatter occurs (e.g., playing, paused, buffering, playing),
+ // so set a longer wait time before writing a status message
+ if (!thisObj.debouncingStatus) {
+ thisObj.statusMessageThreshold = 2000; // in ms (2 seconds)
+ }
+ } else if (!thisObj.debouncingStatus) {
+ // for all other contexts (e.g., users clicks Play/Pause)
+ // user should receive more rapid feedback
+ thisObj.statusMessageThreshold = 250; // in ms
+ }
+ timestamp = (new Date()).getTime();
+ if (!thisObj.statusDebounceStart) {
+ thisObj.statusDebounceStart = timestamp;
+ // Call refreshControls() again after allotted time has passed
+ thisObj.debouncingStatus = true;
+ thisObj.statusTimeout = setTimeout(function () {
+ thisObj.debouncingStatus = false;
+ thisObj.refreshControls(context);
+ }, thisObj.statusMessageThreshold);
+ } else if ((timestamp - thisObj.statusDebounceStart) > thisObj.statusMessageThreshold) {
+ thisObj.$status.text(textByState[currentState]);
+ thisObj.statusDebounceStart = null;
+ clearTimeout(thisObj.statusTimeout);
+ thisObj.statusTimeout = null;
+ }
+ } else {
+ thisObj.statusDebounceStart = null;
+ thisObj.debouncingStatus = false;
+ clearTimeout(thisObj.statusTimeout);
+ thisObj.statusTimeout = null;
+ }
+ // Don't change play/pause button display while using the seek bar (or if YouTube stopped)
+ if (!thisObj.seekBar.tracking && !thisObj.stoppingYouTube) {
+ if (currentState === 'paused' || currentState === 'stopped' || currentState === 'ended') {
+ thisObj.$playpauseButton.attr('aria-label', thisObj.translate( 'play', 'Play' ) );
+ thisObj.getIcon( thisObj.$playpauseButton, 'play' );
+ } else {
+ thisObj.$playpauseButton.attr('aria-label', thisObj.translate( 'pause', 'Pause' ) );
+ thisObj.getIcon( thisObj.$playpauseButton, 'pause' );
+ }
+ }
+ });
+ }
+ }
+
+ // Show/hide status bar content conditionally
+ if (!this.fullscreen) {
+ statusBarWidthBreakpoint = 300;
+ if (this.$statusBarDiv.width() < statusBarWidthBreakpoint) {
+ // Player is too small for a speed span
+ this.$statusBarDiv.find('span.able-speed').hide();
+ this.hidingSpeed = true;
+ } else {
+ if (this.hidingSpeed) {
+ this.$statusBarDiv.find('span.able-speed').show();
+ this.hidingSpeed = false;
+ }
+ }
+ }
+
+ };
+
+ AblePlayer.prototype.handlePlay = function(e) {
+ if (this.paused) {
+ // user clicked play
+ this.okToPlay = true;
+ this.playMedia();
+ if (this.synth.paused) {
+ // media was paused while description was speaking
+ // resume utterance
+ this.synth.resume();
+ }
+ } else {
+ // user clicked pause
+ this.okToPlay = false;
+ this.pauseMedia();
+ if (this.speakingDescription) {
+ // pause the current utterance
+ // it will resume when the user presses play
+ this.synth.pause();
+ }
+ }
+ if (this.speechEnabled === null) {
+ this.initSpeech('play');
+ }
+ };
+
+ AblePlayer.prototype.handleRestart = function() {
+
+ if (this.speakingDescription) {
+ // cancel audio description
+ this.synth.cancel();
+ }
+ this.seekTo(0);
+ };
+
+ AblePlayer.prototype.handlePrevTrack = function() {
+
+ // currently on the first track
+ // wrap to bottom and play the last track
+ let newIndex = (this.playlistIndex === 0) ? this.$playlist.length - 1 : this.playlistIndex - 1;
+ this.cueingPlaylistItem = true; // stopgap to prevent multiple firings
+ this.cuePlaylistItem(newIndex);
+ };
+
+ AblePlayer.prototype.handleNextTrack = function() {
+
+ // currently on the last track
+ // wrap to top and play the first track
+ let newIndex = (this.playlistIndex === this.$playlist.length - 1) ? 0 : this.playlistIndex + 1;
+ this.cueingPlaylistItem = true; // stopgap to prevent multiple firings
+ this.cuePlaylistItem(newIndex);
+ };
+
+ AblePlayer.prototype.handleRewind = function() {
+
+ var targetTime;
+
+ targetTime = this.elapsed - this.seekInterval;
+ if (this.useChapterTimes && (targetTime < this.currentChapter.start)) {
+ targetTime = this.currentChapter.start;
+ } else if (targetTime < 0) {
+ targetTime = 0;
+ }
+ this.seekTo(targetTime);
+ };
+
+ AblePlayer.prototype.handleFastForward = function() {
+
+ var targetTime, lastChapterIndex;
+
+ lastChapterIndex = this.chapters.length-1;
+ targetTime = this.elapsed + this.seekInterval;
+ if (this.useChapterTimes) {
+ if (this.chapters[lastChapterIndex] == this.currentChapter) {
+ // this is the last chapter
+ if (targetTime > this.duration || targetTime > this.currentChapter.end) {
+ // targetTime would exceed the end of the video (or chapter)
+ // scrub to end of whichever is earliest
+ targetTime = Math.min(this.duration, this.currentChapter.end);
+ } else if (this.duration % targetTime < this.seekInterval) {
+ // nothing left but pocket change after seeking to targetTime
+ // go ahead and seek to end of video (or chapter), whichever is earliest
+ targetTime = Math.min(this.duration, this.currentChapter.end);
+ }
+ } else {
+ // this is not the last chapter
+ if (targetTime > this.currentChapter.end) {
+ // targetTime would exceed the end of the chapter
+ // scrub exactly to end of chapter
+ targetTime = this.currentChapter.end;
+ }
+ }
+ } else {
+ // not using chapter times
+ if (targetTime > this.duration) {
+ targetTime = this.duration;
+ }
+ }
+ this.seekTo(targetTime);
+ };
+
+ AblePlayer.prototype.handleRateIncrease = function() {
+ this.changeRate(1);
+ };
+
+ AblePlayer.prototype.handleRateDecrease = function() {
+ this.changeRate(-1);
+ };
+
+ // Increases or decreases playback rate, where dir is 1 or -1 indication direction.
+ AblePlayer.prototype.changeRate = function (dir) {
+
+ var rates, currentRate, index, newRate, vimeoMin, vimeoMax;
+
+ if (this.player === 'html5') {
+ this.setPlaybackRate(this.getPlaybackRate() + (0.25 * dir));
+ } else if (this.player === 'youtube') {
+ if (this.youTubePlayerReady) {
+ rates = this.youTubePlayer.getAvailablePlaybackRates();
+ currentRate = this.getPlaybackRate();
+ index = rates.indexOf(currentRate);
+ if (index === -1) ; else {
+ index += dir;
+ // Can only increase or decrease rate if there's another rate available.
+ if (index < rates.length && index >= 0) {
+ this.setPlaybackRate(rates[index]);
+ }
+ }
+ }
+ } else if (this.player === 'vimeo') {
+ // range is 0.5 to 2
+ // increase/decrease in inrements of 0.5
+ vimeoMin = 0.5;
+ vimeoMax = 2;
+ if (dir === 1) {
+ newRate = (this.vimeoPlaybackRate + 0.5 <= vimeoMax) ? this.vimeoPlaybackRate + 0.5 : vimeoMax;
+ } else if (dir === -1) {
+ newRate = (this.vimeoPlaybackRate - 0.5 >= vimeoMin) ? this.vimeoPlaybackRate - 0.5 : vimeoMin;
+ }
+ this.setPlaybackRate(newRate);
+ }
+ };
+
+ AblePlayer.prototype.handleCaptionToggle = function() {
+
+ var thisObj = this;
+ var captions, ariaPressed;
+ if (this.hidingPopup) {
+ // stopgap to prevent spacebar in Firefox from reopening popup
+ // immediately after closing it
+ this.hidingPopup = false;
+ return false;
+ }
+
+ captions = (this.captions.length) ? this.captions : [];
+ if (captions.length === 1) {
+ // When there's only one set of captions, just do an on/off toggle.
+ if (this.captionsOn === true) {
+ // turn them off
+ this.captionsOn = false;
+ this.prefCaptions = 0;
+ ariaPressed = false;
+ this.updatePreferences('prefCaptions');
+ if (this.usingYouTubeCaptions) {
+ this.youTubePlayer.unloadModule('captions');
+ } else if (this.usingVimeoCaptions) {
+ this.vimeoPlayer.disableTextTrack();
+ } else {
+ this.$captionsWrapper.hide();
+ }
+ } else {
+ // captions are off. Turn them on.
+ this.captionsOn = true;
+ this.prefCaptions = 1;
+ ariaPressed = true;
+ this.updatePreferences('prefCaptions');
+ if (this.usingYouTubeCaptions) {
+ this.youTubePlayer.loadModule('captions');
+ } else if (this.usingVimeoCaptions) {
+ this.vimeoPlayer.enableTextTrack(this.captionLang).catch(function(error) {
+ switch (error.name) {
+ }
+ });
+ } else {
+ this.$captionsWrapper.show();
+ }
+ for (var i=0; i= 0) {
+ this.selectedDescriptions = this.descriptions[0];
+ }
+ }
+ } else {
+ // there is more than one caption track.
+ // clicking on a track is handled via caption.js > getCaptionClickFunction()
+ if (this.captionsPopup && this.captionsPopup.is(':visible')) {
+ this.captionsPopup.hide();
+ this.hidingPopup = false;
+ this.$ccButton.attr('aria-expanded', 'false');
+ this.waitThenFocus(this.$ccButton);
+ } else {
+ this.closePopups();
+ if (this.captionsPopup) {
+ this.captionsPopup.show();
+ this.$ccButton.attr('aria-expanded','true');
+
+ // Gives time to "register" expanded ccButton
+ setTimeout(function() {
+ thisObj.captionsPopup.css('top', thisObj.$ccButton.position().top - thisObj.captionsPopup.outerHeight());
+ thisObj.captionsPopup.css('left', thisObj.$ccButton.position().left);
+ // Place focus on the first button (even if another button is checked)
+ thisObj.captionsPopup.find('li').removeClass('able-focus');
+ thisObj.captionsPopup.find('li').first().trigger('focus').addClass('able-focus');
+ }, 50);
+ }
+ }
+ }
+ var ariaLabelOn = ( captions.length > 1 ) ? this.translate( 'captions', 'Captions' ) : this.translate( 'showCaptions', 'Show captions' );
+ var ariaLabelOff = ( captions.length > 1 ) ? this.translate( 'captions', 'Captions' ) : this.translate( 'hideCaptions', 'Hide captions' );
+
+ this.toggleButtonState(
+ this.$ccButton,
+ this.captionsOn,
+ ariaLabelOff,
+ ariaLabelOn,
+ ariaPressed
+ );
+ };
+
+ /**
+ * Gives enough time for DOM changes to take effect before adjusting focus.
+ * Helpful for allowing screen reading of elements whose state is intermittently changed.
+ *
+ * @param {*} $el element to focus on
+ * @param {*} timeout optional wait time in milliseconds before focus
+ */
+ AblePlayer.prototype.waitThenFocus = function($el, timeout) {
+
+ // Default wait time of 50 ms
+ var _timeout = (timeout === undefined || timeout === null) ? 50 : timeout;
+
+ setTimeout(function() {
+ $el.trigger('focus');
+ }, _timeout);
+ };
+
+ AblePlayer.prototype.handleChapters = function () {
+ if (this.hidingPopup) {
+ // stopgap to prevent spacebar in Firefox from reopening popup
+ // immediately after closing it
+ this.hidingPopup = false;
+ return false;
+ }
+ if (this.chaptersPopup.is(':visible')) {
+ this.chaptersPopup.hide();
+ this.hidingPopup = false;
+ this.$chaptersButton.attr('aria-expanded','false').trigger('focus');
+ } else {
+ this.closePopups();
+ this.chaptersPopup.show();
+ this.$chaptersButton.attr('aria-expanded','true');
+ this.chaptersPopup.css('top', this.$chaptersButton.position().top - this.chaptersPopup.outerHeight());
+ this.chaptersPopup.css('left', this.$chaptersButton.position().left);
+
+ // Highlight the current chapter, if any chapters are checked
+ // Otherwise, place focus on the first chapter
+ this.chaptersPopup.find('li').removeClass('able-focus');
+ if (this.chaptersPopup.find('li[aria-checked="true"]').length) {
+ this.chaptersPopup.find('li[aria-checked="true"]').trigger('focus').addClass('able-focus');
+ } else {
+ this.chaptersPopup.find('li').first().addClass('able-focus').attr('aria-checked','true').trigger('focus');
+ }
+ }
+ };
+
+ AblePlayer.prototype.handleDescriptionToggle = function() {
+
+ this.descOn = !this.descOn;
+ this.prefDesc = + this.descOn; // convert boolean to integer
+ this.updatePreferences('prefDesc');
+ if (typeof this.$descDiv !== 'undefined') {
+ if (!this.$descDiv.is(':hidden')) {
+ this.$descDiv.hide();
+ }
+ // NOTE: now showing $descDiv here if previously hidden
+ // that's handled elsewhere, dependent on whether there's text to show
+ }
+ this.initDescription();
+ this.refreshControls('descriptions');
+ };
+
+ AblePlayer.prototype.handlePrefsClick = function(pref) {
+
+ // NOTE: the prefs menu is positioned near the right edge of the player
+ // This assumes the Prefs button is also positioned in that vicinity
+ // (last or second-last button the right)
+
+ // NOTE: If previously unable to fully populate the Description dialog
+ // because the Web Speech API failed to getVoices()
+ // now is a good time to try again
+ // so the Description dialog can be rebuilt before the user requests it
+
+ var thisObj, prefsButtonPosition, prefsMenuRight, prefsMenuLeft;
+
+ thisObj = this;
+
+ if (this.speechEnabled === null) {
+ this.initSpeech('prefs');
+ }
+ if (this.hidingPopup) {
+ // stopgap to prevent spacebar in Firefox from reopening popup
+ // immediately after closing it
+ this.hidingPopup = false;
+ return false;
+ }
+ if (this.prefsPopup.is(':visible')) {
+ this.prefsPopup.hide();
+ this.$prefsButton.attr('aria-expanded','false');
+ // restore each menu item to original hidden state
+ this.prefsPopup.find('li').removeClass('able-focus').attr('tabindex','-1');
+ if (!this.showingPrefsDialog) {
+ this.$prefsButton.trigger('focus');
+ }
+ // wait briefly, then reset hidingPopup
+ setTimeout(function() {
+ thisObj.hidingPopup = false;
+ },100);
+ } else {
+ this.closePopups();
+ this.prefsPopup.show();
+ this.$prefsButton.attr('aria-expanded','true');
+ this.$prefsButton.trigger('focus'); // focus first on prefs button to announce expanded state
+ // give time for focus on button then adjust popup settings and focus
+ setTimeout(function() {
+ prefsButtonPosition = thisObj.$prefsButton.position();
+ prefsMenuRight = thisObj.$ableDiv.width() - 5;
+ prefsMenuLeft = prefsMenuRight - thisObj.prefsPopup.width();
+ thisObj.prefsPopup.css('top', prefsButtonPosition.top - thisObj.prefsPopup.outerHeight());
+ thisObj.prefsPopup.css('left', prefsMenuLeft);
+ // remove prior focus and set focus on first item; also change tabindex from -1 to 0
+ thisObj.prefsPopup.find('li').removeClass('able-focus').attr('tabindex','0');
+ thisObj.prefsPopup.find('li').first().trigger('focus').addClass('able-focus');
+ }, 50);
+ }
+ };
+
+ AblePlayer.prototype.handleTranscriptToggle = function () {
+ var thisObj = this;
+ var visible = this.$transcriptDiv.is(':visible');
+ if ( visible ) {
+ this.$transcriptArea.hide();
+ this.toggleButtonState( this.$transcriptButton, ! visible, this.translate( 'hideTranscript', 'Hide transcript' ), this.translate( 'showTranscript', 'Show transcript' ) );
+ this.prefTranscript = 0;
+ if ( this.transcriptType === 'popup' ) {
+ this.$transcriptButton.trigger('focus').addClass('able-focus');
+ // wait briefly before resetting stopgap var
+ // otherwise the keypress used to select 'Close' will trigger the transcript button
+ // Benchmark tests: If this is gonna happen, it typically happens in around 3ms; max 12ms
+ // Setting timeout to 100ms is a virtual guarantee of proper functionality
+ setTimeout(function() {
+ thisObj.closingTranscript = false;
+ }, 100);
+ }
+ } else {
+ if ( this.transcriptType === 'popup' ) {
+ this.positionDraggableWindow('transcript');
+ this.$transcriptArea.show();
+ // showing transcriptArea has a cascading effect of showing all content *within* transcriptArea
+ // need to re-hide the popup menu
+ this.$transcriptPopup.hide();
+ this.toggleButtonState( this.$transcriptButton, ! visible, this.translate( 'hideTranscript', 'Hide transcript' ), this.translate( 'showTranscript', 'Show transcript' ) );
+ this.prefTranscript = 1;
+ // move focus to first focusable element (window options button)
+ this.focusNotClick = true;
+ this.$transcriptArea.find('button').first().trigger('focus');
+ // wait briefly before resetting stopgap var
+ setTimeout(function() {
+ thisObj.focusNotClick = false;
+ }, 100);
+ } else {
+ this.toggleButtonState( this.$transcriptButton, ! visible, this.translate( 'hideTranscript', 'Hide transcript' ), this.translate( 'showTranscript', 'Show transcript' ) );
+ this.$transcriptArea.show();
+ }
+ }
+ this.updatePreferences('prefTranscript');
+ };
+
+ AblePlayer.prototype.handleSignToggle = function () {
+
+ var thisObj = this;
+ var visible = this.$signWindow.is(':visible');
+ if ( visible ) {
+ this.$signWindow.hide();
+ this.toggleButtonState( this.$signButton, ! visible, this.translate( 'hideSign', 'Hide sign language' ), this.translate( 'showSign', 'Show sign language' ) );
+ this.prefSign = 0;
+ this.$signButton.trigger('focus').addClass('able-focus');
+ // wait briefly before resetting stopgap var
+ // otherwise the keypress used to select 'Close' will trigger the transcript button
+ setTimeout(function() {
+ thisObj.closingSign = false;
+ }, 100);
+ } else {
+ this.positionDraggableWindow('sign');
+ this.$signWindow.show();
+ // showing signWindow has a cascading effect of showing all content *within* signWindow
+ // need to re-hide the popup menu
+ this.$signPopup.hide();
+ this.toggleButtonState( this.$signButton, ! visible, this.translate( 'hideSign', 'Hide sign language' ), this.translate( 'showSign', 'Show sign language' ) );
+ this.prefSign = 1;
+ this.focusNotClick = true;
+ this.$signWindow.find('button').first().trigger('focus');
+ // wait briefly before resetting stopgap var
+ // otherwise the keypress used to select 'Close' will trigger the transcript button
+ setTimeout(function() {
+ thisObj.focusNotClick = false;
+ }, 100);
+ }
+ this.updatePreferences('prefSign');
+ };
+
+ AblePlayer.prototype.setFullscreen = function (fullscreen) {
+
+ if (this.fullscreen == fullscreen) {
+ return;
+ }
+ var thisObj = this;
+ var $el = this.$ableWrapper;
+ var el = $el[0];
+
+ if (this.nativeFullscreenSupported()) {
+ // Note: many varying names for options for browser compatibility.
+ if (fullscreen) {
+ var scroll = {
+ x: window.pageXOffset || 0,
+ y: window.pageYOffset || 0
+ };
+ if (this.prefTranscript === 1) {
+ // transcript is on. Go ahead and reposition it
+ this.rePositionDraggableWindow("transcript");
+ }
+ if (this.prefSign === 1) {
+ // sign is on. Go ahead and reposition it
+ this.rePositionDraggableWindow("sign");
+ }
+ this.scrollPosition = scroll;
+ // Initialize fullscreen
+ if (el.requestFullscreen) {
+ el.requestFullscreen();
+ } else if (el.webkitRequestFullscreen) {
+ el.webkitRequestFullscreen();
+ }
+ this.fullscreen = true;
+ } else {
+ // Exit fullscreen
+ this.restoringAfterFullscreen = true;
+ if (document.exitFullscreen) {
+ document.exitFullscreen();
+ } else if (document.webkitExitFullscreen) {
+ document.webkitExitFullscreen();
+ } else if (document.webkitCancelFullscreen) {
+ document.webkitCancelFullscreen();
+ }
+ if (this.prefTranscript === 1) {
+ // transcript is on. Go ahead and reposition it
+ this.positionDraggableWindow("transcript");
+ }
+ if (this.prefSign === 1) {
+ // sign is on. Go ahead and reposition it
+ this.positionDraggableWindow("sign");
+ }
+ this.fullscreen = false;
+ }
+ }
+ // add event handlers for changes in fullscreen mode.
+ // Browsers natively trigger this event with the Escape key,
+ // in addition to clicking the exit fullscreen button
+ $(document).on('fullscreenchange webkitfullscreenchange', function(e) {
+ // NOTE: e.type = the specific event that fired (in case needing to control for browser-specific idiosyncrasies)
+ if (!thisObj.fullscreen) {
+ // user has just exited full screen
+ thisObj.restoringAfterFullscreen = true;
+ } else if (!thisObj.clickedFullscreenButton) {
+ // user triggered fullscreenchange without clicking fullscreen button
+ thisObj.fullscreen = false;
+ thisObj.restoringAfterFullscreen = true;
+ }
+ thisObj.resizePlayer();
+ thisObj.refreshControls('fullscreen');
+ // Reset scrollPosition after closing fullscreen.
+ if ( thisObj.scrollPosition ) {
+ scroll = thisObj.scrollPosition;
+ window.scrollTo( scroll.x, scroll.y );
+ }
+ // NOTE: The fullscreenchange (or browser-equivalent) event is triggered twice
+ // when exiting fullscreen via the "Exit fullscreen" button (only once if using Escape)
+ // Not sure why, but consequently we need to be sure thisObj.clickedFullscreenButton
+ // continues to be true through both events
+ // Could use a counter variable to control that (reset to false after the 2nd trigger)
+ // However, since I don't know why it's happening, and whether it's 100% reliable
+ // resetting clickedFullscreenButton after a timeout seems to be better approach
+ setTimeout(function() {
+ thisObj.clickedFullscreenButton = false;
+ thisObj.restoringAfterFullscreen = false;
+ },100);
+ });
+ };
+
+ AblePlayer.prototype.handleFullscreenToggle = function () {
+
+ var stillPaused = this.paused;
+ this.setFullscreen(!this.fullscreen);
+ if (stillPaused) {
+ this.pauseMedia(); // when toggling fullscreen and media is just paused, keep media paused.
+ } else if (!stillPaused) {
+ this.playMedia(); // when toggling fullscreen and media is playing, continue playing.
+ }
+ // automatically hide controller in fullscreen mode
+ // then reset back to original setting after exiting fullscreen mode
+ if (this.fullscreen) {
+ this.hideControls = true;
+ if (this.playing) {
+ // go ahead and hide the controls
+ this.fadeControls('out');
+ this.controlsHidden = true;
+ }
+ } else {
+ // exit fullscreen mode
+ this.hideControls = this.hideControlsOriginal;
+ if (!this.hideControls) { // do not hide controls
+ if (this.controlsHidden) {
+ this.fadeControls('in');
+ this.controlsHidden = false;
+ }
+ // if there's an active timeout to fade controls out again, clear it
+ if (this.hideControlsTimeoutStatus === 'active') {
+ window.clearTimeout(this.hideControlsTimeout);
+ this.hideControlsTimeoutStatus = 'clear';
+ }
+ }
+ }
+ // don't resizePlayer yet; that will be called in response to the window resize event
+ };
+
+ AblePlayer.prototype.handleTranscriptLockToggle = function (val) {
+
+ this.autoScrollTranscript = val; // val is boolean
+ this.prefAutoScrollTranscript = +val; // convert boolean to numeric 1 or 0 for cookie
+ this.updatePreferences('prefAutoScrollTranscript');
+ this.refreshControls('transcript');
+ };
+
+ AblePlayer.prototype.getIcon = function( $button, id) {
+ // Remove existing HTML before generating.
+ // iconData: [0 = svg viewbox, 1 = svg path]
+ // Font and image icon functionality was removed in 5.0.0 in favor of SVG.
+ var iconData = this.getIconData( id );
+
+ var existingIcon = $button.find( 'svg#ableplayer-' + id );
+ // Avoid repainting icon if there's no change.
+ if ( existingIcon.length > 0 ) {
+ return;
+ }
+ $button.find('svg').remove();
+
+ // Outdented for simpler diff
+ // Function to create SVG nodes.
+ function getNode(n, v) {
+ n = document.createElementNS("http://www.w3.org/2000/svg", n);
+ for (var p in v) {
+ n.setAttributeNS(null, p.replace(/[A-Z]/g, function(m) {
+ return "-" + m.toLowerCase();
+ }), v[p]);
+ }
+ return n;
+ }
+ var icon = document.createElementNS( 'http://www.w3.org/2000/svg', 'svg' );
+ icon.setAttribute( 'focusable', 'false' );
+ icon.setAttribute( 'aria-hidden', 'true');
+ icon.setAttribute( 'viewBox', iconData[0] );
+ icon.setAttribute( 'id', 'ableplayer-' + id );
+ let path = getNode( 'path', { d: iconData[1] } );
+ icon.appendChild( path );
+
+ $button.append( icon );
+ // Refresh the DOM.
+ $button.html($button.html());
+ };
+
+ AblePlayer.prototype.setText = function( $button, text ) {
+ $button.attr( 'aria-label', text );
+ };
+
+ AblePlayer.prototype.toggleButtonState = function($button, isOn, onLabel, offLabel, ariaPressed = false, ariaExpanded = false) {
+ // isOn means "the feature is being turned on".
+ let buttonOff = ( $button.hasClass( 'buttonOff' ) ) ? true : false;
+ if ( buttonOff && ! isOn || ! buttonOff && isOn ) {
+ // Only toggle state if button state does not match feature state.
+ return;
+ }
+ if (! isOn) {
+ $button.addClass('buttonOff').attr('aria-label', offLabel);
+ if ( ariaPressed ) {
+ $button.attr('aria-pressed', 'false');
+ }
+ if ( ariaExpanded ) {
+ $button.attr( 'aria-expanded', 'false' );
+ }
+ } else {
+ $button.removeClass('buttonOff').attr('aria-label', onLabel);
+ if ( ariaPressed ) {
+ $button.attr('aria-pressed', 'true');
+ }
+ if ( ariaExpanded ) {
+ $button.attr( 'aria-expanded', 'true' );
+ }
+ }
+ };
+
+ AblePlayer.prototype.showTooltip = function($tooltip) {
+
+ $tooltip.show();
+ };
+
+ AblePlayer.prototype.showAlert = function( msg, location = 'main' ) {
+
+ // location is either of the following:
+ // 'main' (default)
+ // 'screenreader (visibly hidden)
+ // 'sign' (sign language window)
+ // 'transcript' (transcript window)
+ var thisObj, $alertBox, $parentWindow;
+
+ thisObj = this;
+ $alertBox = thisObj.$alertBox;
+ $parentWindow = thisObj.$ableDiv;
+ if (location === 'transcript') {
+ $parentWindow = thisObj.$transcriptArea;
+ } else if (location === 'sign') {
+ $parentWindow = thisObj.$signWindow;
+ } else if (location === 'screenreader') {
+ $alertBox = thisObj.$srAlertBox;
+ }
+ $alertBox.find('span').text(msg);
+ $alertBox.appendTo($parentWindow);
+ $alertBox.css( {'display': 'flex'} );
+
+ if (location !== 'screenreader') {
+ setTimeout( function () {
+ $alertBox.hide();
+ }, 30000 );
+ }
+ };
+
+ AblePlayer.prototype.showedAlert = function (which) {
+
+ // returns true if the target alert has already been shown
+ // useful for throttling alerts that only need to be shown once
+ // e.g., move alerts with instructions for dragging a window
+ if (which === 'transcript') {
+ return this.showedTranscriptAlert ?? false;
+ } else if (which === 'sign') {
+ return this.showedSignAlert ?? false;
+ }
+ return false;
+ };
+
+ // Resizes all relevant player attributes.
+ AblePlayer.prototype.resizePlayer = function (width, height) {
+
+ var captionSize, newWidth, newHeight, $iframe;
+
+ if (this.mediaType === 'audio') {
+ return;
+ }
+ if (typeof width !== 'undefined' && typeof height !== 'undefined') {
+ // this is being called the first time a player is initialized
+ // width and height were collected from the HTML, YouTube, or Vimeo media API
+ // so are reflective of the actual size of the media
+ // use these values to calculate aspectRatio
+ this.aspectRatio = height / width;
+ if (this.playerWidth) {
+ // default width is already defined via a width or data-width attribute. Use that.
+ newWidth = this.playerWidth;
+ if (this.playerHeight) {
+ newHeight = this.playerHeight;
+ } else {
+ newHeight = Math.round(newWidth * this.aspectRatio);
+ this.playerHeight = newHeight;
+ }
+ } else {
+ // playerWidth was not defined via HTML attributes
+ newWidth = (this.player === 'html5') ? $(window).width() : this.$ableWrapper.width();
+ newHeight = Math.round(newWidth * this.aspectRatio);
+ }
+ } else if (this.fullscreen) {
+ this.$ableWrapper.addClass('fullscreen');
+ newWidth = $(window).width();
+ // the 5 pixel buffer is arbitrary, but results in a better fit for all browsers
+ newHeight = $(window).height() - this.$playerDiv.outerHeight() - 5;
+ this.positionCaptions('overlay');
+ } else { // not fullscreen, and not first time initializing player
+ this.$ableWrapper.removeClass('fullscreen');
+ if (this.player === 'html5') {
+ newWidth = (this.playerWidth) ? this.playerWidth : $(window).width();
+ } else {
+ newWidth = this.$ableWrapper.width();
+ }
+ newHeight = Math.round(newWidth * this.aspectRatio);
+ this.positionCaptions(this.prefCaptionsPosition);
+ }
+ if (this.debug) ;
+ // Now size the player with newWidth and newHeight
+ if (this.player === 'youtube' || this.player === 'vimeo') {
+ $iframe = this.$ableWrapper.find('iframe');
+ if (this.player === 'youtube' && this.youTubePlayer) {
+ // alternatively, YouTube API offers a method for setting the video size
+ // this adds width and height attributes to the iframe
+ // but might have other effects, so best to do it this way
+ this.youTubePlayer.setSize(newWidth,newHeight);
+ } else {
+ // Vimeo API does not have a method for changing size of player
+ // Therefore, need to change iframe attributes directly
+ $iframe.attr({
+ 'width': newWidth,
+ 'height': newHeight
+ });
+ }
+ if (this.playerWidth && this.playerHeight) {
+ if (this.fullscreen) {
+ // remove constraints
+ $iframe.css({
+ 'max-width': '',
+ 'max-height': ''
+ });
+ } else {
+ // use CSS on iframe to enforce explicitly defined size constraints
+ $iframe.css({
+ 'max-width': this.playerWidth + 'px',
+ 'max-height': this.playerHeight + 'px'
+ });
+ }
+ }
+ } else if (this.player === 'html5') {
+ if (this.fullscreen) {
+ this.$media.attr({
+ 'width': newWidth,
+ 'height': newHeight
+ });
+ this.$ableWrapper.css({
+ 'width': newWidth,
+ 'height': newHeight
+ });
+ } else {
+ // No constraints. Let CSS handle the positioning.
+ this.$media.removeAttr('width height');
+ this.$ableWrapper.removeAttr( 'style' );
+ }
+ }
+ // Resize captions
+ if (typeof this.$captionsDiv !== 'undefined') {
+
+ // Font-size is too small in full screen view
+ // use viewport units (vw) for large viewports
+ // % units work fine if not fullscreen
+ // prefCaptionSize is expressed as a percentage
+ var isSmallScreen = false;
+ var windowWidth = window.screen.width;
+ if ( windowWidth < 1200 ) {
+ isSmallScreen = true;
+ }
+ captionSize = parseInt(this.prefCaptionsSize,10);
+ if (this.fullscreen && ! isSmallScreen ) {
+ captionSize = (captionSize / 100) + 'vw';
+ } else if ( this.fullscreen && isSmallScreen ) {
+ captionSize = '1.2rem';
+ } else {
+ captionSize = captionSize + '%';
+ }
+ this.$captionsDiv.css({
+ 'font-size': captionSize
+ });
+ }
+ this.refreshControls();
+ };
+
+ AblePlayer.prototype.retrieveOffscreenWindow = function( which, width, height ) {
+
+ // check to be sure popup windows ('transcript' or 'sign') are positioned on-screen
+ // (they sometimes disappear off-screen when entering fullscreen mode)
+ // if off-screen, recalculate so they are back on screen
+
+ var window, windowPos, windowTop, windowLeft, windowRight, windowWidth, windowBottom, windowHeight;
+
+ if (which == 'transcript') {
+ window = this.$transcriptArea;
+ } else if (which == 'sign') {
+ window = this.$signWindow;
+ }
+ windowWidth = window.width();
+ windowHeight = window.height();
+ windowPos = window.position();
+ windowTop = windowPos.top;
+ windowLeft = windowPos.left;
+ windowRight = windowLeft + windowWidth;
+ windowBottom = windowTop + windowHeight;
+
+ if (windowTop < 0) { // off-screen to the top
+ windowTop = 10;
+ window.css('top',windowTop);
+ }
+ if (windowLeft < 0) { // off-screen to the left
+ windowLeft = 10;
+ window.css('left',windowLeft);
+ }
+ if (windowRight > width) { // off-screen to the right
+ windowLeft = (width - 20) - windowWidth;
+ window.css('left',windowLeft);
+ }
+ if (windowBottom > height) { // off-screen to the bottom
+ windowTop = (height - 10) - windowHeight;
+ window.css('top',windowTop);
+ }
+ };
+
+ AblePlayer.prototype.updateZIndex = function(which) {
+
+ // update z-index of 'transcript' or 'sign', relative to each other
+ // direction is always 'up' (i.e., move window to top)
+ // windows come to the top when the user clicks on them
+ var defHighZ, defLowZ, transcriptZ, signZ, newHighZ, newLowZ;
+
+ // set the default z-indexes, as defined in ableplayer.css
+ defHighZ = 8000; // by default, assigned to the sign window
+ defLowZ = 7000; // by default, assigned to the transcript area
+
+ // Previously collected the highest z-index. Removed in 4.6.
+ // If something on the page has a higher z-index than the transcript or sign window, do we care?
+ // Excluding it here assumes "No". Our immediate concern is with the relationship between our own components.
+ // If we elevate our z-indexes so our content is on top, we run the risk of starting a z-index war.
+
+ if (typeof this.$transcriptArea === 'undefined' || typeof this.$signWindow === 'undefined' ) {
+ // at least one of the windows doesn't exist, so there's no conflict
+ // since z-index may have been stored to a cookie on another page, need to restore default
+ if (typeof this.$transcriptArea !== 'undefined') {
+ transcriptZ = parseInt(this.$transcriptArea.css('z-index'));
+ if (transcriptZ > defLowZ) {
+ // restore to the default
+ this.$transcriptArea.css('z-index',defLowZ);
+ }
+ } else if (typeof this.$signWindow !== 'undefined') {
+ signZ = parseInt(this.$signWindow.css('z-index'));
+ if (signZ > defHighZ) {
+ // restore to the default
+ this.$signWindow.css('z-index',defHighZ);
+ }
+ }
+ return false;
+ }
+
+ // both windows exist
+
+ // get current values
+ transcriptZ = parseInt(this.$transcriptArea.css('z-index'));
+ signZ = parseInt(this.$signWindow.css('z-index'));
+
+ if (transcriptZ === signZ) {
+ // the two windows are equal; restore defaults (the target window will be on top)
+ newHighZ = defHighZ;
+ newLowZ = defLowZ;
+ } else if (transcriptZ > signZ) {
+ if (which === 'transcript') {
+ // transcript is already on top; nothing to do
+ return false;
+ } else {
+ // swap z's
+ newHighZ = transcriptZ;
+ newLowZ = signZ;
+ }
+ } else { // signZ is greater
+ if (which === 'sign') {
+ // sign is already on top; nothing to do
+ return false;
+ } else {
+ newHighZ = signZ;
+ newLowZ = transcriptZ;
+ }
+ }
+ // now assign the new values
+ if (which === 'transcript') {
+ this.$transcriptArea.css('z-index',newHighZ);
+ this.$signWindow.css('z-index',newLowZ);
+ } else if (which === 'sign') {
+ this.$signWindow.css('z-index',newHighZ);
+ this.$transcriptArea.css('z-index',newLowZ);
+ }
+ };
+
+ AblePlayer.prototype.syncTrackLanguages = function (source, language) {
+
+ // this function is called when the player is built (source == 'init')
+ // and again when user changes the language of either 'captions' or 'transcript'
+ // It syncs the languages of chapters, descriptions, and metadata tracks
+ // NOTE: Caption and transcript languages are somewhat independent from one another
+ // If a user changes the caption language, the transcript follows
+ // However, if a user changes the transcript language, this only affects the transcript
+ // This was a group decision based on the belief that users may want a transcript
+ // that is in a different language than the captions
+
+ var i, captions, descriptions, chapters, meta;
+
+ // Captions
+ for (i = 0; i < this.captions.length; i++) {
+ if (this.captions[i].language === language) {
+ captions = this.captions[i];
+ }
+ }
+ // Chapters
+ for (i = 0; i < this.chapters.length; i++) {
+ if (this.chapters[i].language === language) {
+ chapters = this.chapters[i];
+ }
+ }
+ // Descriptions
+ for (i = 0; i < this.descriptions.length; i++) {
+ if (this.descriptions[i].language === language) {
+ descriptions = this.descriptions[i];
+ }
+ }
+ // Metadata
+ for (i = 0; i < this.meta.length; i++) {
+ if (this.meta[i].language === language) {
+ meta = this.meta[i];
+ }
+ }
+ // regardless of source...
+ this.transcriptLang = language;
+ if (source === 'init' || source === 'captions') {
+ this.captionLang = language;
+ this.selectedCaptions = captions;
+ this.selectedChapters = chapters;
+ this.selectedDescriptions = descriptions;
+ this.selectedMeta = meta;
+ this.transcriptCaptions = captions;
+ this.transcriptChapters = chapters;
+ this.transcriptDescriptions = descriptions;
+ this.updateChaptersList();
+ // the following was commented out in Oct/Nov 2018.
+ // chapters popup is setup automatically when setupPopups() is called later with no param
+ // not sure why it was included here.
+ // this.setupPopups('chapters');
+ } else if (source === 'transcript') {
+ this.transcriptCaptions = captions;
+ this.transcriptChapters = chapters;
+ this.transcriptDescriptions = descriptions;
+ }
+ if (this.selectedDescriptions) {
+ // updating description voice to match new description language
+ this.setDescriptionVoice();
+ if (this.$sampleDescDiv) {
+ if (this.sampleText) {
+ for (i = 0; i < this.sampleText.length; i++) {
+ if (this.sampleText[i].lang === this.selectedDescriptions.language) {
+ this.currentSampleText = this.sampleText[i]['text'];
+ this.$sampleDescDiv.html(this.currentSampleText);
+ }
+ }
+ }
+ }
+ }
+ this.updateTranscript();
+ };
-(function ($) {
+ }
- AblePlayer.prototype.setupTracks = function () {
- var thisObj, deferred, promise, loadingPromises, loadingPromise, i, tracks, track, kind;
+ function addDescriptionFunctions(AblePlayer) {
+ AblePlayer.prototype.initDescription = function() {
+
+ // set default mode for delivering description (open vs closed)
+ // based on availability and user preference
+
+ // called when player is being built, or when a user
+ // toggles the Description button or changes a description-related preference
+
+ // The following variables are applicable to delivery of description:
+ // defaultStateDescriptions == 'on' or 'off', defined by website owner (overridden by prefDesc)
+ // prefDesc == 1 if user wants description (i.e., Description button is on); else 0
+ // prefDescPause == 1 to pause video when description starts; else 0
+ // prefDescVisible == 1 to visibly show text-based description area; else 0
+ // prefDescMethod == either 'video' or 'text' (as of v4.0.10, prefDescMethod is always 'video')
+ // descMethod is the format actually used ('video' or 'text'), regardless of user preference
+ // hasOpenDesc == true if a described version of video is available via data-desc-src attribute
+ // hasClosedDesc == true if a description text track is available
+ // descOn == true if description of either type is on
+ // readDescriptionsAloud == true if text description is to be announced audibly; otherwise false
+ // descReader == either 'browser' or 'screenreader'
+
+ var deferred, promise;
+
+ deferred = new this.defer();
+ promise = deferred.promise();
+
+ if (this.mediaType === 'audio') {
+ deferred.resolve();
+ }
+
+ // check to see if there's an open-described version of this video
+ // checks only the first source since if a described version is provided,
+ // it must be provided for all sources
+ this.descFile = this.$sources.first().attr('data-desc-src');
+ if (typeof this.descFile !== 'undefined') {
+ this.hasOpenDesc = true;
+ } else {
+ // there's no open-described version via data-desc-src,
+ // but what about data-youtube-desc-src or data-vimeo-desc-src?
+ // if these exist, they would have been defined earlier
+ this.hasOpenDesc = (this.youTubeDescId || this.vimeoDescId) ? true : false;
+ }
+
+ // Set this.descMethod based on media availability & user preferences
+ // no description is available for this video
+ this.descMethod = null;
+ if (this.hasOpenDesc && this.hasClosedDesc) {
+ // both formats are available. User gets their preference.
+ this.descMethod = (this.prefDescMethod) ? this.prefDescMethod : 'video';
+ } else if (this.hasOpenDesc) {
+ this.descMethod = 'video';
+ } else if (this.hasClosedDesc) {
+ this.descMethod = 'text';
+ }
+
+ // Set the default state of descriptions
+ this.descOn = false;
+ if (this.descMethod) {
+ if (this.prefDesc === 1) {
+ this.descOn = true;
+ } else if (this.prefDesc === 0) {
+ this.descOn = false;
+ } else {
+ // user has no prefs. Use default state.
+ this.descOn = (this.defaultStateDescriptions === 1) ? true : false;
+ }
+ }
+
+ // If a video has text audio descriptions, inject the description area.
+ if (typeof this.$descDiv === 'undefined' && this.hasClosedDesc ) {
+ this.injectTextDescriptionArea();
+ }
+
+ if (this.descOn) {
+ if (this.descMethod === 'video' && !this.usingDescribedVersion() ) {
+ // switched from non-described to described version
+ this.swapDescription();
+ }
+ if (this.hasClosedDesc) {
+ if (this.prefDescVisible) {
+ // make description text visible
+ if (typeof this.$descDiv !== 'undefined') {
+ this.$descDiv.show();
+ this.$descDiv.removeClass('able-offscreen');
+ }
+ } else {
+ // keep it visible to screen readers, but hide it visibly
+ if (typeof this.$descDiv !== 'undefined') {
+ this.$descDiv.addClass('able-offscreen');
+ }
+ }
+ }
+ } else { // description is off.
+ if (this.descMethod === 'video') { // user has turned off described version of video
+ if (this.usingDescribedVersion()) {
+ // user was using the described verion. Swap for non-described version
+ this.swapDescription();
+ }
+ } else if (this.descMethod === 'text') { // user has turned off text description
+ // hide description div from everyone, including screen reader users
+ if (typeof this.$descDiv !== 'undefined') {
+ this.$descDiv.hide();
+ this.$descDiv.removeClass('able-offscreen');
+ }
+ }
+ }
+ deferred.resolve();
+ return promise;
+ };
+
+ AblePlayer.prototype.usingDescribedVersion = function () {
+
+ // Returns true if currently using audio description, false otherwise.
+
+ if (this.player === 'youtube') {
+ return (this.activeYouTubeId === this.youTubeDescId);
+ } else if (this.player === 'vimeo') {
+ return (this.activeVimeoId === this.vimeoDescId);
+ } else {
+ return (this.$sources.first().attr('data-desc-src') === this.$sources.first().attr('src'));
+ }
+ };
+
+ /**
+ * Initializes speech synthesis capabilities for the player.
+ * This method addresses browser and OS limitations that require user interaction
+ * before speech synthesis functions become available. It handles different contexts
+ * like initialization, playing media, accessing preferences, or announcing descriptions.
+ * @param {string} context - The context in which the function is called ('init', 'play', 'prefs', 'desc').
+ */
+ AblePlayer.prototype.initSpeech = function (context) {
+ var thisObj = this;
+
+ // Function to attempt enabling speech synthesis
+ function attemptEnableSpeech() {
+ var greeting = new SpeechSynthesisUtterance("\x20");
+ greeting.onend = function () {
+ thisObj.getBrowserVoices();
+ if (
+ (Array.isArray(thisObj.descVoices) && thisObj.descVoices.length) ||
+ context !== "init"
+ ) {
+ thisObj.speechEnabled = true;
+ }
+ };
+ thisObj.synth.speak(greeting);
+ }
+
+ // Function to handle the initial click and enable speech synthesis
+ function handleInitialClick() {
+ attemptEnableSpeech();
+ // Once the utterance starts, remove this specific click event listener
+ // Ensures the event handler only runs once and cleans up after itself
+ $(document).off("click", handleInitialClick);
+ }
+
+ if (this.speechEnabled === null) {
+ if (window.speechSynthesis) {
+ // Browser supports speech synthesis
+ this.synth = window.speechSynthesis;
+ this.synth.cancel(); // Cancel any ongoing speech synthesis
+
+ if (context === "init") {
+ // Attempt to enable speech synthesis directly for browsers that don't require a click
+ attemptEnableSpeech();
+ // For initial setup, require a user click to enable speech synthesis
+ // Scoping to a particular handler to avoid conflicts with other click events
+ $(document).on("click", handleInitialClick);
+ } else {
+ // For other contexts, attempt to enable speech synthesis directly
+ attemptEnableSpeech();
+ }
+ } else {
+ // Browser does not support speech synthesis
+ this.speechEnabled = false;
+ }
+ }
+ };
+
+ AblePlayer.prototype.getBrowserVoices = function () {
+
+ // define this.descVoices array
+ // includes only languages that match the language of the captions or player
+
+ var voices, trackLangs, voiceLang, preferredLang;
+
+ preferredLang = (this.captionLang) ? this.captionLang.substring(0,2).toLowerCase() : this.lang.substring(0,2).toLowerCase();
+
+ this.descVoices = [];
+ voices = this.synth.getVoices();
+ trackLangs = this.getTrackLangs();
+ if (voices.length > 0) {
+ this.descVoices = [];
+ // available languages are identified with local suffixes (e.g., en-US)
+ for (var i=0; i 0) {
+ if (prefDescVoice) {
+ // select the language that matches prefDescVoice, if it's available
+ prefVoiceFound = false;
+ for (var i=0; i 0) {
+ this.swapTime = this.elapsed;
+ } else {
+ this.swapTime = 0;
+ }
+ if (this.duration > 0) {
+ this.prevDuration = this.duration;
+ }
+
+ // Capture current playback state, so media can resume after source is swapped
+ if (!this.okToPlay) {
+ this.okToPlay = this.playing;
+ }
+
+ if (this.descOn) {
+ this.showAlert( this.translate( 'alertDescribedVersion', 'Using the audio described version of this video' ) );
+ } else {
+ this.showAlert( this.translate( 'alertNonDescribedVersion', 'Using the non-described version of this video' ) );
+ }
+
+ if (this.player === 'html5') {
+
+ this.swappingSrc = true;
+ this.paused = true;
+
+ if (this.usingDescribedVersion()) {
+ // the described version is currently playing. Swap to non-described
+ for (i=0; i < this.$sources.length; i++) {
+ // for all elements, replace src with data-orig-src
+ origSrc = purify.sanitize( this.$sources[i].getAttribute('data-orig-src') );
+ if (origSrc) {
+ this.$sources[i].setAttribute('src',origSrc);
+ }
+ }
+ } else {
+ // the non-described version is currently playing. Swap to described.
+ for (i=0; i < this.$sources.length; i++) {
+ // for all elements, replace src with data-desc-src (if one exists)
+ // then store original source in a new data-orig-src attribute
+ origSrc = purify.sanitize( this.$sources[i].getAttribute('src') );
+ descSrc = purify.sanitize( this.$sources[i].getAttribute('data-desc-src') );
+ if (descSrc) {
+ this.$sources[i].setAttribute('src',descSrc);
+ this.$sources[i].setAttribute('data-orig-src',origSrc);
+ }
+ }
+ }
+
+ if (this.recreatingPlayer) {
+ // stopgap to prevent multiple firings of recreatePlayer()
+ return;
+ }
+ if (this.playerCreated) {
+ // delete old player, then recreate it with new source & tracks
+ this.deletePlayer('swap-desc-html');
+ this.recreatePlayer().then(function() {
+ if (!thisObj.loadingMedia) {
+ thisObj.media.load();
+ thisObj.loadingMedia = true;
+ }
+ });
+ }
+ } else if (this.player === 'youtube') {
+
+ // if the described version is currently playing, swap to non-described
+ this.activeYouTubeId = (this.usingDescribedVersion()) ? this.youTubeId : this.youTubeDescId;
+
+ if (typeof this.youTubePlayer !== 'undefined') {
+ thisObj.swappingSrc = true;
+ if (thisObj.playing) {
+ // loadVideoById() loads and immediately plays the new video at swapTime
+ thisObj.youTubePlayer.loadVideoById(thisObj.activeYouTubeId,thisObj.swapTime);
+ } else {
+ // cueVideoById() loads the new video and seeks to swapTime, but does not play
+ thisObj.youTubePlayer.cueVideoById(thisObj.activeYouTubeId,thisObj.swapTime);
+ }
+ }
+ if (this.playerCreated) {
+ this.deletePlayer('swap-desc-youtube');
+ }
+ // player needs to be recreated with new source
+ if (this.recreatingPlayer) {
+ // stopgap to prevent multiple firings of recreatePlayer()
+ return;
+ }
+ this.recreatePlayer().then(function() {
+ // nothing to do here
+ // next steps occur when youtube onReady event fires
+ // see youtube.js > finalizeYoutubeInit()
+ });
+ } else if (this.player === 'vimeo') {
+ if (this.usingDescribedVersion()) {
+ // the described version is currently playing. Swap to non-described
+ this.activeVimeoId = this.vimeoId;
+ this.showAlert( this.translate( 'alertNonDescribedVersion', 'Using the non-described version of this video' ) );
+ } else {
+ // the non-described version is currently playing. Swap to described.
+ this.activeVimeoId = this.vimeoDescId;
+ this.showAlert( this.translate( 'alertDescribedVersion', 'Using the audio described version of this video' ) );
+ }
+ if (this.playerCreated) {
+ this.deletePlayer('swap-desc-vimeo');
+ }
+ // player needs to be recreated with new source
+ if (this.recreatingPlayer) {
+ // stopgap to prevent multiple firings of recreatePlayer()
+ return;
+ }
+ this.recreatePlayer().then(function() {
+ // load the new video source
+ thisObj.vimeoPlayer.loadVideo(thisObj.activeVimeoId).then(function() {
+ if (thisObj.playing) {
+ // video was playing when user requested an alternative version
+ // seek to swapTime and continue playback (playback happens automatically)
+ thisObj.vimeoPlayer.setCurrentTime(thisObj.swapTime);
+ } else {
+ // Vimeo autostarts immediately after video loads
+ // The "Described" button should not trigger playback, so stop this before the user notices.
+ thisObj.vimeoPlayer.pause();
+ }
+ });
+ });
+ }
+ };
+
+ AblePlayer.prototype.showDescription = function(now) {
+ if (!this.playing || !this.hasClosedDesc || this.swappingSrc || !this.descOn || ( this.descMethod === 'video' && !this.prefDescVisible ) ) {
+ return;
+ }
+
+ var cues, d, thisDescription, descText;
+
+ var flattenComponentForDescription = function (component) {
+ var result = [];
+ if (component.type === 'string') {
+ result.push(component.value);
+ } else {
+ for (var i = 0; i < component.children.length; i++) {
+ result.push(flattenComponentForDescription(component.children[i]));
+ }
+ }
+ return result.join('');
+ };
+ cues = [];
+ if (this.selectedDescriptions) {
+ cues = this.selectedDescriptions.cues;
+ } else if (this.descriptions.length >= 1) {
+ cues = this.descriptions[0].cues;
+ }
+ for (d = 0; d < cues.length; d++) {
+ if ((cues[d].start <= now) && (cues[d].end > now)) {
+ thisDescription = d;
+ break;
+ }
+ }
+ if (typeof thisDescription !== 'undefined') {
+ if (this.currentDescription !== thisDescription) {
+ // temporarily remove aria-live from $status to prevent description from being interrupted
+ this.$status.removeAttr('aria-live');
+ descText = flattenComponentForDescription(cues[thisDescription].components);
+ if (this.descReader === 'screenreader') {
+ // load the new description into the container div for screen readers to read
+ this.$descDiv.html(descText);
+ } else if (this.speechEnabled) {
+ if ( 'video' !== this.descMethod ) {
+ // use browser's built-in speech synthesis
+ this.announceText('description',descText);
+ }
+ if (this.prefDescVisible) {
+ // write description to the screen for sighted users
+ // but remove ARIA attributes since it isn't intended to be read by screen readers
+ this.$descDiv.html(descText).removeAttr('aria-live aria-atomic');
+ }
+ } else {
+ // browser does not support speech synthesis
+ // load the new description into the container div for screen readers to read
+ this.$descDiv.html(descText);
+ }
+ // Only pause video if not using a described video.
+ if (this.prefDescPause && this.descMethod === 'text') {
+ this.pauseMedia();
+ this.pausedForDescription = true;
+ }
+ this.currentDescription = thisDescription;
+ }
+ } else {
+ this.$descDiv.html('');
+ this.currentDescription = -1;
+ // restore aria-live to $status
+ this.$status.attr('aria-live','polite');
+ }
+ };
+
+ AblePlayer.prototype.syncSpeechToPlaybackRate = function(rate) {
+
+ // called when user changed playback rate
+ // adjust rate of audio description to match
+ var speechRate;
+
+ if (rate === 0.5) {
+ speechRate = 0.7; // option 1 in prefs menu
+ } else if (rate === 0.75) {
+ speechRate = 0.8; // option 2 in prefs menu
+ } else if (rate === 1.0) {
+ speechRate = 1; // option 4 in prefs menu (normal speech, default)
+ } else if (rate === 1.25) {
+ speechRate = 1.1; // option 5 in prefs menu
+ } else if (rate === 1.5) {
+ speechRate = 1.2; // option 6 in prefs menu
+ } else if (rate === 1.75) {
+ speechRate = 1.5; // option 7 in prefs menu
+ } else if (rate === 2.0) {
+ speechRate = 2; // option 8 in prefs menu (fast)
+ } else if (rate === 2.25) {
+ speechRate = 2.5; // option 9 in prefs menu (very fast)
+ } else if (rate >= 2.5) {
+ speechRate = 3; // option 10 in prefs menu (super fast)
+ }
+ this.prefDescRate = speechRate;
+ };
+
+ AblePlayer.prototype.announceText = function(context, text, rate) {
+
+ // this function announces text using speech synthesis
+ // it's only called if already determined that browser supports speech synthesis
+ // context is either:
+ // 'description' - actual description text extracted from WebVTT file
+ // 'sample' - called when user changes a setting in Description Prefs dialog
+ // 'caption' - called when announcing a caption.
+
+ var thisObj, voiceName, i, voice, pitch, volume, utterance,
+ timeElapsed;
+
+ thisObj = this;
+
+ if (!this.speechEnabled) {
+ // voices array failed to load the first time. Try again
+ this.initSpeech('desc');
+ }
+
+ if (context === 'sample') {
+ // get settings from form
+ voiceName = $('#' + this.mediaId + '_prefDescVoice').val();
+ pitch = $('#' + this.mediaId + '_prefDescPitch').val();
+ rate = $('#' + this.mediaId + '_prefDescRate').val();
+ volume = $('#' + this.mediaId + '_prefDescVolume').val();
+ } else if ( context === 'captionSample' ) {
+ // get settings from form
+ voiceName = $('#' + this.mediaId + '_prefCaptionsVoice').val();
+ pitch = $('#' + this.mediaId + '_prefCaptionsPitch').val();
+ rate = $('#' + this.mediaId + '_prefCaptionsRate').val();
+ volume = $('#' + this.mediaId + '_prefCaptionsVolume').val();
+ } else if ( context === 'description' ) {
+ // get settings from global prefs
+ voiceName = this.prefDescVoice;
+ pitch = this.prefDescPitch;
+ rate = this.prefDescRate;
+ volume = this.prefDescVolume;
+ } else {
+ // get settings from global prefs
+ voiceName = this.prefCaptionsVoice;
+ pitch = this.prefCaptionsPitch;
+ rate = ( rate < this.prefCaptionsRate ) ? this.prefCaptionsRate : rate;
+ volume = this.prefCaptionsVolume;
+ }
+
+ // get the voice associated with the user's chosen voice name
+ if (this.descVoices) {
+ if (this.descVoices.length > 0) {
+ if (voiceName) {
+ // get the voice that matches user's preferred voiceName
+ for (i = 0; i < this.descVoices.length; i++) {
+ if (this.descVoices[i].name == voiceName) {
+ voice = this.descVoices[i];
+ break;
+ }
+ }
+ }
+ if (typeof voice === 'undefined') {
+ // no matching voice was found
+ // use the first voice in the array
+ voice = this.descVoices[0];
+ }
+ }
+ } else {
+ voice = null;
+ }
+ utterance = new SpeechSynthesisUtterance();
+ if (voice) {
+ utterance.voice = voice;
+ }
+ utterance.voiceURI = 'native';
+ utterance.volume = volume;
+ utterance.rate = rate;
+ utterance.pitch = pitch;
+ utterance.text = text;
+ // TODO: Consider the best language for the utterance:
+ // language of the web page? (this.lang)
+ // language of the WebVTT description track?
+ // language of the user's chosen voice?
+ // If there's a mismatch between any of these, the description will likely be unintelligible
+ utterance.lang = this.lang;
+ utterance.onstart = function(e) {
+ // utterance has started
+ };
+ utterance.onpause = function(e) {
+ // utterance has paused
+ };
+ utterance.onend = function(e) {
+ // utterance has ended
+ if ( 'description' === context ) {
+ this.speakingDescription = false;
+ } else if ( 'caption' === context ) {
+ this.speakingCaption = false;
+ }
+ timeElapsed = e.elapsedTime;
+ // As of Firefox 95, e.elapsedTime is expressed in seconds
+ // Other browsers (tested in Chrome & Edge) express this in milliseconds
+ // Assume no utterance will require over 100 seconds to express...
+ // If a large value, time is likely expressed in milliseconds.
+ (timeElapsed > 100) ? (e.elapsedTime/1000).toFixed(2) : (e.elapsedTime).toFixed(2);
+
+ if (this.debug) ;
+ if (context === 'description') {
+ if (thisObj.prefDescPause) {
+ if (thisObj.pausedForDescription) {
+ thisObj.playMedia();
+ this.pausedForDescription = false;
+ }
+ }
+ }
+ };
+ utterance.onerror = function(e) {
+ // handle error
+ };
+ if (this.synth.paused) {
+ this.synth.resume();
+ }
+ this.synth.speak(utterance);
+ if ( 'description' === context ) {
+ this.speakingDescription = true;
+ } else if ( 'caption' === context ) {
+ this.speakingCaption = true;
+ }
+ };
- thisObj = this;
+ }
- deferred = new this.defer();
- promise = deferred.promise();
+ // Outdented for a simpler diff
+ var focusableElementsSelector = "a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]";
+
+ // Based on the incredible accessible modal dialog.
+ function AccessibleDialog( modalDiv, $returnElement, title, closeButtonLabel) {
+
+ this.title = title;
+ this.closeButtonLabel = closeButtonLabel;
+ this.focusedElementBeforeModal = $returnElement;
+ this.baseId = $(modalDiv).attr('id') || Math.floor(Math.random() * 1000000000).toString();
+ var thisObj = this;
+ var modal = modalDiv;
+ this.modal = modal;
+
+ modal.addClass('able-modal-dialog');
+
+ var closeButton = $('',{
+ 'class': 'modalCloseButton',
+ 'title': thisObj.closeButtonLabel,
+ 'aria-label': thisObj.closeButtonLabel
+ }).text('×');
+ closeButton.on( 'keydown', function (e) {
+ if (e.key === ' ') {
+ thisObj.hide();
+ }
+ }).on( 'click', function () {
+ thisObj.hide();
+ });
+
+ var titleH1 = $(' ');
+ titleH1.attr('id', 'modalTitle-' + this.baseId);
+ titleH1.text(title);
+ this.titleH1 = titleH1;
+
+ modal.attr({
+ 'aria-labelledby': 'modalTitle-' + this.baseId,
+ });
+ var modalHeader = $( '', {
+ 'class': 'able-modal-header'
+ });
+ modalHeader.prepend(titleH1);
+ modalHeader.prepend(closeButton);
+ modal.prepend(modalHeader);
+
+ modal.attr({
+ 'aria-hidden': 'true',
+ 'role': 'dialog',
+ 'aria-modal': 'true'
+ });
+
+ modal.on( 'keydown', function (e) {
+ if (e.key === 'Escape') {
+ thisObj.hide();
+ e.preventDefault();
+ } else if (e.key === 'Tab') {
+ // Manually loop tab navigation inside the modal.
+ var parts = modal.find('*');
+ var focusable = parts.filter(focusableElementsSelector).filter(':visible');
+
+ if (focusable.length === 0) {
+ return;
+ }
+
+ var focused = $(':focus');
+ var currentIndex = focusable.index(focused);
+ if (e.shiftKey) {
+ // If backwards from first element, go to last.
+ if (currentIndex === 0) {
+ focusable.get(focusable.length - 1).trigger('focus');
+ e.preventDefault();
+ }
+ } else {
+ if (currentIndex === focusable.length - 1) {
+ focusable.get(0).trigger('focus');
+ e.preventDefault();
+ }
+ }
+ }
+ e.stopPropagation();
+ });
+
+ if ( $( 'body' ).hasClass( 'able-modal-active' ) ) {
+ $( 'body > *') .not('.able-modal-overlay').not('.able-modal-dialog').removeAttr('inert');
+ $( 'body' ).removeClass( 'able-modal-active' );
+ }
+ }
+ AccessibleDialog.prototype.show = function () {
+ if (!this.overlay) {
+ // Generate overlay.
+ var overlay = $('
').attr({
+ 'class': 'able-modal-overlay',
+ 'tabindex': '-1'
+ });
+ this.overlay = overlay;
+ $('body').append(overlay);
+
+ // Keep from moving focus out of dialog when clicking outside of it.
+ overlay.on('mousedown.accessibleModal', function (e) {
+ e.preventDefault();
+ thisObj.hide();
+ });
+ }
+
+ $('body > *').not('.able-modal-overlay').not('.able-modal-dialog').attr('inert', true);
+ $( 'body' ).addClass( 'able-modal-active' );
+
+ this.overlay.css('display', 'block');
+ this.modal.css('display', 'block');
+ this.modal.attr({
+ 'aria-hidden': 'false',
+ 'tabindex': '-1'
+ });
+
+ var focusable = this.modal.find("*").filter(focusableElementsSelector).filter(':visible');
+ if (focusable.length === 0) {
+ this.focusedElementBeforeModal.blur();
+ }
+ var thisObj = this;
+ setTimeout(function () {
+ // set focus on the first focusable element
+ thisObj.modal.find('button.modalCloseButton').first().trigger('focus');
+ }, 300);
+ };
+
+ AccessibleDialog.prototype.hide = function () {
+ if (this.overlay) {
+ this.overlay.css('display', 'none');
+ }
+ this.modal.css('display', 'none');
+ this.modal.attr('aria-hidden', 'true');
+ $('body > *').not('.able-modal-overlay').not('.able-modal-dialog').removeAttr('inert');
+ $( 'body' ).removeClass( 'able-modal-active' );
+
+ this.focusedElementBeforeModal.trigger('focus');
+ };
+
+ AccessibleDialog.prototype.getInputs = function () {
+
+ // return an array of input elements within this dialog
+ if (this.modal) {
+ var inputs = this.modal.find('input');
+ return inputs;
+ }
+ return false;
+ };
+
+ function addDragdropFunctions(AblePlayer) {
+ AblePlayer.prototype.initDragDrop = function ( which ) {
+
+ // supported values of which: 'sign', 'transcript'
+
+ // NOTE: "Drag and Drop" for Able Player is a metaphor only!!!
+ // HTML5 Drag & Drop API enables moving elements to new locations in the DOM
+ // Thats not our purpose; we're simply changing the visible position on-screen
+ // Therefore, the drag & drop interface was overhauled in v2.3.41 to simply
+ // use mouse (and keyboard) events to change CSS positioning properties
+
+ // There are nevertheless lessons to be learned from Drag & Drop about accessibility:
+ // http://dev.opera.com/articles/accessible-drag-and-drop/
+
+ var thisObj, $window, $toolbar, windowName, $dragHandle, $resizeHandle, $resizeSvg,
+ i, x1, y1, x2, y2, $resizeLine, resizeZIndex;
+
+ thisObj = this;
+
+ if (which === 'transcript') {
+ $window = this.$transcriptArea;
+ windowName = 'transcript-window';
+ $toolbar = this.$transcriptToolbar;
+ $toolbar.attr( 'aria-label', this.translate( 'transcriptControls', 'Transcript Window Controls' ) );
+ } else if (which === 'sign') {
+ $window = this.$signWindow;
+ windowName = 'sign-window';
+ $toolbar = this.$signToolbar;
+ $toolbar.attr( 'aria-label', this.translate( 'signControls', 'Sign Language Window Controls' ) );
+ }
+
+ // add class to trigger change in cursor on hover
+ $toolbar.addClass('able-draggable');
+ $toolbar.attr( 'role', 'application' );
+
+ $dragHandle = $('
',{
+ 'class': 'able-drag-handle'
+ });
+
+ $dragHandle.html('
');
+ // add resize handle selector to bottom right corner
+ $resizeHandle = $('
',{
+ 'class': 'able-resizable'
+ });
+
+ // fill it with three parallel diagonal lines
+ $resizeSvg = $('
').attr({
+ 'width': '100%',
+ 'height': '100%',
+ 'viewBox': '0 0 100 100',
+ 'preserveAspectRatio': 'none'
+ });
+ for (i=1; i<=3; i++) {
+ if (i === 1) {
+ x1 = '100';
+ y1 = '0';
+ x2 = '0';
+ y2 = '100';
+ } else if (i === 2) {
+ x1 = '33';
+ y1 = '100';
+ x2 = '100';
+ y2 = '33';
+ } else if (i === 3) {
+ x1 = '67';
+ y1 = '100';
+ x2 = '100';
+ y2 = '67';
+ }
+ $resizeLine = $('').attr({
+ 'x1': x1,
+ 'y1': y1,
+ 'x2': x2,
+ 'y2': y2,
+ 'vector-effect': 'non-scaling-stroke'
+ });
+ $resizeSvg.append($resizeLine);
+ }
+ $resizeHandle.html($resizeSvg);
+
+ // assign z-index that's slightly higher than parent window
+ resizeZIndex = parseInt($window.css('z-index')) + 100;
+ $resizeHandle.css('z-index',resizeZIndex);
+ $window.append($resizeHandle);
+ $toolbar.append($dragHandle);
+
+ // Final step: Need to refresh the DOM in order for browser to process & display the SVG
+ $resizeHandle.html($resizeHandle.html());
+
+ // add event listener to toolbar to start and end drag
+ // other event listeners will be added when drag starts
+ $dragHandle.on('mousedown mouseup touchstart touchend', function(e) {
+ e.stopPropagation();
+ if (e.type === 'mousedown' || e.type === 'touchstart' ) {
+ if (!thisObj.windowMenuClickRegistered) {
+ thisObj.windowMenuClickRegistered = true;
+ thisObj.startMouseX = e.pageX;
+ thisObj.startMouseY = e.pageY;
+ thisObj.dragDevice = 'mouse'; // ok to use this even if device is a touchpad
+ thisObj.startDrag(which, $window);
+ }
+ } else if (e.type === 'mouseup' || e.type === 'touchend') {
+ if (thisObj.dragging && thisObj.dragDevice === 'mouse') {
+ thisObj.endDrag(which);
+ }
+ }
+ return false;
+ });
+
+ // add event listeners for resizing
+ $resizeHandle.on('mousedown mouseup touchstart touchend', function(e) {
+ e.stopPropagation();
+ if (e.type === 'mousedown' || e.type === 'touchstart') {
+ if (!thisObj.windowMenuClickRegistered) {
+ thisObj.windowMenuClickRegistered = true;
+ thisObj.startMouseX = e.pageX;
+ thisObj.startMouseY = e.pageY;
+ thisObj.startResize(which, $window);
+ }
+ } else if (e.type === 'mouseup' || e.type === 'touchend') {
+ if (thisObj.resizing) {
+ thisObj.endResize(which);
+ }
+ }
+ return false;
+ });
+
+ // whenever a window is clicked, bring it to the foreground
+ $window.on('click', function() {
+
+ if (!thisObj.windowMenuClickRegistered && !thisObj.finishingDrag) {
+ thisObj.updateZIndex(which);
+ }
+ thisObj.finishingDrag = false;
+ });
+ this.addWindowMenu(which,$window,windowName);
+ };
+
+ AblePlayer.prototype.addWindowMenu = function(which, $window, windowName) {
+
+ var thisObj, menuId, $newButton, tooltipId, $tooltip, $popup;
+
+ thisObj = this;
+
+ // Add a Boolean that will be set to true temporarily if window button or a menu item is clicked
+ // This will prevent the click event from also triggering a mousedown event on the toolbar
+ // (which would unexpectedly send the window into drag mode)
+ this.windowMenuClickRegistered = false;
+
+ // Add another Boolean that will be set to true temporarily when mouseup fires at the end of a drag
+ // this will prevent the click event from being triggered
+ this.finishingDrag = false;
+
+ // add button to draggable window which triggers a popup menu
+ menuId = this.mediaId + '-' + windowName + '-menu';
+ $newButton = $('',{
+ 'type': 'button',
+ 'tabindex': '0',
+ 'aria-haspopup': 'true',
+ 'aria-controls': menuId,
+ 'aria-expanded': 'false',
+ 'class': 'able-button-handler-preferences'
+ });
+ this.getIcon( $newButton, 'preferences' );
+ this.setText( $newButton, this.translate( 'windowButtonLabel', 'Window options' ) );
+
+ // add a tooltip that displays aria-label on mouseenter or focus
+ tooltipId = this.mediaId + '-' + windowName + '-tooltip';
+ $tooltip = $('',{
+ 'class' : 'able-tooltip',
+ 'id' : tooltipId
+ }).hide();
+
+ $newButton.on('mouseenter focus',function(e) {
+ var label = $(this).attr('aria-label');
+ var tooltip = AblePlayer.localGetElementById($newButton[0], tooltipId).text(label);
+ // get height of the tooltip
+ var tooltipHeight = tooltip.height();
+ var tooltipY = ( tooltipHeight + 2 ) * -1;
+ var tooltipX = 0;
+ var tooltipStyle = {
+ right: '',
+ left: tooltipX + 'px',
+ top: tooltipY + 'px'
+ };
+ tooltip.css(tooltipStyle);
+ thisObj.showTooltip(tooltip);
+ $(this).on('mouseleave blur',function() {
+ AblePlayer.localGetElementById($newButton[0], tooltipId).text('').hide();
+ });
+ });
+
+ // setup popup menu
+ $popup = this.setupPopups(windowName); // 'transcript-window' or 'sign-window'
+ // define vars and assemble all the parts
+ if (which === 'transcript') {
+ this.$transcriptPopupButton = $newButton;
+ this.$transcriptPopup = $popup;
+ this.$transcriptToolbar.prepend($newButton,$tooltip,$popup);
+ } else if (which === 'sign') {
+ this.$signPopupButton = $newButton;
+ this.$signPopup = $popup;
+ this.$signToolbar.append($newButton,$tooltip,$popup);
+ }
+
+ // handle button click
+ $newButton.on('click keydown',function(e) {
+
+ if (thisObj.focusNotClick) {
+ return false;
+ }
+ if (thisObj.dragging) {
+ thisObj.dragKeys(which, e);
+ return false;
+ }
+ e.stopPropagation();
+ if (!thisObj.windowMenuClickRegistered && !thisObj.finishingDrag) {
+ // don't set windowMenuClickRegistered yet; that happens in handler function
+ thisObj.handleWindowButtonClick(which, e);
+ }
+ thisObj.finishingDrag = false;
+ });
+
+ this.addResizeDialog(which, $window);
+ };
+
+ AblePlayer.prototype.addResizeDialog = function (which) {
+
+ var thisObj, $windowPopup, $windowButton, widthId, heightId,
+ $resizeForm, $resizeWrapper, $resizeControls, $resizeWidthDiv, $resizeWidthInput, $resizeWidthLabel,
+ $resizeHeightDiv, $resizeHeightInput, $resizeHeightLabel, $saveButton, $cancelButton,
+ newWidth, newHeight, resizeDialog;
+
+ thisObj = this;
+
+ if (which === 'transcript') {
+ $windowPopup = this.$transcriptPopup;
+ $windowButton = this.$transcriptPopupButton;
+ } else if (which === 'sign') {
+ $windowPopup = this.$signPopup;
+ $windowButton = this.$signPopupButton;
+ }
+
+ widthId = this.mediaId + '-resize-' + which + '-width';
+ heightId = this.mediaId + '-resize-' + which + '-height';
+
+ $resizeForm = $('
',{
+ 'class' : 'able-resize-form'
+ });
+
+ // inner container for all content, will be assigned to modal div's aria-describedby
+ $resizeWrapper = $('
');
+ $resizeControls = $( '
' );
+
+ // width field
+ $resizeWidthDiv = $('
');
+ $resizeWidthInput = $('
',{
+ 'type': 'number',
+ 'id': widthId,
+ 'min': 0,
+ 'value': '',
+ });
+ $resizeWidthLabel = $('
',{
+ 'for': widthId
+ }).text( this.translate( 'width', 'Width' ) );
+
+ // height field
+ $resizeHeightDiv = $('
');
+ $resizeHeightInput = $(' ',{
+ 'type': 'number',
+ 'id': heightId,
+ 'min': 0,
+ 'value': '',
+ });
+ $resizeHeightLabel = $('',{
+ 'for': heightId
+ }).text( this.translate( 'height', 'Height' ) );
+
+ // Add save and cancel buttons.
+ $saveButton = $('' + this.translate( 'save', 'Save' ) + ' ');
+ $cancelButton = $('' + this.translate( 'cancel', 'Cancel' ) + ' ');
+ $saveButton.on('click',function () {
+ newWidth = $('#' + widthId).val();
+ newHeight = $('#' + heightId).val();
+ thisObj.resizeObject(which,newWidth,newHeight);
+ thisObj.updatePreferences(which);
+
+ resizeDialog.hide();
+ $windowPopup.hide();
+ $windowButton.trigger('focus');
+ });
+ $cancelButton.on('click',function () {
+ resizeDialog.hide();
+ $windowPopup.hide();
+ $windowButton.trigger('focus');
+ });
+
+ // Now assemble all the parts
+ $resizeWidthDiv.append($resizeWidthLabel,$resizeWidthInput);
+ $resizeHeightDiv.append($resizeHeightLabel,$resizeHeightInput);
+ $resizeWrapper.append($resizeWidthDiv,$resizeHeightDiv);
+ $resizeControls.append($saveButton,$cancelButton);
+ $resizeForm.append($resizeWrapper,$resizeControls);
+
+ // must be appended to the BODY!
+ // otherwise when aria-hidden="true" is applied to all background content
+ // that will include an ancestor of the dialog,
+ // which will render the dialog unreadable by screen readers
+ $('body').append($resizeForm);
+ resizeDialog = new AccessibleDialog(
+ $resizeForm,
+ $windowButton,
+ this.translate( 'windowResizeHeading', 'Resize Window' ),
+ this.translate( 'closeButtonLabel', 'Close' ),
+ );
+ if (which === 'transcript') {
+ this.transcriptResizeDialog = resizeDialog;
+ } else if (which === 'sign') {
+ this.signResizeDialog = resizeDialog;
+ }
+ };
+
+ AblePlayer.prototype.handleWindowButtonClick = function (which, e) {
+
+ var thisObj, $windowPopup, $windowButton, $toolbar, popupTop;
+
+ thisObj = this;
+ if (this.focusNotClick) {
+ // transcript or sign window has just opened,
+ // and focus moved to the window button
+ // ignore the keystroke that triggered the popup
+ return false;
+ }
+
+ if (which === 'transcript') {
+ $windowPopup = this.$transcriptPopup;
+ $windowButton = this.$transcriptPopupButton;
+ $toolbar = this.$transcriptToolbar;
+ } else if (which === 'sign') {
+ $windowPopup = this.$signPopup;
+ $windowButton = this.$signPopupButton;
+ $toolbar = this.$signToolbar;
+ }
+ if (e.type === 'keydown') {
+ // user pressed a key
+ if (e.key === ' ' || e.key === 'Enter') {
+ this.windowMenuClickRegistered = true;
+ } else if (e.key === 'Escape') {
+ if ($windowPopup.is(':visible')) {
+ // close the popup menu
+ $windowPopup.hide();
+ // also reset the Boolean
+ thisObj.windowMenuClickRegistered = false;
+ // also restore menu items to their original state
+ $windowPopup.find('li').removeClass('able-focus').attr('tabindex','-1');
+ // also return focus to window options button
+ $windowButton.trigger('focus');
+ } else {
+ // popup isn't open. Close the window
+ if (which === 'sign') {
+ this.handleSignToggle();
+ } else if (which === 'transcript') {
+ this.handleTranscriptToggle();
+ }
+ }
+ } else {
+ return false;
+ }
+ } else {
+ // this was a mouse event
+ this.windowMenuClickRegistered = true;
+ }
+
+ if ( $windowPopup.is(':visible') ) {
+ $windowPopup.hide();
+ thisObj.windowMenuClickRegistered = false; // reset
+ $windowPopup.find('li').removeClass('able-focus');
+ $windowButton.attr('aria-expanded','false').trigger('focus');
+ } else {
+ // first, be sure window is on top
+ this.updateZIndex(which);
+ popupTop = $toolbar.outerHeight() - 1;
+ $windowPopup.css('top', popupTop);
+ $windowPopup.show();
+ $windowButton.attr('aria-expanded','true');
+ $(this).find('li').first().trigger('focus').addClass('able-focus');
+ thisObj.windowMenuClickRegistered = false; // reset
+ }
+ };
+
+ AblePlayer.prototype.handleMenuChoice = function (which, choice, e) {
+
+ var thisObj, $window, $windowPopup, $windowButton, resizeDialog, startingWidth, startingHeight,
+ aspectRatio, tempWidth, tempHeight;
+
+ thisObj = this;
+ if (which === 'transcript') {
+ $window = this.$transcriptArea;
+ $windowPopup = this.$transcriptPopup;
+ $windowButton = this.$transcriptPopupButton;
+ resizeDialog = this.transcriptResizeDialog;
+ } else if (which === 'sign') {
+ $window = this.$signWindow;
+ $windowPopup = this.$signPopup;
+ $windowButton = this.$signPopupButton;
+ resizeDialog = this.signResizeDialog;
+
+ startingWidth = $window.outerWidth();
+ startingHeight = $window.outerHeight();
+ aspectRatio = startingWidth / startingHeight;
+ // make height a read-only field
+ // and calculate its value based on width to preserve aspect ratio
+ let widthId = this.mediaId + '-resize-' + which + '-width';
+ let heightId = this.mediaId + '-resize-' + which + '-height';
+ $( '#' + heightId ).prop('readonly',true);
+ $( '#' + widthId ).on('input',function() {
+ tempWidth = $(this).val();
+ tempHeight = Math.round(tempWidth/aspectRatio);
+ $( '#' + heightId ).val(tempHeight);
+ });
+ }
+ this.$activeWindow = $window;
+
+ if (e.type === 'keydown') {
+ if (e.key === 'Escape') { // escape
+ // hide the popup menu
+ $windowPopup.hide();
+ // also reset the Boolean
+ thisObj.windowMenuClickRegistered = false;
+ // also restore menu items to their original state
+ $windowPopup.find('li').removeClass('able-focus').attr('tabindex','-1');
+ $windowButton.attr('aria-expanded','false');
+ // also return focus to window options button
+ $windowButton.trigger('focus');
+
+ return false;
+ } else {
+ // all other keys will be handled by upstream functions
+ if (choice !== 'close') {
+ this.$activeWindow = $window;
+ }
+ return false;
+ }
+ }
+
+ // hide the popup menu
+ $windowPopup.hide();
+ // also reset the boolean
+ thisObj.windowMenuClickRegistered = false;
+ // also restore menu items to their original state
+ $windowPopup.find('li').removeClass('able-focus').attr('tabindex','-1');
+ $windowButton.attr('aria-expanded','false');
+
+ if (choice !== 'close') {
+ $windowButton.trigger('focus');
+ }
+ if (choice === 'move') {
+ // temporarily add role="application" to activeWindow
+ // otherwise, screen readers incercept arrow keys and moving window will not work
+ this.$activeWindow.attr('role','application');
+
+ if (!this.showedAlert(which)) {
+ this.showAlert( this.translate( 'windowMoveAlert', 'Drag or use arrow keys to move the window; Enter to stop' ),which);
+ if (which === 'transcript') {
+ this.showedTranscriptAlert = true;
+ } else if (which === 'sign') {
+ this.showedSignAlert = true;
+ }
+ }
+ this.dragDevice = (e.type === 'keydown') ? 'keyboard' : 'mouse';
+ this.startDrag(which, $window);
+ $windowPopup.hide().parent().attr( 'tabindex', '-1' ).trigger('focus');
+ } else if (choice == 'resize') {
+ // resize through the menu uses a form, not drag
+ var resizeFields = resizeDialog.getInputs();
+ if (resizeFields) {
+ // reset width and height values in form
+ resizeFields[0].value = Math.round( $window.outerWidth() );
+ resizeFields[1].value = Math.round( $window.outerHeight() );
+ }
+ resizeDialog.show();
+ } else if (choice == 'close') {
+ // close window, place focus on corresponding button on controller bar
+ if (which === 'transcript') {
+ this.closingTranscript = true; // stopgap to prevent double-firing of keypress
+ this.handleTranscriptToggle();
+ } else if (which === 'sign') {
+ this.closingSign = true; // stopgap to prevent double-firing of keypress
+ this.handleSignToggle();
+ }
+ }
+ };
+
+ AblePlayer.prototype.startDrag = function(which, $element) {
+
+ var thisObj, $windowPopup, startPos, newX, newY;
+
+ thisObj = this;
+
+ if (!this.$activeWindow) {
+ this.$activeWindow = $element;
+ }
+ this.dragging = true;
+
+ if (which === 'transcript') {
+ $windowPopup = this.$transcriptPopup;
+ } else if (which === 'sign') {
+ $windowPopup = this.$signPopup;
+ }
+
+ // if window's popup menu is open, close it
+ if ($windowPopup.is(':visible')) {
+ $windowPopup.hide();
+ }
+
+ // be sure this window is on top
+ this.updateZIndex(which);
+
+ // get starting position of element
+ startPos = this.$activeWindow.position();
+ this.dragStartX = startPos.left;
+ this.dragStartY = startPos.top;
+
+ if (typeof this.startMouseX === 'undefined') {
+ this.dragDevice = 'keyboard';
+ this.dragKeyX = this.dragStartX;
+ this.dragKeyY = this.dragStartY;
+ // add stopgap to prevent the Enter that triggered startDrag() from also triggering dragEnd()
+ this.startingDrag = true;
+ } else {
+ this.dragDevice = 'mouse';
+ // get offset between mouse position and top left corner of draggable element
+ this.dragOffsetX = this.startMouseX - this.dragStartX;
+ this.dragOffsetY = this.startMouseY - this.dragStartY;
+ }
+
+ // prepare element for dragging
+ this.$activeWindow.addClass('able-drag').css({
+ 'position': 'absolute',
+ 'top': this.dragStartY + 'px',
+ 'left': this.dragStartX + 'px'
+ }).trigger('focus');
+
+ // add device-specific event listeners
+ if (this.dragDevice === 'mouse') { // might also be a touchpad
+ $(document).on('mousemove touchmove',function(e) {
+ if (thisObj.dragging) {
+ // calculate new top left based on current mouse position - offset
+ newX = e.pageX - thisObj.dragOffsetX;
+ newY = e.pageY - thisObj.dragOffsetY;
+ thisObj.resetDraggedObject( newX, newY );
+ }
+ });
+ } else if (this.dragDevice === 'keyboard') {
+ this.$activeWindow.on('keydown',function(e) {
+ if (thisObj.dragging) {
+ thisObj.dragKeys(which, e);
+ }
+ });
+ }
+ return false;
+ };
+
+ /**
+ * Handle moving the transcript or sign window from the keyboard.
+ *
+ * @param {string} which 'transcript' or 'sign' window.
+ * @param {Event} e Triggered event.
+ */
+ AblePlayer.prototype.dragKeys = function(which, e) {
+
+ var key, keySpeed;
+
+ // stopgap to prevent firing on initial Enter or space
+ // that selected "Move" from menu
+ if (this.startingDrag) {
+ this.startingDrag = false;
+ return false;
+ }
+ key = e.key;
+ keySpeed = 10; // pixels per keypress event
+
+ switch (key) {
+ case 'ArrowLeft': // left
+ this.dragKeyX -= keySpeed;
+ this.$srAlertBox.text( this.translate( 'windowMoveLeft', 'Window moved left' ) );
+ break;
+ case 'ArrowUp': // up
+ this.dragKeyY -= keySpeed;
+ this.$srAlertBox.text( this.translate( 'windowMoveUp', 'Window moved up' ) );
+ break;
+ case 'ArrowRight': // right
+ this.dragKeyX += keySpeed;
+ this.$srAlertBox.text( this.translate( 'windowMoveRight', 'Window moved right' ) );
+ break;
+ case 'ArrowDown': // down
+ this.dragKeyY += keySpeed;
+ this.$srAlertBox.text( this.translate( 'windowMoveDown', 'Window moved down' ) );
+ break;
+ case 'Enter': // enter
+ case 'Escape': // escape
+ this.$srAlertBox.text( this.translate( 'windowMoveStopped', 'Window move stopped' ) );
+ this.endDrag(which);
+ return false;
+ default:
+ return false;
+ }
+ this.resetDraggedObject(this.dragKeyX,this.dragKeyY);
+ if (e.preventDefault) {
+ e.preventDefault();
+ }
+ return false;
+ };
+
+ AblePlayer.prototype.resetDraggedObject = function ( x, y) {
+ setTimeout( () => {
+ this.$srAlertBox.text( '' );
+ }, 2000 );
+
+ this.$activeWindow.css({
+ 'left': x + 'px',
+ 'top': y + 'px'
+ });
+ },
+
+ AblePlayer.prototype.resizeObject = function ( which, width, height ) {
+
+ var innerHeight;
+
+ // which is either 'transcript' or 'sign'
+ this.$activeWindow.css({
+ 'width': width + 'px',
+ 'height': height + 'px'
+ });
+
+ if (which === 'transcript') {
+ // $activeWindow is the outer $transcriptArea
+ // but the inner able-transcript also needs to be resized proportionally
+ // (it's 50px less than its outer container)
+ innerHeight = height - 50;
+ this.$transcriptDiv.css('height', innerHeight + 'px');
+ }
+ };
+
+ AblePlayer.prototype.endDrag = function(which) {
+
+ var thisObj, $windowButton;
+ thisObj = this;
+
+ if (which === 'transcript') {
+ $windowButton = this.$transcriptPopupButton;
+ } else if (which === 'sign') {
+ $windowButton = this.$signPopupButton;
+ }
+
+ $(document).off('mousemove mouseup touchmove touchup');
+ this.$activeWindow.off('keydown').removeClass('able-drag');
+ // restore activeWindow role from 'application' to 'dialog'
+ this.$activeWindow.attr('role','dialog');
+ this.$activeWindow = null;
+
+ if (this.dragDevice === 'keyboard') {
+ $windowButton.trigger('focus');
+ }
+ this.dragging = false;
+
+ // save final position of dragged element
+ this.updatePreferences(which);
+
+ // reset starting mouse positions
+ this.startMouseX = undefined;
+ this.startMouseY = undefined;
+
+ // Boolean to stop stray events from firing
+ this.windowMenuClickRegistered = false;
+ this.finishingDrag = true; // will be reset after window click event
+ // finishingDrag should be reset after window click event,
+ // which is triggered automatically after mouseup
+ // However, in case that's not reliable in some browsers
+ // need to ensure this gets cancelled
+ setTimeout(function() {
+ thisObj.finishingDrag = false;
+ }, 100);
+ };
+
+ AblePlayer.prototype.startResize = function(which, $element) {
+
+ var thisObj, $windowPopup, newWidth, newHeight;
+
+ thisObj = this;
+ this.$activeWindow = $element;
+ this.resizing = true;
+
+ $windowPopup = (which === 'transcript') ? this.$transcriptPopup : this.$signPopup;
+
+ // if window's popup menu is open, close it & place focus on button (???)
+ if ($windowPopup.is(':visible')) {
+ $windowPopup.hide().parent().trigger('focus');
+ }
+
+ // get starting width and height
+ this.dragKeyX = this.dragStartX;
+ this.dragKeyY = this.dragStartY;
+ this.dragStartWidth = this.$activeWindow.width();
+ this.dragStartHeight = this.$activeWindow.outerHeight();
+
+ // add event listeners
+ $(document).on('mousemove touchmove',function(e) {
+ if (thisObj.resizing) {
+ // calculate new width and height based on changes to mouse position
+ newWidth = thisObj.dragStartWidth + (e.pageX - thisObj.startMouseX);
+ newHeight = thisObj.dragStartHeight + (e.pageY - thisObj.startMouseY);
+ thisObj.resizeObject( which, newWidth, newHeight );
+ }
+ });
+
+ return false;
+ };
+
+ AblePlayer.prototype.endResize = function(which) {
+
+ var $windowButton;
+
+ if (which === 'transcript') {
+ $windowButton = this.$transcriptPopupButton;
+ } else if (which === 'sign') {
+ $windowButton = this.$signPopupButton;
+ }
+
+ $(document).off('mousemove mouseup touchmove touchup');
+ this.$activeWindow.off('keydown');
+ $windowButton.show().trigger('focus');
+ this.resizing = false;
+ this.$activeWindow.removeClass('able-resize');
+
+ // save final width and height of dragged element
+ this.updatePreferences(which);
+
+ // Booleans for preventing stray events
+ this.windowMenuClickRegistered = false;
+ this.finishingDrag = true;
+
+ // finishingDrag should e reset after window click event,
+ // which is triggered automatically after mouseup
+ // However, in case that's not reliable in some browsers
+ // need to ensure this gets cancelled
+ setTimeout(function() {
+ this.finishingDrag = false;
+ }, 100);
+ };
+ }
- loadingPromises = [];
+ function addEventFunctions(AblePlayer) {
+ // Media events
+ AblePlayer.prototype.onMediaUpdateTime = function (duration, elapsed) {
+
+ // duration and elapsed are passed from callback functions of Vimeo API events
+ // duration is expressed as sss.xxx
+ // elapsed is expressed as sss.xxx
+ var thisObj = this;
+ this.getMediaTimes(duration,elapsed).then(function(mediaTimes) {
+ thisObj.duration = mediaTimes['duration'];
+ thisObj.elapsed = mediaTimes['elapsed'];
+ if (thisObj.duration > 0) {
+ // do all the usual time-sync stuff during playback
+ if (thisObj.prefHighlight === 1) {
+ thisObj.highlightTranscript(thisObj.elapsed);
+ }
+ thisObj.updateCaption(thisObj.elapsed);
+ thisObj.showDescription(thisObj.elapsed);
+ thisObj.updateChapter(thisObj.elapsed);
+ thisObj.updateMeta(thisObj.elapsed);
+ thisObj.refreshControls('timeline', thisObj.duration, thisObj.elapsed);
+ }
+ });
+ };
+
+ AblePlayer.prototype.onMediaPause = function () {
+
+ if (this.controlsHidden) {
+ this.fadeControls('in');
+ this.controlsHidden = false;
+ }
+ if (this.hideControlsTimeoutStatus === 'active') {
+ window.clearTimeout(this.hideControlsTimeout);
+ this.hideControlsTimeoutStatus = 'clear';
+
+ }
+ this.refreshControls('playpause');
+ };
+
+ AblePlayer.prototype.onMediaComplete = function () {
+ // if there's a playlist, advance to next item and start playing
+ if (this.hasPlaylist && !this.cueingPlaylistItem) {
+ if (this.playlistIndex === (this.$playlist.length - 1)) {
+ // this is the last track in the playlist
+ if (this.loop) {
+ this.cueingPlaylistItem = true; // stopgap to prevent multiple firings
+ this.cuePlaylistItem(0);
+ } else {
+ this.playing = false;
+ this.paused = true;
+ }
+ } else {
+ // this is not the last track. Play the next one.
+ this.playlistIndex++;
+ this.cueingPlaylistItem = true; // stopgap to prevent multiple firings
+ this.cuePlaylistItem(this.playlistIndex);
+ }
+ }
+ this.refreshControls();
+ };
+
+ AblePlayer.prototype.onMediaNewSourceLoad = function () {
+
+ var loadIsComplete = false;
+
+ if (this.cueingPlaylistItem) {
+ // this variable was set to address bugs caused by multiple firings of media 'end' event
+ // safe to reset now
+ this.cueingPlaylistItem = false;
+ }
+ if (this.recreatingPlayer) {
+ // same as above; different bugs
+ this.recreatingPlayer = false;
+ }
+ if (this.playbackRate) {
+ // user has set playbackRate on a previous src or track
+ // use that setting on the new src or track too
+ this.setPlaybackRate(this.playbackRate);
+ }
+ if (this.userClickedPlaylist) {
+ if (!this.startedPlaying || this.okToPlay) {
+ // start playing; no further user action is required
+ this.playMedia();
+ loadIsComplete = true;
+ }
+ } else if (this.seekTrigger == 'restart' ||
+ this.seekTrigger == 'chapter' ||
+ this.seekTrigger == 'transcript' ||
+ this.seekTrigger == 'search'
+ ) {
+ // by clicking on any of these elements, user is likely intending to play
+ // Not included: elements where user might click multiple times in succession
+ // (i.e., 'rewind', 'forward', or seekbar); for these, video remains paused until user initiates play
+ this.playMedia();
+ loadIsComplete = true;
+ } else if (this.swappingSrc) {
+ // new source file has just been loaded
+ if (this.hasPlaylist) {
+ // a new source file from the playlist has just been loaded
+ if ((this.playlistIndex !== this.$playlist.length) || this.loop) {
+ // this is not the last track in the playlist (OR playlist is looping so it doesn't matter)
+ this.playMedia();
+ loadIsComplete = true;
+ }
+ } else if (this.swapTime > 0) {
+ if (this.seekStatus === 'complete') {
+ if (this.okToPlay) {
+ // should be able to resume playback
+ this.playMedia();
+ }
+ loadIsComplete = true;
+ } else if (this.seekStatus === 'seeking') ; else {
+ if (this.swapTime === this.elapsed) {
+ // seek is finished!
+ this.seekStatus = 'complete';
+ if (this.okToPlay) {
+ // should be able to resume playback
+ this.playMedia();
+ }
+ loadIsComplete = true;
+ } else {
+ // seeking hasn't started yet
+ // first, determine whether it's possible
+ if (this.hasDescTracks) {
+ // do nothing. Unable to seek ahead if there are descTracks
+ loadIsComplete = true;
+ } else if (this.durationsAreCloseEnough(this.duration,this.prevDuration)) {
+ // durations of two sources are close enough to making seek ahead in new source ok
+ this.seekStatus = 'seeking';
+ this.seekTo(this.swapTime);
+ } else {
+ // durations of two sources are too dissimilar to support seeking ahead to swapTime.
+ loadIsComplete = true;
+ }
+ }
+ }
+ } else {
+ // swapTime is 0. No seeking required.
+ if (this.playing) {
+ this.playMedia();
+ // swap is complete. Reset vars.
+ loadIsComplete = true;
+ }
+ }
+ } else if (!this.startedPlaying) {
+ if (this.startTime > 0) {
+ if (this.seeking) {
+ // a seek has already been initiated
+ // since canplaythrough has been triggered, the seek is complete
+ this.seeking = false;
+ if (this.okToPlay) {
+ this.playMedia();
+ }
+ loadIsComplete = true;
+ } else {
+ // haven't started seeking yet
+ this.seekTo(this.startTime);
+ }
+ } else if (this.defaultChapter && typeof this.selectedChapters !== 'undefined') {
+ this.seekToChapter(this.defaultChapter);
+ } else {
+ // there is no startTime, therefore no seeking required
+ if (this.okToPlay) {
+ this.playMedia();
+ }
+ loadIsComplete = true;
+ }
+ } else if (this.hasPlaylist) {
+ // new source media is part of a playlist, but user didn't click on it
+ // (and somehow, swappingSrc is false)
+ // this may happen when the previous track ends and next track loads
+ // this same code is called above when swappingSrc is true
+ if ((this.playlistIndex !== this.$playlist.length) || this.loop) {
+ // this is not the last track in the playlist (OR playlist is looping so it doesn't matter)
+ this.playMedia();
+ loadIsComplete = true;
+ }
+ } else {
+ // None of the above.
+ // User is likely seeking to a new time, but not loading a new media source
+ // need to reset vars
+ loadIsComplete = true;
+ }
+ if (loadIsComplete) {
+ // reset vars
+ this.swappingSrc = false;
+ this.seekStatus = null;
+ this.swapTime = 0;
+ this.seekTrigger = null;
+ this.seekingFromTranscript = false;
+ this.userClickedPlaylist = false;
+ this.okToPlay = false;
+ }
+ this.refreshControls();
+ if (this.$focusedElement) {
+ this.restoreFocus();
+ this.$focusedElement = null;
+ this.activeMedia = null;
+ }
+ };
+
+ AblePlayer.prototype.durationsAreCloseEnough = function(d1,d2) {
+
+ // Compare the durations of two media sources to determine whether it's ok to seek ahead after swapping src
+ // The durations may not be exact, but they might be "close enough"
+ // returns true if "close enough", otherwise false
+
+ var tolerance, diff;
+
+ tolerance = 1; // number of seconds between rounded durations that is considered "close enough"
+ diff = Math.abs(Math.round(d1) - Math.round(d2));
+
+ return (diff <= tolerance) ? true : false;
+ };
+
+ AblePlayer.prototype.restoreFocus = function() {
+
+ // function called after player has been rebuilt (during media swap)
+ // the original focusedElement no longer exists,
+ // but this function finds a match in the new player
+ // and places focus there
+
+ var classList, $mediaParent;
+
+ if ( this.$focusedElement && null !== this.activeMedia ) {
+ $mediaParent = $( '#' + this.activeMedia ).closest( '.able' );
+ if ( (this.$focusedElement).attr('role') === 'button' ) {
+ classList = this.$focusedElement.attr("class").split(/\s+/);
+ $.each(classList, function(index, item) {
+ if (item.substring(0,20) === 'able-button-handler-') {
+ $mediaParent.find('div.able-controller div.' + item).trigger('focus');
+ }
+ });
+ }
+ }
+
+ };
+
+ AblePlayer.prototype.addSeekbarListeners = function () {
+
+ var thisObj = this;
+
+ // Handle seek bar events.
+ this.seekBar.seekbarDiv.on('startTracking', function (e) {
+ thisObj.pausedBeforeTracking = thisObj.paused;
+ thisObj.pauseMedia();
+ }).on('tracking', function (e, position) {
+ // Scrub transcript, captions, and metadata.
+ thisObj.highlightTranscript(position);
+ thisObj.updateCaption(position);
+ thisObj.showDescription(position);
+ thisObj.updateChapter(thisObj.convertChapterTimeToVideoTime(position));
+ thisObj.updateMeta(position);
+ thisObj.refreshControls();
+ }).on('stopTracking', function (e, position) {
+ if (thisObj.useChapterTimes) {
+ thisObj.seekTo(thisObj.convertChapterTimeToVideoTime(position));
+ } else {
+ thisObj.seekTo(position);
+ }
+ if (!thisObj.pausedBeforeTracking) {
+ setTimeout(function () {
+ thisObj.playMedia();
+ }, 200);
+ }
+ });
+ };
+
+ AblePlayer.prototype.onClickPlayerButton = function (el) {
+ var whichButton, prefsPopup;
+ whichButton = this.getButtonNameFromClass($(el).attr('class'));
+ switch ( whichButton ) {
+ case 'play':
+ this.clickedPlay = true;
+ this.handlePlay();
+ break;
+ case 'restart':
+ this.seekTrigger = 'restart';
+ this.handleRestart();
+ break;
+ case 'previous':
+ this.userClickedPlaylist = true;
+ this.okToPlay = true;
+ this.seekTrigger = 'previous';
+ this.buttonWithFocus = 'previous';
+ this.handlePrevTrack();
+ break;
+ case 'next':
+ this.userClickedPlaylist = true;
+ this.okToPlay = true;
+ this.seekTrigger = 'next';
+ this.buttonWithFocus = 'next';
+ this.handleNextTrack();
+ break;
+ case 'rewind':
+ this.seekTrigger = 'rewind';
+ this.handleRewind();
+ break;
+ case 'forward':
+ this.seekTrigger = 'forward';
+ this.handleFastForward();
+ break;
+ case 'mute':
+ this.handleMute();
+ break;
+ case 'volume':
+ this.handleVolumeButtonClick();
+ break;
+ case 'faster':
+ this.handleRateIncrease();
+ break;
+ case 'slower':
+ this.handleRateDecrease();
+ break;
+ case 'captions':
+ this.handleCaptionToggle();
+ break;
+ case 'chapters':
+ this.handleChapters();
+ break;
+ case 'descriptions':
+ this.handleDescriptionToggle();
+ break;
+ case 'sign':
+ if ( ! this.closingSign ) {
+ this.handleSignToggle();
+ }
+ break;
+ case 'preferences':
+ if ($(el).attr('data-prefs-popup') === 'menu') {
+ this.handlePrefsClick();
+ } else {
+ this.showingPrefsDialog = true; // stopgap
+ this.closePopups();
+ prefsPopup = $(el).attr('data-prefs-popup');
+ if (prefsPopup === 'keyboard') {
+ this.keyboardPrefsDialog.show();
+ } else if (prefsPopup === 'captions') {
+ this.captionPrefsDialog.show();
+ } else if (prefsPopup === 'descriptions') {
+ this.descPrefsDialog.show();
+ } else if (prefsPopup === 'transcript') {
+ this.transcriptPrefsDialog.show();
+ }
+ this.showingPrefsDialog = false;
+ }
+ break;
+ case 'transcript':
+ if ( !this.closingTranscript ) {
+ this.handleTranscriptToggle();
+ }
+ break;
+ case 'fullscreen':
+ this.clickedFullscreenButton = true;
+ this.handleFullscreenToggle();
+ break;
+ }
+ };
+
+ AblePlayer.prototype.getButtonNameFromClass = function (classString) {
+ // player control buttons all have class="able-button-handler-x" where x is the identifier
+ // buttons might also have other classes assigned though
+ var classes, i;
+
+ classes = classString.split(' ');
+ for (i = 0; i < classes.length; i++) {
+ if (classes[i].substring(0,20) === 'able-button-handler-') {
+ return classes[i].substring(20);
+ }
+ }
+ return classString;
+ };
+
+ AblePlayer.prototype.okToHandleKeyPress = function () {
+ let defaultReturn = true;
+ if ( this.prefNoKeyShortcuts === 1 ) {
+ defaultReturn = false;
+ }
+ // returns true unless user's focus is on a UI element or user has disabled keyboard shortcuts.
+ // that is likely to need supported keystrokes, including space
+ var activeElement = AblePlayer.getActiveDOMElement();
+
+ return ($(activeElement).prop('tagName') === 'INPUT') ? false : defaultReturn;
+ };
+
+ AblePlayer.prototype.onPlayerKeyPress = function (e) {
+
+ // handle keystrokes (using DHTML Style Guide recommended key combinations)
+ // https://web.archive.org/web/20130127004544/http://dev.aol.com/dhtml_style_guide/#mediaplayer
+ // Modifier keys Alt + Ctrl are on by default, but can be changed within Preferences
+ // - Style guide only supports Play/Pause, Stop, Mute, Captions, & Volume Up & Down
+ // The rest are reasonable best choices
+ // - If there are multiple players on a single page, keystroke handlers
+ // are only bound to the FIRST player
+ // - The DHTML Style Guide is now the W3C WAI-ARIA Authoring Guide and has undergone many revisions
+ // including removal of the "media player" design pattern. There's an issue about that:
+ // https://github.com/w3c/aria-practices/issues/27
+
+ var key, $thisElement;
+
+ // Convert to lower case.
+ key = e.key;
+ $thisElement = $(document.activeElement);
+
+ if (key === 'Escape') {
+ if (this.$transcriptArea && $.contains(this.$transcriptArea[0],$thisElement[0]) && !this.hidingPopup) {
+ // This element is part of transcript area.
+ this.handleTranscriptToggle();
+ return false;
+ }
+ }
+ if (!this.okToHandleKeyPress()) {
+ return false;
+ }
+
+ // Only use keypress to control player if focus is NOT on a form field or contenteditable element
+ // (or a textarea element with player in stenoMode)
+ if (!(
+ $(':focus').is('[contenteditable]') ||
+ $(':focus').is('input') ||
+ ($(':focus').is('textarea') && !this.stenoMode) ||
+ $(':focus').is('select') ||
+ e.target.hasAttribute('contenteditable') ||
+ e.target.tagName === 'INPUT' ||
+ (e.target.tagName === 'TEXTAREA' && !this.stenoMode) ||
+ e.target.tagName === 'SELECT'
+ )){
+ if (key === 'Escape') {
+ this.closePopups();
+ this.$tooltipDiv.hide();
+ this.seekBar.hideSliderTooltips();
+ } else if (key === ' ') {
+ // disable spacebar support for play/pause toggle as of 4.2.10
+ // spacebar should not be handled everywhere on the page, since users use that to scroll the page
+ // when the player has focus, most controls are buttons so spacebar should be used to trigger the buttons
+ if ($thisElement.attr('role') === 'button') {
+ // register a click on this element
+ e.preventDefault();
+ $thisElement.trigger( 'click' );
+ }
+ } else if ( key === 'p' ) {
+ if (this.usingModifierKeys(e)) {
+ e.preventDefault();
+ this.handlePlay();
+ }
+ } else if (key === 's') {
+ if (this.usingModifierKeys(e)) {
+ e.preventDefault();
+ this.handleRestart();
+ }
+ } else if (key === 'm') {
+ if (this.usingModifierKeys(e)) {
+ e.preventDefault();
+ this.handleMute();
+ }
+ } else if (key === 'v') {
+ if (this.usingModifierKeys(e)) {
+ e.preventDefault();
+ this.handleVolumeButtonClick();
+ }
+ } else if (key >= 0 && key <= 9) {
+ if (this.usingModifierKeys(e)) {
+ e.preventDefault();
+ this.handleVolumeKeystroke(key);
+ }
+ } else if (key === 'c') {
+ if (this.usingModifierKeys(e)) {
+ e.preventDefault();
+ this.handleCaptionToggle();
+ }
+ } else if (key === 'd') {
+ if (this.usingModifierKeys(e)) {
+ e.preventDefault();
+ this.handleDescriptionToggle();
+ }
+ } else if (key === 'f') {
+ if (this.usingModifierKeys(e)) {
+ e.preventDefault();
+ this.handleFastForward();
+ }
+ } else if (key === 'r') {
+ if (this.usingModifierKeys(e)) {
+ e.preventDefault();
+ this.handleRewind();
+ }
+ } else if (key === 'b') {
+ if (this.usingModifierKeys(e)) {
+ e.preventDefault();
+ this.handlePrevTrack();
+ }
+ } else if (key === 'n') {
+ if (this.usingModifierKeys(e)) {
+ e.preventDefault();
+ this.handleNextTrack();
+ }
+ } else if (key === 'e') {
+ if (this.usingModifierKeys(e)) {
+ e.preventDefault();
+ this.handlePrefsClick();
+ }
+ } else if (key === 'Enter') {
+ if ($thisElement.attr('role') === 'button' || $thisElement.prop('tagName') === 'SPAN') {
+ // register a click on this element
+ // if it's a transcript span the transcript span click handler will take over
+ $thisElement.trigger( 'click' );
+ } else if ($thisElement.prop('tagName') === 'LI') {
+ $thisElement.trigger( 'click' );
+ }
+ }
+ }
+ };
+
+ AblePlayer.prototype.addHtml5MediaListeners = function () {
+
+ var thisObj = this;
+
+ // NOTE: iOS and some browsers do not support autoplay
+ // and no events are triggered until media begins to play
+ // Able Player gets around this by automatically loading media in some circumstances
+ // (see initialize.js > initPlayer() for details)
+
+ this.$media
+ .on('emptied',function() {
+ // do something
+ })
+ .on('loadedmetadata',function() {
+ // should be able to get duration now
+ thisObj.duration = thisObj.media.duration;
+ })
+ .on('canplay',function() {
+ // previously handled seeking to startTime here
+ // but it's probably safer to wait for canplaythrough
+ // so we know player can seek ahead to anything
+ })
+ .on('canplaythrough',function() {
+ // previously onMediaNewSourceLoad() was called on 'loadedmetadata'
+ // but that proved to be too soon for some of this functionality.
+ // TODO: Monitor this. If moving it here causes performance issues,
+ // consider moving some or all of this functionality to 'canplay'
+ thisObj.onMediaNewSourceLoad();
+ })
+ .on('play',function() {
+ // 'play' indicates that the play method has been called.
+ // Don't do anything until playback has actually started.
+ })
+ .on('playing',function() {
+ // 'playing' indicates that the video is playing.
+ thisObj.playing = true;
+ thisObj.paused = false;
+ thisObj.swappingSrc = false;
+ thisObj.refreshControls('playpause');
+ })
+ .on('ended',function() {
+ thisObj.playing = false;
+ thisObj.paused = true;
+ thisObj.onMediaComplete();
+ })
+ .on('progress', function() {
+ thisObj.refreshControls('timeline');
+ })
+ .on('waiting',function() {
+ // could fire a notification about loss of data.
+ })
+ .on('durationchange',function() {
+ // Display new duration.
+ thisObj.refreshControls('timeline');
+ })
+ .on('timeupdate',function() {
+ thisObj.onMediaUpdateTime(); // includes a call to refreshControls()
+ })
+ .on('pause',function() {
+ if (!thisObj.clickedPlay) {
+ // 'pause' was triggered automatically, not initiated by user
+ // this happens in some browsers when swapping source
+ // (e.g., between tracks in a playlist or swapping description)
+ if (thisObj.hasPlaylist || thisObj.swappingSrc) ; else {
+ thisObj.playing = false;
+ thisObj.paused = true;
+ }
+ } else {
+ thisObj.playing = false;
+ thisObj.paused = true;
+ }
+ thisObj.clickedPlay = false; // done with this variable
+ thisObj.onMediaPause(); // includes a call to refreshControls()
+ })
+ .on('ratechange',function() {
+ // do something
+ })
+ .on('volumechange',function() {
+ thisObj.volume = thisObj.getVolume();
+ })
+ .on('error',function() {
+ if (thisObj.debug) {
+ switch (thisObj.media.error.code) {
+ }
+ }
+ });
+ };
+
+ AblePlayer.prototype.addVimeoListeners = function () {
+
+ var thisObj = this;
+
+ // Vimeo doesn't seem to support chaining of on() functions
+ // so each event listener must be attached separately
+ this.vimeoPlayer.on('loaded', function(vimeoId) {
+ // Triggered when a new video is loaded in the player
+ thisObj.onMediaNewSourceLoad();
+ });
+ this.vimeoPlayer.on('play', function(e) {
+ // Triggered when the video plays
+ thisObj.playing = true;
+ thisObj.startedPlaying = true;
+ thisObj.paused = false;
+ thisObj.refreshControls('playpause');
+ });
+ this.vimeoPlayer.on('ended', function(e) {
+ // Triggered any time the video playback reaches the end.
+ // Note: when loop is turned on, the ended event will not fire.
+ thisObj.playing = false;
+ thisObj.paused = true;
+ thisObj.onMediaComplete();
+ });
+ this.vimeoPlayer.on('bufferstart', function() {
+ // Triggered when buffering starts in the player.
+ // This is also triggered during preload and while seeking.
+ // There is no associated data with this event.
+ });
+ this.vimeoPlayer.on('bufferend', function() {
+ // Triggered when buffering ends in the player.
+ // This is also triggered at the end of preload and seeking.
+ // There is no associated data with this event.
+ });
+ this.vimeoPlayer.on('progress', function(e) {
+ // Triggered as the video is loaded.
+ // Reports back the amount of the video that has been buffered (NOT the amount played)
+ // Data has keys duration, percent, and seconds
+ });
+ this.vimeoPlayer.on('seeking', function(e) {
+ // Triggered when the player starts seeking to a specific time.
+ // A timeupdate event will also be fired at the same time.
+ });
+ this.vimeoPlayer.on('seeked', function(e) {
+ // Triggered when the player seeks to a specific time.
+ // A timeupdate event will also be fired at the same time.
+ });
+ this.vimeoPlayer.on('timeupdate',function(e) {
+ // Triggered as the currentTime of the video updates.
+ // It generally fires every 250ms, but it may vary depending on the browser.
+ thisObj.onMediaUpdateTime(e['duration'], e['seconds']);
+ });
+ this.vimeoPlayer.on('pause',function(e) {
+ // Triggered when the video pauses
+ if (!thisObj.clickedPlay) {
+ // 'pause' was triggered automatically, not initiated by user
+ // this happens in some browsers (not Chrome, as of 70.x)
+ // when swapping source (e.g., between tracks in a playlist, or swapping description)
+ if (thisObj.hasPlaylist || thisObj.swappingSrc) ; else {
+ thisObj.playing = false;
+ thisObj.paused = true;
+ }
+ } else {
+ thisObj.playing = false;
+ thisObj.paused = true;
+ }
+ thisObj.clickedPlay = false; // done with this variable
+ thisObj.onMediaPause();
+ thisObj.refreshControls('playpause');
+ });
+ this.vimeoPlayer.on('playbackratechange',function(e) {
+ // Triggered when the playback rate of the video in the player changes.
+ // The ability to change rate can be disabled by the creator
+ // and the event will not fire for those videos.
+ // data contains one key: 'playbackRate'
+ thisObj.vimeoPlaybackRate = e['playbackRate'];
+ });
+ this.vimeoPlayer.on('texttrackchange', function(e) {
+ // Triggered when the active text track (captions/subtitles) changes.
+ // The values will be null if text tracks are turned off.
+ // data contains three keys: kind, label, language
+ });
+ this.vimeoPlayer.on('volumechange',function(e) {
+ // Triggered when the volume in the player changes.
+ // Some devices do not support setting the volume of the video
+ // independently from the system volume,
+ // so this event will never fire on those devices.
+ thisObj.volume = e['volume'] * 10;
+ });
+ this.vimeoPlayer.on('error',function(e) {
+ // do something with the available data
+ // data contains three keys: message, method, name
+ // message: A user-friendly error message
+ // method: The Vimeo API method call that triggered the error
+ // name: Name of the error (not necesssarily user-friendly)
+ });
+ };
+
+ AblePlayer.prototype.addEventListeners = function () {
+
+ var thisObj = this;
+
+ // Appropriately resize media player for full screen.
+ $(window).on('resize',function () {
+ thisObj.resizePlayer();
+ });
+
+ // Refresh player if it changes from hidden to visible
+ // There is no event triggered by a change in visibility
+ // but MutationObserver works in most browsers (but NOT in IE 10 or earlier)
+ // http://caniuse.com/#feat=mutationobserver
+ if (window.MutationObserver) {
+ var target = this.$ableDiv[0];
+ var observer = new MutationObserver(function(mutations) {
+ mutations.forEach(function(mutation) {
+ if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
+ // the player's style attribute has changed. Check to see if it's visible
+ if (thisObj.$ableDiv.is(':visible')) {
+ thisObj.refreshControls();
+ }
+ }
+ });
+ });
+ var config = { attributes: true, childList: true, characterData: true };
+ observer.observe(target, config);
+ }
+ if (typeof this.seekBar !== 'undefined') {
+ this.addSeekbarListeners();
+ } else {
+ // wait a bit and try again
+ // TODO: Should set this up to keep trying repeatedly.
+ // Seekbar listeners are critical.
+ setTimeout(function() {
+ if (typeof thisObj.seekBar !== 'undefined') {
+ thisObj.addSeekbarListeners();
+ }
+ },2000);
+ }
+
+ // handle clicks on player buttons
+ this.$controllerDiv.find('div[role="button"]').on('click',function(e){
+ e.stopPropagation();
+ thisObj.onClickPlayerButton(this);
+ });
+
+ // handle clicks (left only) anywhere on the page. If any popups are open, close them.
+ $('body').on('click', function(e) {
+
+ if (e.button !== 0) { // not a left click
+ return false;
+ }
+ if ($('.able-popup:visible').length || $('.able-volume-slider:visible').length ) {
+ // at least one popup is visible
+ thisObj.closePopups();
+ }
+ if (e.target.tagName === 'VIDEO') {
+ // user clicked the video (not an element that sits on top of the video)
+ // handle this as a play/pause toggle click
+ thisObj.clickedPlay = true;
+ }
+ });
+
+ // handle mouse movement over player; make controls visible again if hidden
+ this.$ableDiv.on('mousemove',function() {
+ if (thisObj.controlsHidden) {
+ thisObj.fadeControls('in');
+ thisObj.controlsHidden = false;
+ // if there's already an active timeout, clear it and start timer again
+ if (thisObj.hideControlsTimeoutStatus === 'active') {
+ window.clearTimeout(thisObj.hideControlsTimeout);
+ thisObj.hideControlsTimeoutStatus = 'clear';
+ }
+ if (thisObj.hideControls) {
+ // after showing controls, hide them again after a brief timeout
+ thisObj.invokeHideControlsTimeout();
+ }
+ } else {
+ // if there's already an active timeout, clear it and start timer again
+ if (thisObj.hideControlsTimeoutStatus === 'active') {
+ window.clearTimeout(thisObj.hideControlsTimeout);
+ thisObj.hideControlsTimeoutStatus = 'clear';
+ if (thisObj.hideControls) {
+ thisObj.invokeHideControlsTimeout();
+ }
+ }
+ }
+ });
+
+ // if user presses a key from anywhere on the page, show player controls
+ $(document).on( 'keydown', function(e) {
+ if (thisObj.controlsHidden) {
+ thisObj.fadeControls('in');
+ thisObj.controlsHidden = false;
+ if (thisObj.hideControlsTimeoutStatus === 'active') {
+ window.clearTimeout(thisObj.hideControlsTimeout);
+ thisObj.hideControlsTimeoutStatus = 'clear';
+ }
+ if (thisObj.hideControls) {
+ // after showing controls, hide them again after a brief timeout
+ thisObj.invokeHideControlsTimeout();
+ }
+ } else {
+ // controls are visible
+ // if there's already an active timeout, clear it and start timer again
+ if (thisObj.hideControlsTimeoutStatus === 'active') {
+ window.clearTimeout(thisObj.hideControlsTimeout);
+ thisObj.hideControlsTimeoutStatus = 'clear';
+
+ if (thisObj.hideControls) {
+ thisObj.invokeHideControlsTimeout();
+ }
+ }
+ }
+ });
+
+ // handle local keydown events if this isn't the only player on the page;
+ // otherwise these are dispatched by global handler (see ableplayer-base.js)
+ this.$ableDiv.on( 'keydown', function (e) {
+ if (!AblePlayer.hasSingleInstance()) {
+ thisObj.onPlayerKeyPress(e);
+ }
+ });
+
+ // If stenoMode is enabled in an iframe, handle keydown events from the iframe
+ if (this.stenoMode && (typeof this.stenoFrameContents !== 'undefined')) {
+ this.stenoFrameContents.on('keydown',function(e) {
+ thisObj.onPlayerKeyPress(e);
+ });
+ }
+ // transcript is not a child of this.$ableDiv
+ // therefore, must be added separately
+ if (this.$transcriptArea) {
+ this.$transcriptArea.on('keydown',function (e) {
+ if (!AblePlayer.hasSingleInstance()) {
+ thisObj.onPlayerKeyPress(e);
+ }
+ });
+ }
+
+ // handle clicks on playlist items
+ if (this.$playlist) {
+ this.$playlist.on( 'click', function(e) {
+ if (!thisObj.userClickedPlaylist) {
+ // stopgap in case multiple clicks are fired on the same playlist item
+ thisObj.userClickedPlaylist = true; // will be set to false after new src is loaded & canplaythrough is triggered
+ thisObj.playlistIndex = $(this).index();
+ thisObj.cuePlaylistItem(thisObj.playlistIndex);
+ }
+ });
+ }
+
+ // Also play/pause when clicking on the media.
+ this.$media.on( 'click', function () {
+ thisObj.handlePlay();
+ });
+
+ // add listeners for media events
+ if (this.player === 'html5') {
+ this.addHtml5MediaListeners();
+ } else if (this.player === 'vimeo') {
+ this.addVimeoListeners();
+ } else if (this.player === 'youtube') {
+ // Youtube doesn't give us time update events, so we just periodically generate them ourselves
+ setInterval(function () {
+ thisObj.onMediaUpdateTime();
+ }, 300);
+ }
+ };
+ }
- if ($("#able-vts").length) {
- this.vtsTracks = [];
- this.hasVts = true;
- } else {
- this.hasVts = false;
- }
+ function addInitializeFunctions(AblePlayer) {
+ // Set default variable values.
+ AblePlayer.prototype.setDefaults = function () {
+
+ this.playerCreated = false; // will set to true after recreatePlayer() is complete the first time
+ this.playing = false; // will change to true after 'playing' event is triggered
+ this.paused = true; // will always be the opposite of this.playing (available for convenience)
+ this.clickedPlay = false; // will change to true temporarily if user clicks 'play' (or pause)
+ this.fullscreen = false; // will change to true if player is in full screen mode
+ this.swappingSrc = false; // will change to true temporarily while media source is being swapped
+ this.initializing = false; // will change to true temporarily while initPlayer() is processing
+ this.cueingPlaylistItems = false; // will change to true temporarily while cueing next playlist item
+ this.buttonWithFocus = null; // will change to 'previous' or 'next' if user clicks either of those buttons
+ this.speechEnabled = null; // will change either to 'true' in initSpeech(), or false if not supported
+
+ this.setIconColor();
+ };
+
+ AblePlayer.prototype.setIconColor = function() {
+
+ // determine the best color choice (white or black) for icons,
+ // given the background-color of their container elements
+ // Source for relative luminance formula:
+ // https://en.wikipedia.org/wiki/Relative_luminance
+
+ // We need to know the color *before* creating the element
+ // so the element doesn't exist yet when this function is called
+ // therefore, need to create a temporary element then remove it after color is determined
+ // Temp element must be added to the DOM or WebKit can't retrieve its CSS properties
+
+ var $elements, i, $el, bgColor, rgb, red, green, blue, luminance, iconColor;
+
+ $elements = ['controller', 'toolbar'];
+ for (i=0; i<$elements.length; i++) {
+ if ($elements[i] == 'controller') {
+ $el = $('', {
+ 'class': 'able-controller'
+ }).hide();
+ } else if ($elements[i] === 'toolbar') {
+ $el = $('
', {
+ 'class': 'able-window-toolbar'
+ }).hide();
+ }
+ $('body').append($el);
+ bgColor = $el.css('background-color');
+ // bgColor is a string in the form 'rgb(R, G, B)', perhaps with a 4th item for alpha;
+ // split the 3 or 4 channels into an array
+ rgb = bgColor.replace(/[^\d,]/g, '').split(',');
+ red = rgb[0];
+ green = rgb[1];
+ blue = rgb[2];
+ luminance = (0.2126 * red) + (0.7152 * green) + (0.0722 * blue);
+ // range is 1 - 255; therefore 125 is the tipping point
+ iconColor = (luminance < 125) ? 'white' : 'black';
+
+ if ($elements[i] === 'controller') {
+ this.iconColor = iconColor;
+ } else if ($elements[i] === 'toolbar') {
+ this.toolbarIconColor = iconColor;
+ }
+ $el.remove();
+ }
+ };
+
+ AblePlayer.prototype.getIconData = function(button) {
+
+ // returns array of values for creating
tag for specified button
+ // 0 = viewBox attribute
+ // 1 = d (description) attribute
+ // 2 = icon class for font icons
+ // 3 = img URL for images.
+ var svg = Array();
+
+ switch (button) {
+
+ case 'play':
+ svg[0] = '0 0 16 20';
+ svg[1] = 'M0 18.393v-16.429q0-0.29 0.184-0.402t0.441 0.033l14.821 8.237q0.257 0.145 0.257 0.346t-0.257 0.346l-14.821 8.237q-0.257 0.145-0.441 0.033t-0.184-0.402z';
+ break;
+
+ case 'pause':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M0 18.036v-15.714q0-0.29 0.212-0.502t0.502-0.212h5.714q0.29 0 0.502 0.212t0.212 0.502v15.714q0 0.29-0.212 0.502t-0.502 0.212h-5.714q-0.29 0-0.502-0.212t-0.212-0.502zM10 18.036v-15.714q0-0.29 0.212-0.502t0.502-0.212h5.714q0.29 0 0.502 0.212t0.212 0.502v15.714q0 0.29-0.212 0.502t-0.502 0.212h-5.714q-0.29 0-0.502-0.212t-0.212-0.502z';
+ break;
+
+ case 'restart':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M18 8h-6l2.243-2.243c-1.133-1.133-2.64-1.757-4.243-1.757s-3.109 0.624-4.243 1.757c-1.133 1.133-1.757 2.64-1.757 4.243s0.624 3.109 1.757 4.243c1.133 1.133 2.64 1.757 4.243 1.757s3.109-0.624 4.243-1.757c0.095-0.095 0.185-0.192 0.273-0.292l1.505 1.317c-1.466 1.674-3.62 2.732-6.020 2.732-4.418 0-8-3.582-8-8s3.582-8 8-8c2.209 0 4.209 0.896 5.656 2.344l2.344-2.344v6z';
+ break;
+
+ case 'rewind':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M11.25 3.125v6.25l6.25-6.25v13.75l-6.25-6.25v6.25l-6.875-6.875z';
+ break;
+
+ case 'forward':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M10 16.875v-6.25l-6.25 6.25v-13.75l6.25 6.25v-6.25l6.875 6.875z';
+ break;
+
+ case 'previous':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M5 17.5v-15h2.5v6.875l6.25-6.25v13.75l-6.25-6.25v6.875z';
+ break;
+
+ case 'next':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M15 2.5v15h-2.5v-6.875l-6.25 6.25v-13.75l6.25 6.25v-6.875z';
+ break;
+
+ case 'slower':
+ svg[0] = '0 0 11 20';
+ svg[1] = 'M0 7.321q0-0.29 0.212-0.502t0.502-0.212h10q0.29 0 0.502 0.212t0.212 0.502-0.212 0.502l-5 5q-0.212 0.212-0.502 0.212t-0.502-0.212l-5-5q-0.212-0.212-0.212-0.502z';
+ break;
+
+ case 'faster':
+ svg[0] = '0 0 11 20';
+ svg[1] = 'M0 12.411q0-0.29 0.212-0.502l5-5q0.212-0.212 0.502-0.212t0.502 0.212l5 5q0.212 0.212 0.212 0.502t-0.212 0.502-0.502 0.212h-10q-0.29 0-0.502-0.212t-0.212-0.502z';
+ break;
+
+ case 'turtle':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M17.212 3.846c-0.281-0.014-0.549 0.025-0.817 0.144-1.218 0.542-1.662 2.708-2.163 3.942-1.207 2.972-7.090 4.619-11.755 5.216-0.887 0.114-1.749 0.74-2.428 1.466 0.82-0.284 2.126-0.297 2.74 0.144 0.007 0.488-0.376 1.062-0.625 1.37-0.404 0.5-0.398 0.793 0.12 0.793 0.473 0 0.752 0.007 1.635 0 0.393-0.003 0.618-0.16 1.49-1.49 3.592 0.718 5.986-0.264 5.986-0.264s0.407 1.755 1.418 1.755h1.49c0.633 0 0.667-0.331 0.625-0.433-0.448-1.082-0.68-1.873-0.769-2.5-0.263-1.857 0.657-3.836 2.524-5.457 0.585 0.986 2.253 0.845 2.909-0.096s0.446-2.268-0.192-3.221c-0.49-0.732-1.345-1.327-2.188-1.37zM8.221 4.663c-0.722-0.016-1.536 0.111-2.5 0.409-4.211 1.302-4.177 4.951-3.51 5.745 0 0-0.955 0.479-0.409 1.274 0.448 0.652 3.139 0.191 5.409-0.529s4.226-1.793 5.312-2.692c0.948-0.785 0.551-2.106-0.505-1.947-0.494-0.98-1.632-2.212-3.798-2.26zM18.846 5.962c0.325 0 0.577 0.252 0.577 0.577s-0.252 0.577-0.577 0.577c-0.325 0-0.577-0.252-0.577-0.577s0.252-0.577 0.577-0.577z';
+ break;
+
+ case 'rabbit':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M10.817 0c-2.248 0-1.586 0.525-1.154 0.505 1.551-0.072 5.199 0.044 6.851 2.428 0 0-1.022-2.933-5.697-2.933zM10.529 0.769c-2.572 0-2.837 0.51-2.837 1.106 0 0.545 1.526 0.836 2.524 0.697 2.778-0.386 4.231-0.12 5.264 0.865-1.010 0.779-0.75 1.401-1.274 1.851-1.093 0.941-2.643-0.673-4.976-0.673-2.496 0-4.712 1.92-4.712 4.76-0.157-0.537-0.769-0.913-1.442-0.913-0.974 0-1.514 0.637-1.514 1.49 0 0.769 1.13 1.791 2.861 0.938 0.499 1.208 2.265 1.364 2.452 1.418 0.538 0.154 1.875 0.098 1.875 0.865 0 0.794-1.034 1.094-1.034 1.707 0 1.070 1.758 0.873 2.284 1.034 1.683 0.517 2.103 1.214 2.788 2.212 0.771 1.122 2.572 1.408 2.572 0.625 0-3.185-4.413-4.126-4.399-4.135 0.608-0.382 2.139-1.397 2.139-3.534 0-1.295-0.703-2.256-1.755-2.861 1.256 0.094 2.572 1.205 2.572 2.74 0 1.877-0.653 2.823-0.769 2.957 1.975-1.158 3.193-3.91 3.029-6.37 0.61 0.401 1.27 0.577 1.971 0.625 0.751 0.052 1.475-0.225 1.635-0.529 0.38-0.723 0.162-2.321-0.12-2.837-0.763-1.392-2.236-1.73-3.606-1.683-1.202-1.671-3.812-2.356-5.529-2.356zM1.37 3.077l-0.553 1.538h3.726c0.521-0.576 1.541-1.207 2.284-1.538h-5.457zM18.846 5.192c0.325 0 0.577 0.252 0.577 0.577s-0.252 0.577-0.577 0.577c-0.325 0-0.577-0.252-0.577-0.577s0.252-0.577 0.577-0.577zM0.553 5.385l-0.553 1.538h3.197c0.26-0.824 0.586-1.328 0.769-1.538h-3.413z';
+ break;
+
+ case 'ellipsis':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M10.001 7.8c-1.215 0-2.201 0.985-2.201 2.2s0.986 2.2 2.201 2.2c1.215 0 2.199-0.985 2.199-2.2s-0.984-2.2-2.199-2.2zM3.001 7.8c-1.215 0-2.201 0.985-2.201 2.2s0.986 2.2 2.201 2.2c1.215 0 2.199-0.986 2.199-2.2s-0.984-2.2-2.199-2.2zM17.001 7.8c-1.215 0-2.201 0.985-2.201 2.2s0.986 2.2 2.201 2.2c1.215 0 2.199-0.985 2.199-2.2s-0.984-2.2-2.199-2.2z';
+ break;
+
+ case 'pipe':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M10.15 0.179h0.623c0.069 0 0.127 0.114 0.127 0.253v19.494c0 0.139-0.057 0.253-0.127 0.253h-1.247c-0.069 0-0.126-0.114-0.126-0.253v-19.494c0-0.139 0.057-0.253 0.126-0.253h0.623z';
+ break;
+
+ case 'captions':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M0.033 3.624h19.933v12.956h-19.933v-12.956zM18.098 10.045c-0.025-2.264-0.124-3.251-0.743-3.948-0.112-0.151-0.322-0.236-0.496-0.344-0.606-0.386-3.465-0.526-6.782-0.526s-6.313 0.14-6.907 0.526c-0.185 0.108-0.396 0.193-0.519 0.344-0.607 0.697-0.693 1.684-0.731 3.948 0.037 2.265 0.124 3.252 0.731 3.949 0.124 0.161 0.335 0.236 0.519 0.344 0.594 0.396 3.59 0.526 6.907 0.547 3.317-0.022 6.176-0.151 6.782-0.547 0.174-0.108 0.384-0.183 0.496-0.344 0.619-0.697 0.717-1.684 0.743-3.949v0 0zM9.689 9.281c-0.168-1.77-1.253-2.813-3.196-2.813-1.773 0-3.168 1.387-3.168 3.617 0 2.239 1.271 3.636 3.372 3.636 1.676 0 2.851-1.071 3.035-2.852h-2.003c-0.079 0.661-0.397 1.168-1.068 1.168-1.059 0-1.253-0.91-1.253-1.876 0-1.33 0.442-2.010 1.174-2.010 0.653 0 1.068 0.412 1.13 1.129h1.977zM16.607 9.281c-0.167-1.77-1.252-2.813-3.194-2.813-1.773 0-3.168 1.387-3.168 3.617 0 2.239 1.271 3.636 3.372 3.636 1.676 0 2.851-1.071 3.035-2.852h-2.003c-0.079 0.661-0.397 1.168-1.068 1.168-1.059 0-1.253-0.91-1.253-1.876 0-1.33 0.441-2.010 1.174-2.010 0.653 0 1.068 0.412 1.13 1.129h1.976z';
+ break;
+
+ case 'descriptions':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M17.623 3.57h-1.555c1.754 1.736 2.763 4.106 2.763 6.572 0 2.191-0.788 4.286-2.189 5.943h1.484c1.247-1.704 1.945-3.792 1.945-5.943-0-2.418-0.886-4.754-2.447-6.572v0zM14.449 3.57h-1.55c1.749 1.736 2.757 4.106 2.757 6.572 0 2.191-0.788 4.286-2.187 5.943h1.476c1.258-1.704 1.951-3.792 1.951-5.943-0-2.418-0.884-4.754-2.447-6.572v0zM11.269 3.57h-1.542c1.752 1.736 2.752 4.106 2.752 6.572 0 2.191-0.791 4.286-2.181 5.943h1.473c1.258-1.704 1.945-3.792 1.945-5.943 0-2.418-0.876-4.754-2.447-6.572v0zM10.24 9.857c0 3.459-2.826 6.265-6.303 6.265v0.011h-3.867v-12.555h3.896c3.477 0 6.274 2.806 6.274 6.279v0zM6.944 9.857c0-1.842-1.492-3.338-3.349-3.338h-0.876v6.686h0.876c1.858 0 3.349-1.498 3.349-3.348v0z';
+ break;
+
+ case 'sign':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M10.954 10.307c0.378 0.302 0.569 1.202 0.564 1.193 0.697 0.221 1.136 0.682 1.136 0.682 1.070-0.596 1.094-0.326 1.558-0.682 0.383-0.263 0.366-0.344 0.567-1.048 0.187-0.572-0.476-0.518-1.021-1.558-0.95 0.358-1.463 0.196-1.784 0.167-0.145-0.020-0.12 0.562-1.021 1.247zM14.409 17.196c-0.133 0.182-0.196 0.218-0.363 0.454-0.28 0.361 0.076 0.906 0.253 0.82 0.206-0.076 0.341-0.488 0.567-0.623 0.115-0.061 0.422-0.513 0.709-0.82 0.211-0.238 0.363-0.344 0.564-0.594 0.341-0.422 0.412-0.744 0.709-1.193 0.184-0.236 0.312-0.307 0.481-0.594 0.886-1.679 0.628-2.432 1.475-3.629 0.26-0.353 0.552-0.442 0.964-0.653 0.383-2.793-0.888-4.356-0.879-4.361-1.067 0.623-1.644 0.879-2.751 0.82-0.417-0.005-0.636-0.182-1.048-0.145-0.385 0.015-0.582 0.159-0.964 0.29-0.589 0.182-0.91 0.344-1.529 0.535-0.393 0.11-0.643 0.115-1.050 0.255-0.348 0.147-0.182 0.029-0.427 0.312-0.317 0.348-0.238 0.623-0.535 1.222-0.371 0.785-0.326 0.891-0.115 0.987-0.14 0.402-0.174 0.672-0.14 1.107 0.039 0.331-0.101 0.562 0.255 0.825 0.483 0.361 1.499 1.205 1.757 1.217 0.39-0.012 1.521 0.029 2.096-0.368 0.13-0.081 0.167-0.162 0.056 0.145-0.022 0.037-1.433 1.136-1.585 1.131-1.794 0.056-1.193 0.157-1.303 0.115-0.091 0-0.955-1.055-1.477-0.682-0.196 0.12-0.287 0.236-0.363 0.452 0.066 0.137 0.383 0.358 0.675 0.54 0.422 0.27 0.461 0.552 0.881 0.653 0.513 0.115 1.060 0.039 1.387 0.081 0.125 0.034 1.256-0.297 1.961-0.675 0.65-0.336-0.898 0.648-1.276 1.131-1.141 0.358-0.82 0.373-1.362 0.483-0.503 0.115-0.479 0.086-0.822 0.196-0.356 0.086-0.648 0.572-0.312 0.825 0.201 0.167 0.827-0.066 1.445-0.086 0.275-0.005 1.391-0.518 1.644-0.653 0.633-0.339 1.099-0.81 1.472-1.077 0.518-0.361-0.584 0.991-1.050 1.558zM8.855 9.799c-0.378-0.312-0.569-1.212-0.564-1.217-0.697-0.206-1.136-0.667-1.136-0.653-1.070 0.582-1.099 0.312-1.558 0.653-0.388 0.277-0.366 0.363-0.567 1.045-0.187 0.594 0.471 0.535 1.021 1.561 0.95-0.344 1.463-0.182 1.784-0.142 0.145 0.010 0.12-0.572 1.021-1.247zM5.4 2.911c0.133-0.191 0.196-0.228 0.368-0.454 0.27-0.371-0.081-0.915-0.253-0.849-0.211 0.096-0.346 0.508-0.599 0.653-0.093 0.052-0.4 0.503-0.682 0.82-0.211 0.228-0.363 0.334-0.564 0.599-0.346 0.407-0.412 0.729-0.709 1.161-0.184 0.258-0.317 0.324-0.481 0.621-0.886 1.669-0.631 2.422-1.475 3.6-0.26 0.38-0.552 0.461-0.964 0.682-0.383 2.788 0.883 4.346 0.879 4.336 1.068-0.609 1.639-0.861 2.751-0.825 0.417 0.025 0.636 0.201 1.048 0.174 0.385-0.025 0.582-0.169 0.964-0.285 0.589-0.196 0.91-0.358 1.499-0.54 0.422-0.12 0.672-0.125 1.080-0.285 0.348-0.128 0.182-0.010 0.427-0.282 0.312-0.358 0.238-0.633 0.508-1.217 0.398-0.8 0.353-0.906 0.142-0.991 0.135-0.412 0.174-0.677 0.14-1.107-0.044-0.336 0.101-0.572-0.255-0.82-0.483-0.375-1.499-1.22-1.752-1.222-0.395 0.002-1.526-0.039-2.101 0.339-0.13 0.101-0.167 0.182-0.056-0.11 0.022-0.052 1.433-1.148 1.585-1.163 1.794-0.039 1.193-0.14 1.303-0.088 0.091-0.007 0.955 1.045 1.477 0.682 0.191-0.13 0.287-0.245 0.368-0.452-0.071-0.147-0.388-0.368-0.68-0.537-0.422-0.282-0.464-0.564-0.881-0.655-0.513-0.125-1.065-0.049-1.387-0.11-0.125-0.015-1.256 0.317-1.956 0.68-0.66 0.351 0.893-0.631 1.276-1.136 1.136-0.339 0.81-0.353 1.36-0.479 0.501-0.101 0.476-0.071 0.82-0.172 0.351-0.096 0.648-0.577 0.312-0.849-0.206-0.152-0.827 0.081-1.44 0.086-0.28 0.020-1.396 0.533-1.649 0.677-0.633 0.329-1.099 0.8-1.472 1.048-0.523 0.38 0.584-0.967 1.050-1.529z';
+ break;
+
+ case 'mute':
+ case 'volume-mute':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714zM18.75 12.093v1.657h-1.657l-2.093-2.093-2.093 2.093h-1.657v-1.657l2.093-2.093-2.093-2.093v-1.657h1.657l2.093 2.093 2.093-2.093h1.657v1.657l-2.093 2.093z';
+ break;
+
+ case 'volume-soft':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M10.723 14.473c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 1.584-1.584 1.584-4.161 0-5.745-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c2.315 2.315 2.315 6.082 0 8.397-0.183 0.183-0.423 0.275-0.663 0.275zM7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714z';
+ break;
+
+ case 'volume-medium':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M14.053 16.241c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 2.559-2.559 2.559-6.722 0-9.281-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c1.594 1.594 2.471 3.712 2.471 5.966s-0.878 4.373-2.471 5.966c-0.183 0.183-0.423 0.275-0.663 0.275zM10.723 14.473c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 1.584-1.584 1.584-4.161 0-5.745-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c2.315 2.315 2.315 6.082 0 8.397-0.183 0.183-0.423 0.275-0.663 0.275zM7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714z';
+ break;
+
+ case 'volume-loud':
+ svg[0] = '0 0 21 20';
+ svg[1] = 'M17.384 18.009c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 1.712-1.712 2.654-3.988 2.654-6.408s-0.943-4.696-2.654-6.408c-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c2.066 2.066 3.204 4.813 3.204 7.734s-1.138 5.668-3.204 7.734c-0.183 0.183-0.423 0.275-0.663 0.275zM14.053 16.241c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 2.559-2.559 2.559-6.722 0-9.281-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c1.594 1.594 2.471 3.712 2.471 5.966s-0.878 4.373-2.471 5.966c-0.183 0.183-0.423 0.275-0.663 0.275zM10.723 14.473c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 1.584-1.584 1.584-4.161 0-5.745-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c2.315 2.315 2.315 6.082 0 8.397-0.183 0.183-0.423 0.275-0.663 0.275zM7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714z';
+ break;
+
+ case 'chapters':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M5 2.5v17.5l6.25-6.25 6.25 6.25v-17.5zM15 0h-12.5v17.5l1.25-1.25v-15h11.25z';
+ break;
+
+ case 'transcript':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M0 19.107v-17.857q0-0.446 0.313-0.759t0.759-0.313h8.929v6.071q0 0.446 0.313 0.759t0.759 0.313h6.071v11.786q0 0.446-0.313 0.759t-0.759 0.312h-15q-0.446 0-0.759-0.313t-0.313-0.759zM4.286 15.536q0 0.156 0.1 0.257t0.257 0.1h7.857q0.156 0 0.257-0.1t0.1-0.257v-0.714q0-0.156-0.1-0.257t-0.257-0.1h-7.857q-0.156 0-0.257 0.1t-0.1 0.257v0.714zM4.286 12.679q0 0.156 0.1 0.257t0.257 0.1h7.857q0.156 0 0.257-0.1t0.1-0.257v-0.714q0-0.156-0.1-0.257t-0.257-0.1h-7.857q-0.156 0-0.257 0.1t-0.1 0.257v0.714zM4.286 9.821q0 0.156 0.1 0.257t0.257 0.1h7.857q0.156 0 0.257-0.1t0.1-0.257v-0.714q0-0.156-0.1-0.257t-0.257-0.1h-7.857q-0.156 0-0.257 0.1t-0.1 0.257v0.714zM11.429 5.893v-5.268q0.246 0.156 0.402 0.313l4.554 4.554q0.156 0.156 0.313 0.402h-5.268z';
+ break;
+
+ case 'preferences':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M18.238 11.919c-1.049-1.817-0.418-4.147 1.409-5.205l-1.965-3.404c-0.562 0.329-1.214 0.518-1.911 0.518-2.1 0-3.803-1.714-3.803-3.828h-3.931c0.005 0.653-0.158 1.314-0.507 1.919-1.049 1.818-3.382 2.436-5.212 1.382l-1.965 3.404c0.566 0.322 1.056 0.793 1.404 1.396 1.048 1.815 0.42 4.139-1.401 5.2l1.965 3.404c0.56-0.326 1.209-0.513 1.902-0.513 2.094 0 3.792 1.703 3.803 3.808h3.931c-0.002-0.646 0.162-1.3 0.507-1.899 1.048-1.815 3.375-2.433 5.203-1.387l1.965-3.404c-0.562-0.322-1.049-0.791-1.395-1.391zM10 14.049c-2.236 0-4.050-1.813-4.050-4.049s1.813-4.049 4.050-4.049 4.049 1.813 4.049 4.049c-0 2.237-1.813 4.049-4.049 4.049z';
+ break;
+
+ case 'close':
+ svg[0] = '0 0 16 20';
+ svg[1] = 'M1.228 14.933q0-0.446 0.312-0.759l3.281-3.281-3.281-3.281q-0.313-0.313-0.313-0.759t0.313-0.759l1.518-1.518q0.313-0.313 0.759-0.313t0.759 0.313l3.281 3.281 3.281-3.281q0.313-0.313 0.759-0.313t0.759 0.313l1.518 1.518q0.313 0.313 0.313 0.759t-0.313 0.759l-3.281 3.281 3.281 3.281q0.313 0.313 0.313 0.759t-0.313 0.759l-1.518 1.518q-0.313 0.313-0.759 0.313t-0.759-0.313l-3.281-3.281-3.281 3.281q-0.313 0.313-0.759 0.313t-0.759-0.313l-1.518-1.518q-0.313-0.313-0.313-0.759z';
+ break;
+
+ case 'fullscreen-expand':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M0 18.036v-5q0-0.29 0.212-0.502t0.502-0.212 0.502 0.212l1.607 1.607 3.705-3.705q0.112-0.112 0.257-0.112t0.257 0.112l1.272 1.272q0.112 0.112 0.112 0.257t-0.112 0.257l-3.705 3.705 1.607 1.607q0.212 0.212 0.212 0.502t-0.212 0.502-0.502 0.212h-5q-0.29 0-0.502-0.212t-0.212-0.502zM8.717 8.393q0-0.145 0.112-0.257l3.705-3.705-1.607-1.607q-0.212-0.212-0.212-0.502t0.212-0.502 0.502-0.212h5q0.29 0 0.502 0.212t0.212 0.502v5q0 0.29-0.212 0.502t-0.502 0.212-0.502-0.212l-1.607-1.607-3.705 3.705q-0.112 0.112-0.257 0.112t-0.257-0.112l-1.272-1.272q-0.112-0.112-0.112-0.257z';
+ break;
+
+ case 'fullscreen-collapse':
+ svg[0] = '0 0 20 20';
+ svg[1] = 'M0.145 16.964q0-0.145 0.112-0.257l3.705-3.705-1.607-1.607q-0.212-0.212-0.212-0.502t0.212-0.502 0.502-0.212h5q0.29 0 0.502 0.212t0.212 0.502v5q0 0.29-0.212 0.502t-0.502 0.212-0.502-0.212l-1.607-1.607-3.705 3.705q-0.112 0.112-0.257 0.112t-0.257-0.112l-1.272-1.272q-0.112-0.112-0.112-0.257zM8.571 9.464v-5q0-0.29 0.212-0.502t0.502-0.212 0.502 0.212l1.607 1.607 3.705-3.705q0.112-0.112 0.257-0.112t0.257 0.112l1.272 1.272q0.112 0.112 0.112 0.257t-0.112 0.257l-3.705 3.705 1.607 1.607q0.212 0.212 0.212 0.502t-0.212 0.502-0.502 0.212h-5q-0.29 0-0.502-0.212t-0.212-0.502z';
+ break;
+ }
+
+ return svg;
+ };
+
+ // Initialize player based on data on page.
+ // This sets some variables, but does not modify anything. Safe to call multiple times.
+ // Can call again after updating this.media so long as new media element has the same ID.
+ AblePlayer.prototype.reinitialize = function () {
+
+ var deferred, promise;
+
+ deferred = new this.defer();
+ promise = deferred.promise();
+
+ this.startedPlaying = false;
+ // TODO: Move this setting to preferences.
+ this.autoScrollTranscript = true;
+ //this.autoScrollTranscript = this.getPref(autoScrollTranscript); // (doesn't work)
+
+ // Bootstrap from this.media possibly being an ID or other selector.
+ this.$media = $(this.media).first();
+ this.media = this.$media[0];
+
+ // Set media type to 'audio' or 'video'; this determines some of the behavior of player creation.
+ if (this.$media.is('audio')) {
+ this.mediaType = 'audio';
+ } else if (this.$media.is('video')) {
+ this.mediaType = 'video';
+ } else {
+ // Able Player was initialized with some element other than or
+ this.provideFallback();
+ deferred.reject();
+ return promise;
+ }
+
+ this.$sources = this.$media.find('source');
+
+ this.player = this.getPlayer();
+ if (!this.player) {
+ // an error was generated in getPlayer()
+ this.provideFallback();
+ }
+
+ deferred.resolve();
+ return promise;
+ };
+
+ AblePlayer.prototype.setPlayerSize = function(width, height) {
+
+ // Called again after width and height are known
+ if (this.mediaType !== 'audio' && width > 0 && height > 0) {
+ this.playerWidth = width;
+ this.playerHeight = height;
+ this.aspectRatio = height / width;
+ }
+ };
+
+ // Perform one-time setup for this instance of player; called after player is first initialized.
+ AblePlayer.prototype.setupInstance = function () {
+
+ var deferred = new this.defer();
+ var promise = deferred.promise();
+
+ if (this.$media.attr('id')) {
+ this.mediaId = this.$media.attr('id');
+ } else {
+ // Ensure the base media element always has an ID.
+ this.mediaId = "ableMediaId_" + this.ableIndex;
+ this.$media.attr('id', this.mediaId);
+ }
+ deferred.resolve();
+ return promise;
+ };
+
+ AblePlayer.prototype.setupInstancePlaylist = function() {
+
+ // find a matching playlist and set this.hasPlaylist
+ // if there is one, also set this.$playlist, this.playlistIndex, & this.playlistEmbed
+ var thisObj = this;
+
+ this.hasPlaylist = false; // will change to true if a matching playlist is found
+
+ $('.able-playlist').each(function() {
+ if ($(this).data('player') === thisObj.mediaId) {
+ // this is the playlist for the current player
+ thisObj.hasPlaylist = true;
+ // If using an embedded player, we'll replace $playlist with the clone later.
+ thisObj.$playlist = $(this).find('li');
+
+ // check to see if list item has YouTube as its source
+ // if it does, inject a thumbnail from YouTube
+ var $youTubeVideos = $(this).find('li[data-youtube-id]');
+ $youTubeVideos.each(function() {
+ var youTubeId = purify.sanitize( $(this).attr('data-youtube-id') );
+ var youTubePoster = thisObj.getYouTubePosterUrl(youTubeId,'120');
+ var $youTubeImg = $(' ',{
+ 'src': youTubePoster,
+ 'alt': ''
+ });
+ $(this).find('button').prepend($youTubeImg);
+ });
+
+ // check to see if list item has Vimeo as its source
+ // if it does, inject a thumbnail from Vimeo
+ var $vimeoVideos = $(this).find('li[data-vimeo-id]');
+ $vimeoVideos.each(function() {
+ var vimeoId = $(this).attr('data-vimeo-id');
+ var vimeoPoster = thisObj.getVimeoPosterUrl(vimeoId,'120');
+ var $vimeoImg = $(' ',{
+ 'src': vimeoPoster,
+ 'alt': ''
+ });
+ $(this).find('button').prepend($vimeoImg);
+ });
+
+ // add accessibility to the list markup
+ $(this).find('li span').attr('aria-hidden','true');
+ thisObj.playlistIndex = 0;
+ var dataEmbedded = $(this).data('embedded');
+ // is playlist embedded within player?
+ thisObj.playlistEmbed = (typeof dataEmbedded !== 'undefined' && dataEmbedded !== false) ? true : false;
+ }
+ });
+
+ if (this.hasPlaylist && this.loop) {
+ // browser will loop the current track in the playlist, rather than the playlist
+ // therefore, need to remove loop attribute from media element
+ // but keep this.loop as true and handle the playlist looping ourselves
+ this.media.removeAttribute('loop');
+ }
+ if (this.hasPlaylist && this.playlistEmbed) {
+ // Copy the playlist out of the dom, so we can reinject when we build the player.
+ var parent = this.$playlist.parent();
+ this.$playlistDom = parent.clone();
+ parent.remove();
+ }
+ if (this.hasPlaylist && this.$sources.length === 0) {
+ // no source elements were provided. Construct them from the first playlist item
+ this.cuePlaylistItem(0);
+ // redefine this.$sources now that media contains one or more elements
+ this.$sources = this.$media.find('source');
+ }
+ };
+
+ AblePlayer.prototype.recreatePlayer = function () {
+
+ // Creates the appropriate player for the current source.
+ // This function is called each time a new media instance is loaded
+ // e.g.,
+ // User clicks on an item in a playlist
+ // User swaps to/from described version of video
+ // Blocks of code that only need to be executed once are controlled
+ // by this.playerCreated
+
+ // TODO: Ensure when recreating player that we carry over the mediaId
+ if (!this.player) {
+ return;
+ }
+
+ var deferred, promise, thisObj, prefsGroups, i;
+
+ deferred = new this.defer();
+ promise = deferred.promise();
+ thisObj = this;
+
+ this.playerDeleted = false; // reset after deletePlayer()
+
+ // set temp stopgap to prevent this function from executing again before finished
+ this.recreatingPlayer = true;
+
+ if (!this.playerCreated) {
+ // only call these functions once
+ this.loadCurrentPreferences();
+ this.injectPlayerCode();
+ this.resizePlayer(this.media.videoWidth,this.media.videoHeight);
+ }
+
+ this.getSampleDescriptionText();
+
+ this.initSignLanguage();
+
+ this.initPlayer().then(function() {
+
+ thisObj.getTracks().then(function() {
+
+ thisObj.initDescription().then(function() {
+
+ thisObj.setupTracks().then(function() {
+ if (thisObj.hasClosedDesc) {
+ if (!thisObj.$descDiv || (thisObj.$descDiv && !($.contains(thisObj.$ableDiv[0], thisObj.$descDiv[0])))) {
+ // descDiv either doesn't exist, or exists in an orphaned state
+ // Either way, it needs to be rebuilt...
+ thisObj.injectTextDescriptionArea();
+ }
+ }
+ thisObj.initSpeech('init');
+
+ thisObj.setupTranscript().then(function() {
+
+ thisObj.initStenoFrame().then(function() {
+
+ if (thisObj.stenoMode && thisObj.$stenoFrame) {
+ thisObj.stenoFrameContents = thisObj.$stenoFrame.contents();
+ }
+ thisObj.getMediaTimes().then(function(mediaTimes) {
+
+ thisObj.duration = mediaTimes['duration'];
+ thisObj.elapsed = mediaTimes['elapsed'];
+
+ if (typeof thisObj.volume === 'undefined') {
+ thisObj.volume = thisObj.defaultVolume;
+ }
+ if (thisObj.volume) {
+ thisObj.setVolume(thisObj.volume);
+ }
+ if (thisObj.transcriptType) {
+ thisObj.addTranscriptAreaEvents();
+ thisObj.updateTranscript();
+ }
+ if (thisObj.captions.length) {
+ thisObj.initDefaultCaption();
+ }
+
+ // setMediaAttributes() sets textTrack.mode to 'disabled' for all tracks
+ // This tells browsers to ignore the text tracks so Able Player can handle them
+ // However, timing is critical as browsers - especially Safari - tend to ignore this request
+ // unless it's sent late in the intialization process.
+ // If browsers ignore the request, the result is redundant captions
+ thisObj.setMediaAttributes();
+ thisObj.addControls();
+ thisObj.addEventListeners();
+
+ // inject each of the hidden forms that will be accessed from the Preferences popup menu
+ prefsGroups = thisObj.getPreferencesGroups();
+ for (i = 0; i < prefsGroups.length; i++) {
+ thisObj.injectPrefsForm(prefsGroups[i]);
+ }
+ thisObj.setupPopups();
+ thisObj.updateCaption();
+ thisObj.injectVTS();
+ thisObj.populateChaptersDiv();
+ thisObj.showSearchResults();
+
+ // Go ahead and load media, without user requesting it
+ // Ideally, we would wait until user clicks play, rather than unnecessarily consume their bandwidth
+ // However, the media needs to load for us to get the media's duration
+ if (thisObj.player === 'html5') {
+ if (!thisObj.loadingMedia) {
+ thisObj.$media[0].load();
+ thisObj.loadingMedia = true;
+ }
+ }
+ // refreshControls is called twice building/initializing the player
+ // this is the second. Best to pause a bit before executing, to be sure all prior steps are complete
+ setTimeout(function() {
+ thisObj.refreshControls();
+ deferred.resolve();
+ },100);
+ });
+ });
+ });
+ });
+ });
+ });
+ },
+ function() { // initPlayer fail
+ thisObj.provideFallback();
+ });
+ return promise;
+ };
+
+ AblePlayer.prototype.initPlayer = function () {
+
+ var thisObj = this;
+ var playerPromise;
+ // First run player specific initialization.
+ if (this.player === 'html5') {
+ playerPromise = this.initHtml5Player();
+ } else if (this.player === 'youtube') {
+ playerPromise = this.initYouTubePlayer();
+ } else if (this.player === 'vimeo') {
+ playerPromise = this.initVimeoPlayer();
+ }
+ // After player specific initialization is done, run remaining general initialization.
+ var deferred = new this.defer();
+ var promise = deferred.promise();
+ playerPromise.then(
+ function () { // done/resolved
+ if (thisObj.useFixedSeekInterval) {
+ // if fixed seekInterval was not already assigned (using value of data-seek-interval)
+ if (!thisObj.seekInterval) {
+ thisObj.seekInterval = thisObj.defaultSeekInterval;
+ }
+ thisObj.seekIntervalCalculated = true;
+ } else {
+ thisObj.setSeekInterval();
+ }
+ deferred.resolve();
+ }
+ ).finally(function () { // failed
+ deferred.reject();
+ }
+ );
+
+ return promise;
+ };
+
+ AblePlayer.prototype.initStenoFrame = function() {
+
+ var deferred, promise;
+ deferred = new this.defer();
+ promise = deferred.promise();
+
+ if (this.stenoMode && this.$stenoFrame) {
+
+ if (this.$stenoFrame[0].contentWindow,document.readyState == 'complete') {
+ // iframe has already loaded
+ deferred.resolve();
+ } else {
+ // iframe has not loaded. Wait for it.
+ this.$stenoFrame.on('load',function() {
+ deferred.resolve();
+ });
+ }
+ } else {
+ // there is no stenoFrame to initialize
+ deferred.resolve();
+ }
+ return promise;
+ };
+
+ AblePlayer.prototype.setSeekInterval = function () {
+
+ // this function is only called if this.useFixedSeekInterval is false
+ // if this.useChapterTimes, this is called as each new chapter is loaded
+ // otherwise, it's called once, as the player is initialized
+ var duration;
+ this.seekInterval = this.defaultSeekInterval;
+ duration = (this.useChapterTimes) ? this.chapterDuration : this.duration;
+
+ if (typeof duration === 'undefined' || duration < 1) {
+ // no duration; just use default for now but keep trying until duration is available
+ this.seekIntervalCalculated = false;
+ return;
+ } else {
+ if (duration <= 20) {
+ this.seekInterval = 5; // 4 steps max
+ } else if (duration <= 30) {
+ this.seekInterval = 6; // 5 steps max
+ } else if (duration <= 40) {
+ this.seekInterval = 8; // 5 steps max
+ } else if (duration <= 100) {
+ this.seekInterval = 10; // 10 steps max
+ } else {
+ // never more than 10 steps from start to end
+ this.seekInterval = Math.round(duration / 10, 0);
+ }
+ this.seekIntervalCalculated = true;
+ }
+ };
+
+ AblePlayer.prototype.initDefaultCaption = function () {
+
+ var captions, i;
+
+ captions = this.captions;
+ if (captions.length > 0) {
+ for (i=0; i to this.captionLang
+ if (this.$transcriptLanguageSelect) {
+ this.$transcriptLanguageSelect.find('option[lang=' + this.captionLang + ']').prop('selected',true);
+ }
+ // sync all other tracks to this same languge
+ this.syncTrackLanguages('init',this.captionLang);
+ }
+ if (this.player === 'vimeo') {
+ if (this.usingVimeoCaptions && this.prefCaptions == 1) {
+ // initialize Vimeo captions to the default language
+ this.vimeoPlayer.enableTextTrack(this.captionLang).catch(function(error) {
+ switch (error.name) {
+ }
+ });
+ } else {
+ // disable Vimeo captions.
+ this.vimeoPlayer.disableTextTrack().then(function() {
+ // Vimeo captions disabled
+ }).catch(function(error) {
+ });
+ }
+ }
+ }
+ };
+
+ AblePlayer.prototype.initHtml5Player = function () {
+ // Nothing special to do!
+ var deferred = new this.defer();
+ var promise = deferred.promise();
+ deferred.resolve();
+ return promise;
+ };
+
+ // Sets media/track/source attributes; is called whenever player is recreated since $media may have changed.
+ AblePlayer.prototype.setMediaAttributes = function () {
+ // Firefox puts videos in tab order; remove.
+ this.$media.attr('tabindex', -1);
+
+ // Keep native player from displaying captions/subtitles by setting textTrack.mode='disabled'
+ // https://dev.w3.org/html5/spec-author-view/video.html#text-track-mode
+ // This *should* work but historically hasn't been supported in all browsers
+ // As of July 2025, 96% supported per https://caniuse.com/?search=text-track-mode.
+ // Workaround for non-supporting browsers is to remove default attribute
+ // We're doing that too in track.js > setupCaptions()
+ var textTracks = this.$media.get(0).textTracks;
+ if (textTracks) {
+ var i = 0;
+ while (i < textTracks.length) {
+ textTracks[i].mode = 'disabled';
+ i += 1;
+ }
+ }
+ };
+
+ AblePlayer.prototype.getPlayer = function() {
+
+ // Determine which player to use, if any
+ // return 'html5', 'youtube', 'vimeo', or null
+ if (this.testFallback) {
+ return null;
+ } else if (this.youTubeId) {
+ // null if attempting to play a YouTube video using an element other than
+ return (this.mediaType !== 'video') ? null : 'youtube';
+ } else if (this.vimeoId) {
+ // null if attempting to play a Vimeo video using an element other than
+ return (this.mediaType !== 'video') ? null : 'vimeo';
+ } else if (this.media.canPlayType) {
+ return 'html5';
+ } else {
+ // Browser does not support the available media file
+ return null;
+ }
+ };
+ }
+
+ function addLangsFunctions(AblePlayer) {
+ // Look up ISO 639-1 language codes to be used as subtitle labels
+ // In some instances "name" has been trunctation for readability
+ // Sources:
+ // http://stackoverflow.com/questions/3217492/list-of-language-codes-in-yaml-or-json/4900304#4900304
+ // https://www.venea.net/web/culture_code
+
+ var isoLangs = {
+ "ab":{
+ "name":"Abkhaz",
+ "nativeName":"аҧсуа"
+ },
+ "aa":{
+ "name":"Afar",
+ "nativeName":"Afaraf"
+ },
+ "af":{
+ "name":"Afrikaans",
+ "nativeName":"Afrikaans"
+ },
+ "ak":{
+ "name":"Akan",
+ "nativeName":"Akan"
+ },
+ "sq":{
+ "name":"Albanian",
+ "nativeName":"Shqip"
+ },
+ "am":{
+ "name":"Amharic",
+ "nativeName":"አማርኛ"
+ },
+ "ar":{
+ "name":"Arabic",
+ "nativeName":"العربية"
+ },
+ "an":{
+ "name":"Aragonese",
+ "nativeName":"Aragonés"
+ },
+ "hy":{
+ "name":"Armenian",
+ "nativeName":"Հայերեն"
+ },
+ "as":{
+ "name":"Assamese",
+ "nativeName":"অসমীয়া"
+ },
+ "av":{
+ "name":"Avaric",
+ "nativeName":"авар мацӀ, магӀарул мацӀ"
+ },
+ "ae":{
+ "name":"Avestan",
+ "nativeName":"avesta"
+ },
+ "ay":{
+ "name":"Aymara",
+ "nativeName":"aymar aru"
+ },
+ "az":{
+ "name":"Azerbaijani",
+ "nativeName":"azərbaycan dili"
+ },
+ "bm":{
+ "name":"Bambara",
+ "nativeName":"bamanankan"
+ },
+ "ba":{
+ "name":"Bashkir",
+ "nativeName":"башҡорт теле"
+ },
+ "eu":{
+ "name":"Basque",
+ "nativeName":"euskara, euskera"
+ },
+ "be":{
+ "name":"Belarusian",
+ "nativeName":"Беларуская"
+ },
+ "bn":{
+ "name":"Bengali",
+ "nativeName":"বাংলা"
+ },
+ "bh":{
+ "name":"Bihari",
+ "nativeName":"भोजपुरी"
+ },
+ "bi":{
+ "name":"Bislama",
+ "nativeName":"Bislama"
+ },
+ "bs":{
+ "name":"Bosnian",
+ "nativeName":"bosanski jezik"
+ },
+ "br":{
+ "name":"Breton",
+ "nativeName":"brezhoneg"
+ },
+ "bg":{
+ "name":"Bulgarian",
+ "nativeName":"български език"
+ },
+ "my":{
+ "name":"Burmese",
+ "nativeName":"ဗမာစာ"
+ },
+ "ca":{
+ "name":"Catalan",
+ "nativeName":"Català"
+ },
+ "ch":{
+ "name":"Chamorro",
+ "nativeName":"Chamoru"
+ },
+ "ce":{
+ "name":"Chechen",
+ "nativeName":"нохчийн мотт"
+ },
+ "ny":{
+ "name":"Chichewa",
+ "nativeName":"chiCheŵa, chinyanja"
+ },
+ "zh":{
+ "name":"Chinese",
+ "nativeName":"中文 (Zhōngwén), 汉语, 漢語"
+ },
+ "cv":{
+ "name":"Chuvash",
+ "nativeName":"чӑваш чӗлхи"
+ },
+ "kw":{
+ "name":"Cornish",
+ "nativeName":"Kernewek"
+ },
+ "co":{
+ "name":"Corsican",
+ "nativeName":"corsu, lingua corsa"
+ },
+ "cr":{
+ "name":"Cree",
+ "nativeName":"ᓀᐦᐃᔭᐍᐏᐣ"
+ },
+ "hr":{
+ "name":"Croatian",
+ "nativeName":"hrvatski"
+ },
+ "cs":{
+ "name":"Czech",
+ "nativeName":"česky, čeština"
+ },
+ "da":{
+ "name":"Danish",
+ "nativeName":"dansk"
+ },
+ "dv":{
+ "name":"Divehi",
+ "nativeName":"ދިވެހި"
+ },
+ "nl":{
+ "name":"Dutch",
+ "nativeName":"Nederlands, Vlaams"
+ },
+ "en":{
+ "name":"English",
+ "nativeName":"English"
+ },
+ "eo":{
+ "name":"Esperanto",
+ "nativeName":"Esperanto"
+ },
+ "et":{
+ "name":"Estonian",
+ "nativeName":"eesti, eesti keel"
+ },
+ "ee":{
+ "name":"Ewe",
+ "nativeName":"Eʋegbe"
+ },
+ "fo":{
+ "name":"Faroese",
+ "nativeName":"føroyskt"
+ },
+ "fj":{
+ "name":"Fijian",
+ "nativeName":"vosa Vakaviti"
+ },
+ "fi":{
+ "name":"Finnish",
+ "nativeName":"suomi, suomen kieli"
+ },
+ "fr":{
+ "name":"French",
+ "nativeName":"français, langue française"
+ },
+ "ff":{
+ "name":"Fula",
+ "nativeName":"Fulfulde, Pulaar, Pular"
+ },
+ "gl":{
+ "name":"Galician",
+ "nativeName":"Galego"
+ },
+ "ka":{
+ "name":"Georgian",
+ "nativeName":"ქართული"
+ },
+ "de":{
+ "name":"German",
+ "nativeName":"Deutsch"
+ },
+ "el":{
+ "name":"Greek",
+ "nativeName":"Ελληνικά"
+ },
+ "gn":{
+ "name":"Guaraní",
+ "nativeName":"Avañeẽ"
+ },
+ "gu":{
+ "name":"Gujarati",
+ "nativeName":"ગુજરાતી"
+ },
+ "ht":{
+ "name":"Haitian",
+ "nativeName":"Kreyòl ayisyen"
+ },
+ "ha":{
+ "name":"Hausa",
+ "nativeName":"Hausa, هَوُسَ"
+ },
+ "he":{
+ "name":"Hebrew",
+ "nativeName":"עברית"
+ },
+ "hz":{
+ "name":"Herero",
+ "nativeName":"Otjiherero"
+ },
+ "hi":{
+ "name":"Hindi",
+ "nativeName":"हिन्दी, हिंदी"
+ },
+ "ho":{
+ "name":"Hiri Motu",
+ "nativeName":"Hiri Motu"
+ },
+ "hu":{
+ "name":"Hungarian",
+ "nativeName":"Magyar"
+ },
+ "ia":{
+ "name":"Interlingua",
+ "nativeName":"Interlingua"
+ },
+ "id":{
+ "name":"Indonesian",
+ "nativeName":"Bahasa Indonesia"
+ },
+ "ie":{
+ "name":"Interlingue",
+ "nativeName":"Originally called Occidental; then Interlingue after WWII"
+ },
+ "ga":{
+ "name":"Irish",
+ "nativeName":"Gaeilge"
+ },
+ "ig":{
+ "name":"Igbo",
+ "nativeName":"Asụsụ Igbo"
+ },
+ "ik":{
+ "name":"Inupiaq",
+ "nativeName":"Iñupiaq, Iñupiatun"
+ },
+ "io":{
+ "name":"Ido",
+ "nativeName":"Ido"
+ },
+ "is":{
+ "name":"Icelandic",
+ "nativeName":"Íslenska"
+ },
+ "it":{
+ "name":"Italian",
+ "nativeName":"Italiano"
+ },
+ "iu":{
+ "name":"Inuktitut",
+ "nativeName":"ᐃᓄᒃᑎᑐᑦ"
+ },
+ "ja":{
+ "name":"Japanese",
+ "nativeName":"日本語 (にほんご/にっぽんご)"
+ },
+ "jv":{
+ "name":"Javanese",
+ "nativeName":"basa Jawa"
+ },
+ "kl":{
+ "name":"Kalaallisut",
+ "nativeName":"kalaallisut, kalaallit oqaasii"
+ },
+ "kn":{
+ "name":"Kannada",
+ "nativeName":"ಕನ್ನಡ"
+ },
+ "kr":{
+ "name":"Kanuri",
+ "nativeName":"Kanuri"
+ },
+ "ks":{
+ "name":"Kashmiri",
+ "nativeName":"कश्मीरी, كشميري"
+ },
+ "kk":{
+ "name":"Kazakh",
+ "nativeName":"Қазақ тілі"
+ },
+ "km":{
+ "name":"Khmer",
+ "nativeName":"ភាសាខ្មែរ"
+ },
+ "ki":{
+ "name":"Kikuyu",
+ "nativeName":"Gĩkũyũ"
+ },
+ "rw":{
+ "name":"Kinyarwanda",
+ "nativeName":"Ikinyarwanda"
+ },
+ "ky":{
+ "name":"Kyrgyz",
+ "nativeName":"кыргыз тили"
+ },
+ "kv":{
+ "name":"Komi",
+ "nativeName":"коми кыв"
+ },
+ "kg":{
+ "name":"Kongo",
+ "nativeName":"KiKongo"
+ },
+ "ko":{
+ "name":"Korean",
+ "nativeName":"한국어 (韓國語), 조선말 (朝鮮語)"
+ },
+ "ku":{
+ "name":"Kurdish",
+ "nativeName":"Kurdî, كوردی"
+ },
+ "kj":{
+ "name":"Kuanyama",
+ "nativeName":"Kuanyama"
+ },
+ "la":{
+ "name":"Latin",
+ "nativeName":"latine, lingua latina"
+ },
+ "lb":{
+ "name":"Luxembourgish",
+ "nativeName":"Lëtzebuergesch"
+ },
+ "lg":{
+ "name":"Luganda",
+ "nativeName":"Luganda"
+ },
+ "li":{
+ "name":"Limburgish",
+ "nativeName":"Limburgs"
+ },
+ "ln":{
+ "name":"Lingala",
+ "nativeName":"Lingála"
+ },
+ "lo":{
+ "name":"Lao",
+ "nativeName":"ພາສາລາວ"
+ },
+ "lt":{
+ "name":"Lithuanian",
+ "nativeName":"lietuvių kalba"
+ },
+ "lu":{
+ "name":"Luba-Katanga",
+ "nativeName":""
+ },
+ "lv":{
+ "name":"Latvian",
+ "nativeName":"latviešu valoda"
+ },
+ "gv":{
+ "name":"Manx",
+ "nativeName":"Gaelg, Gailck"
+ },
+ "mk":{
+ "name":"Macedonian",
+ "nativeName":"македонски јазик"
+ },
+ "mg":{
+ "name":"Malagasy",
+ "nativeName":"Malagasy fiteny"
+ },
+ "ms":{
+ "name":"Malay",
+ "nativeName":"bahasa Melayu, بهاس ملايو"
+ },
+ "ml":{
+ "name":"Malayalam",
+ "nativeName":"മലയാളം"
+ },
+ "mt":{
+ "name":"Maltese",
+ "nativeName":"Malti"
+ },
+ "mi":{
+ "name":"Māori",
+ "nativeName":"te reo Māori"
+ },
+ "mr":{
+ "name":"Marathi",
+ "nativeName":"मराठी"
+ },
+ "mh":{
+ "name":"Marshallese",
+ "nativeName":"Kajin M̧ajeļ"
+ },
+ "mn":{
+ "name":"Mongolian",
+ "nativeName":"монгол"
+ },
+ "na":{
+ "name":"Nauru",
+ "nativeName":"Ekakairũ Naoero"
+ },
+ "nv":{
+ "name":"Navajo",
+ "nativeName":"Diné bizaad, Dinékʼehǰí"
+ },
+ "nb":{
+ "name":"Norwegian Bokmål",
+ "nativeName":"Norsk bokmål"
+ },
+ "nd":{
+ "name":"North Ndebele",
+ "nativeName":"isiNdebele"
+ },
+ "ne":{
+ "name":"Nepali",
+ "nativeName":"नेपाली"
+ },
+ "ng":{
+ "name":"Ndonga",
+ "nativeName":"Owambo"
+ },
+ "nn":{
+ "name":"Norwegian Nynorsk",
+ "nativeName":"Norsk nynorsk"
+ },
+ "no":{
+ "name":"Norwegian",
+ "nativeName":"Norsk"
+ },
+ "ii":{
+ "name":"Nuosu",
+ "nativeName":"ꆈꌠ꒿ Nuosuhxop"
+ },
+ "nr":{
+ "name":"South Ndebele",
+ "nativeName":"isiNdebele"
+ },
+ "oc":{
+ "name":"Occitan",
+ "nativeName":"Occitan"
+ },
+ "oj":{
+ "name":"Ojibwe",
+ "nativeName":"ᐊᓂᔑᓈᐯᒧᐎᓐ"
+ },
+ "cu":{
+ "name":"Church Slavonic",
+ "nativeName":"ѩзыкъ словѣньскъ"
+ },
+ "om":{
+ "name":"Oromo",
+ "nativeName":"Afaan Oromoo"
+ },
+ "or":{
+ "name":"Oriya",
+ "nativeName":"ଓଡ଼ିଆ"
+ },
+ "os":{
+ "name":"Ossetian",
+ "nativeName":"ирон æвзаг"
+ },
+ "pa":{
+ "name":"Punjabi",
+ "nativeName":"ਪੰਜਾਬੀ, پنجابی"
+ },
+ "pi":{
+ "name":"Pāli",
+ "nativeName":"पाऴि"
+ },
+ "fa":{
+ "name":"Persian",
+ "nativeName":"فارسی"
+ },
+ "pl":{
+ "name":"Polish",
+ "nativeName":"polski"
+ },
+ "ps":{
+ "name":"Pashto",
+ "nativeName":"پښتو"
+ },
+ "pt":{
+ "name":"Portuguese",
+ "nativeName":"Português"
+ },
+ "qu":{
+ "name":"Quechua",
+ "nativeName":"Runa Simi, Kichwa"
+ },
+ "rm":{
+ "name":"Romansh",
+ "nativeName":"rumantsch grischun"
+ },
+ "rn":{
+ "name":"Kirundi",
+ "nativeName":"kiRundi"
+ },
+ "ro":{
+ "name":"Romanian",
+ "nativeName":"română"
+ },
+ "ru":{
+ "name":"Russian",
+ "nativeName":"русский язык"
+ },
+ "sa":{
+ "name":"Sanskrit",
+ "nativeName":"संस्कृतम्"
+ },
+ "sc":{
+ "name":"Sardinian",
+ "nativeName":"sardu"
+ },
+ "sd":{
+ "name":"Sindhi",
+ "nativeName":"सिन्धी, سنڌي، سندھی"
+ },
+ "se":{
+ "name":"Northern Sami",
+ "nativeName":"Davvisámegiella"
+ },
+ "sm":{
+ "name":"Samoan",
+ "nativeName":"gagana faa Samoa"
+ },
+ "sg":{
+ "name":"Sango",
+ "nativeName":"yângâ tî sängö"
+ },
+ "sr":{
+ "name":"Serbian",
+ "nativeName":"српски језик"
+ },
+ "gd":{
+ "name":"Gaelic",
+ "nativeName":"Gàidhlig"
+ },
+ "sn":{
+ "name":"Shona",
+ "nativeName":"chiShona"
+ },
+ "si":{
+ "name":"Sinhalese",
+ "nativeName":"සිංහල"
+ },
+ "sk":{
+ "name":"Slovak",
+ "nativeName":"slovenčina"
+ },
+ "sl":{
+ "name":"Slovene",
+ "nativeName":"slovenščina"
+ },
+ "so":{
+ "name":"Somali",
+ "nativeName":"Soomaaliga, af Soomaali"
+ },
+ "st":{
+ "name":"Southern Sotho",
+ "nativeName":"Sesotho"
+ },
+ "es":{
+ "name":"Spanish",
+ "nativeName":"español, castellano"
+ },
+ "su":{
+ "name":"Sundanese",
+ "nativeName":"Basa Sunda"
+ },
+ "sw":{
+ "name":"Swahili",
+ "nativeName":"Kiswahili"
+ },
+ "ss":{
+ "name":"Swati",
+ "nativeName":"SiSwati"
+ },
+ "sv":{
+ "name":"Swedish",
+ "nativeName":"svenska"
+ },
+ "ta":{
+ "name":"Tamil",
+ "nativeName":"தமிழ்"
+ },
+ "te":{
+ "name":"Telugu",
+ "nativeName":"తెలుగు"
+ },
+ "tg":{
+ "name":"Tajik",
+ "nativeName":"тоҷикӣ, toğikī, تاجیکی"
+ },
+ "th":{
+ "name":"Thai",
+ "nativeName":"ไทย"
+ },
+ "ti":{
+ "name":"Tigrinya",
+ "nativeName":"ትግርኛ"
+ },
+ "bo":{
+ "name":"Tibetan",
+ "nativeName":"བོད་ཡིག"
+ },
+ "tk":{
+ "name":"Turkmen",
+ "nativeName":"Türkmen, Түркмен"
+ },
+ "tl":{
+ "name":"Tagalog",
+ "nativeName":"Wikang Tagalog, ᜏᜒᜃᜅ᜔ ᜆᜄᜎᜓᜄ᜔"
+ },
+ "tn":{
+ "name":"Tswana",
+ "nativeName":"Setswana"
+ },
+ "to":{
+ "name":"Tonga",
+ "nativeName":"faka Tonga"
+ },
+ "tr":{
+ "name":"Turkish",
+ "nativeName":"Türkçe"
+ },
+ "ts":{
+ "name":"Tsonga",
+ "nativeName":"Xitsonga"
+ },
+ "tt":{
+ "name":"Tatar",
+ "nativeName":"татарча, tatarça, تاتارچا"
+ },
+ "tw":{
+ "name":"Twi",
+ "nativeName":"Twi"
+ },
+ "ty":{
+ "name":"Tahitian",
+ "nativeName":"Reo Tahiti"
+ },
+ "ug":{
+ "name":"Uyghur",
+ "nativeName":"Uyƣurqə, ئۇيغۇرچە"
+ },
+ "uk":{
+ "name":"Ukrainian",
+ "nativeName":"українська"
+ },
+ "ur":{
+ "name":"Urdu",
+ "nativeName":"اردو"
+ },
+ "uz":{
+ "name":"Uzbek",
+ "nativeName":"zbek, Ўзбек, أۇزبېك"
+ },
+ "ve":{
+ "name":"Venda",
+ "nativeName":"Tshivenḓa"
+ },
+ "vi":{
+ "name":"Vietnamese",
+ "nativeName":"Tiếng Việt"
+ },
+ "vo":{
+ "name":"Volapük",
+ "nativeName":"Volapük"
+ },
+ "wa":{
+ "name":"Walloon",
+ "nativeName":"Walon"
+ },
+ "cy":{
+ "name":"Welsh",
+ "nativeName":"Cymraeg"
+ },
+ "wo":{
+ "name":"Wolof",
+ "nativeName":"Wollof"
+ },
+ "fy":{
+ "name":"Western Frisian",
+ "nativeName":"Frysk"
+ },
+ "xh":{
+ "name":"Xhosa",
+ "nativeName":"isiXhosa"
+ },
+ "yi":{
+ "name":"Yiddish",
+ "nativeName":"ייִדיש"
+ },
+ "yo":{
+ "name":"Yoruba",
+ "nativeName":"Yorùbá"
+ },
+ "za":{
+ "name":"Zhuang",
+ "nativeName":"Saɯ cueŋƅ, Saw cuengh"
+ },
+ "ar-dz":{
+ "name":"Arabic (Algeria)",
+ "nativeName":"العربية (الجزائر)"
+ },
+ "ar-bh":{
+ "name":"Arabic (Bahrain)",
+ "nativeName":"العربية (البحرين)"
+ },
+ "ar-eg":{
+ "name":"Arabic (Egypt)",
+ "nativeName":"العربية (مصر)"
+ },
+ "ar-iq":{
+ "name":"Arabic (Iraq)",
+ "nativeName":"العربية (العراق)"
+ },
+ "ar-jo":{
+ "name":"Arabic (Jordan)",
+ "nativeName":"العربية (الأردن)"
+ },
+ "ar-kw":{
+ "name":"Arabic (Kuwait)",
+ "nativeName":"العربية (الكويت)"
+ },
+ "ar-lb":{
+ "name":"Arabic (Lebanon)",
+ "nativeName":"العربية (لبنان)"
+ },
+ "ar-ly":{
+ "name":"Arabic (Libya)",
+ "nativeName":"العربية (ليبيا)"
+ },
+ "ar-ma":{
+ "name":"Arabic (Morocco)",
+ "nativeName":"العربية (المملكة المغربية)"
+ },
+ "ar-om":{
+ "name":"Arabic (Oman)",
+ "nativeName":"العربية (عمان)"
+ },
+ "ar-qa":{
+ "name":"Arabic (Qatar)",
+ "nativeName":"العربية (قطر)"
+ },
+ "ar-sa":{
+ "name":"Arabic (Saudi Arabia)",
+ "nativeName":"العربية (المملكة العربية السعودية)"
+ },
+ "ar-sy":{
+ "name":"Arabic (Syria)",
+ "nativeName":"العربية (سوريا)"
+ },
+ "ar-tn":{
+ "name":"Arabic (Tunisia)",
+ "nativeName":"العربية (تونس)"
+ },
+ "ar-ae":{
+ "name":"Arabic (U.A.E.)",
+ "nativeName":"العربية (الإمارات العربية المتحدة)"
+ },
+ "ar-ye":{
+ "name":"Arabic (Yemen)",
+ "nativeName":"العربية (اليمن)"
+ },
+ "de-at":{
+ "name":"German (Austria)",
+ "nativeName":"Deutsch (Österreich)"
+ },
+ "de-li":{
+ "name":"German (Liechtenstein)",
+ "nativeName":"Deutsch (Liechtenstein)"
+ },
+ "de-lu":{
+ "name":"German (Luxembourg)",
+ "nativeName":"Deutsch (Luxemburg)"
+ },
+ "de-ch":{
+ "name":"German (Switzerland)",
+ "nativeName":"Deutsch (Schweiz)"
+ },
+ "en-au":{
+ "name":"English (Australia)",
+ "nativeName":"English (Australia)"
+ },
+ "en-bz":{
+ "name":"English (Belize)",
+ "nativeName":"English (Belize)"
+ },
+ "en-ca":{
+ "name":"English (Canada)",
+ "nativeName":"English (Canada)"
+ },
+ "en-ie":{
+ "name":"English (Ireland)",
+ "nativeName":"English (Ireland)"
+ },
+ "en-jm":{
+ "name":"English (Jamaica)",
+ "nativeName":"English (Jamaica)"
+ },
+ "en-nz":{
+ "name":"English (New Zealand)",
+ "nativeName":""
+ },
+ "en-za":{
+ "name":"English (South Africa)",
+ "nativeName":"English (South Africa)"
+ },
+ "en-tt":{
+ "name":"English (Trinidad)",
+ "nativeName":"English (Trinidad y Tobago)"
+ },
+ "en-gb":{
+ "name":"English (United Kingdom)",
+ "nativeName":"English (United Kingdom)"
+ },
+ "en-us":{
+ "name":"English (United States)",
+ "nativeName":"English (United States)"
+ },
+ "es-ar":{
+ "name":"Spanish (Argentina)",
+ "nativeName":"Español (Argentina)"
+ },
+ "es-bo":{
+ "name":"Spanish (Bolivia)",
+ "nativeName":"Español (Bolivia)"
+ },
+ "es-cl":{
+ "name":"Spanish (Chile)",
+ "nativeName":"Español (Chile)"
+ },
+ "es-co":{
+ "name":"Spanish (Colombia)",
+ "nativeName":"Español (Colombia)"
+ },
+ "es-cr":{
+ "name":"Spanish (Costa Rica)",
+ "nativeName":"Español (Costa Rica)"
+ },
+ "es-do":{
+ "name":"Spanish (Dominican Republic)",
+ "nativeName":"Español (República Dominicana)"
+ },
+ "es-ec":{
+ "name":"Spanish (Ecuador)",
+ "nativeName":"Español (Ecuador)"
+ },
+ "es-sv":{
+ "name":"Spanish (El Salvador)",
+ "nativeName":"Español (El Salvador)"
+ },
+ "es-gt":{
+ "name":"Spanish (Guatemala)",
+ "nativeName":"Español (Guatemala)"
+ },
+ "es-hn":{
+ "name":"Spanish (Honduras)",
+ "nativeName":"Español (Honduras)"
+ },
+ "es-mx":{
+ "name":"Spanish (Mexico)",
+ "nativeName":"Español (México)"
+ },
+ "es-ni":{
+ "name":"Spanish (Nicaragua)",
+ "nativeName":"Español (Nicaragua)"
+ },
+ "es-pa":{
+ "name":"Spanish (Panama)",
+ "nativeName":"Español (Panamá)"
+ },
+ "es-py":{
+ "name":"Spanish (Paraguay)",
+ "nativeName":"Español (Paraguay)"
+ },
+ "es-pe":{
+ "name":"Spanish (Peru)",
+ "nativeName":"Español (Perú)"
+ },
+ "es-pr":{
+ "name":"Spanish (Puerto Rico)",
+ "nativeName":"Español (Puerto Rico)"
+ },
+ "es-uy":{
+ "name":"Spanish (Uruguay)",
+ "nativeName":"Español (Uruguay)"
+ },
+ "es-ve":{
+ "name":"Spanish (Venezuela)",
+ "nativeName":"Español (Venezuela)"
+ },
+ "fr-be":{
+ "name":"French (Belgium)",
+ "nativeName":"français (Belgique)"
+ },
+ "fr-ca":{
+ "name":"French (Canada)",
+ "nativeName":"français (Canada)"
+ },
+ "fr-lu":{
+ "name":"French (Luxembourg)",
+ "nativeName":"français (Luxembourg)"
+ },
+ "fr-ch":{
+ "name":"French (Switzerland)",
+ "nativeName":"français (Suisse)"
+ },
+ "it-ch":{
+ "name":"Italian (Switzerland)",
+ "nativeName":"italiano (Svizzera)"
+ },
+ "nl-be":{
+ "name":"Dutch (Belgium)",
+ "nativeName":"Nederlands (België)"
+ },
+ "pt-br":{
+ "name":"Portuguese (Brazil)",
+ "nativeName":"Português (Brasil)"
+ },
+ "sv-fi":{
+ "name":"Swedish (Finland)",
+ "nativeName":"svenska (Finland)"
+ },
+ "zh-hk":{
+ "name":"Chinese (Hong Kong)",
+ "nativeName":"中文(香港特别行政區)"
+ },
+ "zh-cn":{
+ "name":"Chinese (PRC)",
+ "nativeName":"中文(中华人民共和国)"
+ },
+ "zh-sg":{
+ "name":"Chinese (Singapore)",
+ "nativeName":"中文(新加坡)"
+ },
+ "zh-tw":{
+ "name":"Chinese Traditional (Taiwan)",
+ "nativeName":"中文(台灣)"
+ }
+ };
+
+ AblePlayer.prototype.getLanguageName = function (key,whichName) {
+
+ // return language name associated with lang code "key"
+ // whichName is either "English" or "local" (i.e., native name)
+
+ var lang, code, subTag;
+ lang = isoLangs[key.toLowerCase()];
+ if (lang) {
+ return (whichName === 'local') ? lang.nativeName : lang.name;
+ } else if (key.includes('-')) {
+ code = key.substring(0,2);
+ subTag = key.substring(3);
+ lang = isoLangs[code.toLowerCase()];
+ if (lang) {
+ return (whichName === 'local') ? lang.nativeName + ' (' + subTag + ')' : lang.name + ' (' + subTag + ')';
+ }
+ }
+ // if all else has failed, use the key as the label
+ return key;
+ };
- if (this.hasDescTracks && this.descOn) {
- tracks = this.altTracks;
- } else {
- tracks = this.tracks;
- }
- for (i = 0; i < tracks.length; i++) {
- track = tracks[i];
- kind = ( track.kind ) ? track.kind : 'subtitles';
+ }
- if (!track.src) {
- if (thisObj.usingYouTubeCaptions || thisObj.usingVimeoCaptions) {
- thisObj.setupCaptions(track);
+ function addMetadataFunctions(AblePlayer) {
+ AblePlayer.prototype.updateMeta = function (time) {
+ if (this.hasMeta) {
+ if (this.metaType === "text") {
+ this.$metaDiv.show();
+ this.showMeta(time || this.elapsed);
+ } else {
+ this.showMeta(time || this.elapsed);
}
- continue;
}
- var trackSrc = track.src;
- loadingPromise = this.loadTextObject(trackSrc);
- loadingPromises.push(
- loadingPromise.catch(function (src) {
+ };
- })
- );
- loadingPromise.then(
- (function (track, kind) {
- trackSrc = track.src;
- var trackLang = track.language;
- var trackLabel = track.label;
- var trackDesc = track.desc;
-
- return function (data) {
- var cues = thisObj.parseWebVTT(data).cues;
- if (thisObj.hasVts) {
- thisObj.setupVtsTracks(
- kind,
- trackLang,
- trackDesc,
- trackLabel,
- trackSrc,
- data.text
- );
+ AblePlayer.prototype.showMeta = function (now) {
+ var tempSelectors,
+ m,
+ thisMeta,
+ cues,
+ cueText,
+ cueLines,
+ i,
+ line,
+ showDuration,
+ focusTarget;
+
+ tempSelectors = [];
+ if (this.meta.length >= 1) {
+ cues = this.meta;
+ } else {
+ cues = [];
+ }
+ for (m = 0; m < cues.length; m++) {
+ if (cues[m].start <= now && cues[m].end > now) {
+ thisMeta = m;
+ break;
+ }
+ }
+ if (typeof thisMeta !== "undefined") {
+ if (this.currentMeta !== thisMeta) {
+ if (this.metaType === "text") {
+ // it's time to load the new metadata cue into the container div
+ this.$metaDiv.html(
+ this.flattenCueForMeta(cues[thisMeta]).replace(/\n/g, " ")
+ );
+ } else if (this.metaType === "selector") {
+ // it's time to show content referenced by the designated selector(s)
+ cueText = this.flattenCueForMeta(cues[thisMeta]);
+ cueLines = cueText.split("\n");
+ for (i = 0; i < cueLines.length; i++) {
+ line = cueLines[i].trim();
+ if (line.toLowerCase().trim() === "pause") {
+ // don't show big play button when pausing via metadata
+ this.hideBigPlayButton = true;
+ this.pauseMedia();
+ } else if (line.toLowerCase().substring(0, 6) == "focus:") {
+ focusTarget = line.substring(6).trim();
+ if ($(focusTarget).length) {
+ $(focusTarget).trigger('focus');
+ }
+ } else {
+ if ($(line).length) {
+ // selector exists
+ this.currentMeta = thisMeta;
+ showDuration = parseInt($(line).attr("data-duration"));
+ if (
+ typeof showDuration !== "undefined" &&
+ !isNaN(showDuration)
+ ) {
+ $(line).show();
+ const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
+ delay(showDuration).then(() => {
+ $(line).hide();
+ });
+ } else {
+ // no duration specified. Just show the element until end time specified in VTT file
+ $(line).show();
+ }
+ // add to array of visible selectors so it can be hidden at end time
+ this.visibleSelectors.push(line);
+ tempSelectors.push(line);
+ }
+ }
}
- if (kind === 'captions' || kind === 'subtitles') {
- thisObj.setupCaptions(track, cues);
- } else if (kind === 'descriptions') {
- thisObj.setupDescriptions(track, cues);
- } else if (kind === 'chapters') {
- thisObj.setupChapters(track, cues);
- } else if (kind === 'metadata') {
- thisObj.setupMetadata(cues);
+ // now step through this.visibleSelectors and remove anything that's stale
+ if (this.visibleSelectors && this.visibleSelectors.length) {
+ if (this.visibleSelectors.length !== tempSelectors.length) {
+ for (i = this.visibleSelectors.length - 1; i >= 0; i--) {
+ if ($.inArray(this.visibleSelectors[i], tempSelectors) == -1) {
+ $(this.visibleSelectors[i]).hide();
+ this.visibleSelectors.splice(i, 1);
+ }
+ }
+ }
}
- };
- })(track, kind)
- );
- }
- if (thisObj.usingYouTubeCaptions || thisObj.usingVimeoCaptions) {
- deferred.resolve();
- } else {
- $.when.apply($, loadingPromises).then(function () {
- deferred.resolve();
- });
- }
- return promise;
- };
-
- AblePlayer.prototype.getTracks = function () {
-
- var thisObj, deferred, promise, trackLang, trackLabel, isDefault, forDesc,
- hasDefault, hasTrackInDefLang, trackFound, i;
-
- thisObj = this;
- hasDefault = false;
-
- deferred = new this.defer();
- promise = deferred.promise();
-
- this.$tracks = this.$media.find('track');
- this.tracks = [];
- this.altTracks = [];
-
- this.captions = [];
- this.descriptions = [];
- this.chapters = [];
- this.meta = [];
-
- this.hasCaptionsTrack = false;
- this.hasDescTracks = false;
-
- if (this.$tracks.length) {
- this.usingYouTubeCaptions = false;
- this.$tracks.each(function (index, element) {
- if ($(this).attr('kind') === 'captions') {
- thisObj.hasCaptionsTrack = true;
- } else if ($(this).attr('kind') === 'descriptions') {
- thisObj.hasClosedDesc = true;
+ }
}
-
- if ($(this).attr('srclang')) {
- trackLang = $(this).attr('srclang');
- } else {
- trackLang = thisObj.lang;
+ } else {
+ // there is currently no metadata. Empty stale content
+ if (typeof this.$metaDiv !== "undefined") {
+ this.$metaDiv.html("");
}
- if ($(this).attr('label')) {
- trackLabel = $(this).attr('label');
- } else {
- trackLabel = thisObj.getLanguageName(trackLang);
+ if (this.visibleSelectors && this.visibleSelectors.length) {
+ for (i = 0; i < this.visibleSelectors.length; i++) {
+ $(this.visibleSelectors[i]).hide();
+ }
+ // reset array
+ this.visibleSelectors = [];
}
+ this.currentMeta = -1;
+ }
+ };
- if (typeof $(this).attr('default') !== 'undefined' && !hasDefault) {
- isDefault = true;
- hasDefault = true;
- } else if (trackLang === thisObj.lang) {
- hasTrackInDefLang = true;
- isDefault = false;
+ // Takes a cue and returns the metadata text to display for it.
+ AblePlayer.prototype.flattenCueForMeta = function (cue) {
+ var result = [];
+
+ var flattenComponent = function (component) {
+ var result = [],
+ ii;
+ if (component.type === "string") {
+ result.push(component.value);
+ } else if (component.type === "v") {
+ result.push("[" + component.value + "]");
+ for (ii = 0; ii < component.children.length; ii++) {
+ result.push(flattenComponent(component.children[ii]));
+ }
} else {
- isDefault = false;
- }
- if (isDefault) {
- thisObj.captionLang = trackLang;
+ for (ii = 0; ii < component.children.length; ii++) {
+ result.push(flattenComponent(component.children[ii]));
+ }
}
+ return result.join("");
+ };
- if ($(this).data("desc") !== undefined) {
- forDesc = true;
- thisObj.hasDescTracks = true;
- } else {
- forDesc = false;
- }
- if (forDesc) {
- thisObj.altTracks.push({
- kind: $(this).attr('kind'),
- src: $(this).attr('src'),
- language: trackLang,
- label: trackLabel,
- def: isDefault,
- desc: forDesc,
- });
- } else {
- thisObj.tracks.push({
- kind: $(this).attr('kind'),
- src: $(this).attr('src'),
- language: trackLang,
- label: trackLabel,
- def: isDefault,
- desc: forDesc,
- });
- }
+ for (var ii = 0; ii < cue.components.children.length; ii++) {
+ result.push(flattenComponent(cue.components.children[ii]));
+ }
- if (index == thisObj.$tracks.length - 1) {
- if (!hasDefault) {
- if (hasTrackInDefLang) {
- thisObj.captionLang = thisObj.lang;
- trackFound = false;
- i = 0;
- while (i < thisObj.tracks.length && !trackFound) {
- if (thisObj.tracks[i]['language'] === thisObj.lang) {
- thisObj.tracks[i]['def'] = true;
- trackFound = true;
- }
- i++;
- }
- } else {
- thisObj.tracks[0]['def'] = true;
- thisObj.captionLang = thisObj.tracks[0]['language'];
- }
- }
- thisObj.$media.find("track").removeAttr("default");
+ return result.join("");
+ };
+ }
+
+ function addMiscFunctions(AblePlayer) {
+ AblePlayer.prototype.getNextHeadingLevel = function ($element) {
+ // Finds the nearest heading in the ancestor tree
+ // Loops over each parent of the current element until a heading is found
+ // If multiple headings are found beneath a given parent, get the closest
+ // Returns an integer (1-6) representing the next available heading level
+
+ var $parents, $foundHeadings, numHeadings, headingType, headingNumber;
+
+ $parents = $element.parents();
+ $parents.each(function () {
+ $foundHeadings = $(this).children(":header");
+ numHeadings = $foundHeadings.length;
+ if (numHeadings) {
+ headingType = $foundHeadings.eq(numHeadings - 1).prop("tagName");
+ return false;
}
});
- }
- if (!this.$tracks.length || !this.hasCaptionsTrack) {
- if (this.player === 'youtube') {
- this.getYouTubeCaptionTracks().then(function () {
- if (thisObj.hasCaptions) {
- thisObj.usingYouTubeCaptions = true;
- if (thisObj.$captionsWrapper) {
- thisObj.$captionsWrapper.remove();
- }
- }
- deferred.resolve();
- });
- } else if (this.player === 'vimeo') {
- this.getVimeoCaptionTracks().then(function () {
- if (thisObj.hasCaptions) {
- thisObj.usingVimeoCaptions = true;
- if (thisObj.$captionsWrapper) {
- thisObj.$captionsWrapper.remove();
- }
- }
- deferred.resolve();
- });
+ if (typeof headingType === "undefined") {
+ // page has no headings
+ headingNumber = 1;
} else {
- this.hasCaptions = false;
- if (thisObj.$captionsWrapper) {
- thisObj.$captionsWrapper.remove();
+ // Increment closest heading by one if less than 6.
+ headingNumber = parseInt(headingType[1]);
+ headingNumber += 1;
+ if (headingNumber > 6) {
+ headingNumber = 6;
}
- deferred.resolve();
}
- } else {
- deferred.resolve();
- }
- return promise;
- };
+ return headingNumber;
+ };
- AblePlayer.prototype.setupCaptions = function (track, cues) {
- var inserted, i, capLabel;
+ AblePlayer.prototype.countProperties = function (obj) {
+ // returns the number of properties in an object
+ var count, prop;
+ count = 0;
+ for (prop in obj) {
+ if (Object.hasOwn(obj, prop)) {
+ ++count;
+ }
+ }
+ return count;
+ };
- if (typeof cues === "undefined") {
- cues = null;
- }
+ AblePlayer.prototype.formatSecondsAsColonTime = function (
+ seconds,
+ showFullTime
+ ) {
+ // Takes seconds and converts to string of form hh:mm:ss
+ // If showFullTime is true, shows 00 for hours if time is less than an hour
+ // and show milliseconds (e.g., 00:00:04.123 as in Video Track Sorter)
+ // Otherwise, omits empty hours and milliseconds (e.g., 00:04 as in timer on controller)
- if (this.usingYouTubeCaptions || this.usingVimeoCaptions) {
- } else {
- if (this.captions.length === 0) {
- this.captions.push({
- language: track.language,
- label: track.label,
- def: track.def,
- cues: cues,
- });
- } else {
- inserted = false;
- for (i = 0; i < this.captions.length; i++) {
- capLabel = track.label;
- if (capLabel.toLowerCase() < this.captions[i].label.toLowerCase()) {
- this.captions.splice(i, 0, {
- language: track.language,
- label: track.label,
- def: track.def,
- cues: cues,
- });
- inserted = true;
- break;
+ var times,format,parts,milliSeconds,numShort,i;
+
+ if (showFullTime) {
+ // preserve milliseconds, if included in seconds
+ parts = seconds.toString().split(".");
+ if (parts.length === 2) {
+ milliSeconds = parts[1];
+ if (milliSeconds.length < 3) {
+ numShort = 3 - milliSeconds.length;
+ for (i = 1; i <= numShort; i++) {
+ milliSeconds += "0";
+ }
}
- }
- if (!inserted) {
- this.captions.push({
- language: track.language,
- label: track.label,
- def: track.def,
- cues: cues,
- });
+ } else {
+ milliSeconds = "000";
}
}
- }
+ times = this.secondsToTime( seconds );
+ format = times['value'];
- this.hasCaptions = true;
- this.currentCaption = -1;
- if (this.prefCaptions === 1) {
- this.captionsOn = true;
- } else if (this.prefCaptions === 0) {
- this.captionsOn = false;
- } else {
- if (this.defaultStateCaptions === 1) {
- this.captionsOn = true;
- } else {
- this.captionsOn = false;
- }
- }
- if (this.mediaType === 'audio' && this.captionsOn) {
- this.$captionsContainer.removeClass('captions-off');
- }
+ return (showFullTime) ? format + '.' + milliSeconds : format;
+ };
- if (
- !this.$captionsWrapper ||
- (this.$captionsWrapper &&
- !$.contains(this.$ableDiv[0], this.$captionsWrapper[0]))
- ) {
- this.$captionsDiv = $('', {
- class: "able-captions",
- });
- this.$captionsWrapper = $('
', {
- class: 'able-captions-wrapper',
- 'aria-hidden': 'true',
- }).hide();
- if (this.prefCaptionsPosition === 'below') {
- this.$captionsWrapper.addClass('able-captions-below');
- } else {
- this.$captionsWrapper.addClass('able-captions-overlay');
+ AblePlayer.prototype.getSecondsFromColonTime = function (timeStr) {
+ // Converts string of form hh:mm:ss to seconds
+ var timeParts, hours, minutes, seconds;
+
+ timeParts = timeStr.split(":");
+ if (timeParts.length === 3) {
+ hours = parseInt(timeParts[0]);
+ minutes = parseInt(timeParts[1]);
+ seconds = parseFloat(timeParts[2]);
+ return hours * 3600 + minutes * 60 + seconds;
+ } else if (timeParts.length === 2) {
+ minutes = parseInt(timeParts[0]);
+ seconds = parseFloat(timeParts[1]);
+ return minutes * 60 + seconds;
+ } else if (timeParts.length === 1) {
+ seconds = parseFloat(timeParts[0]);
+ return seconds;
}
- this.$captionsWrapper.append(this.$captionsDiv);
- this.$captionsContainer.append(this.$captionsWrapper);
- }
- };
+ };
- AblePlayer.prototype.setupDescriptions = function (track, cues) {
+ AblePlayer.prototype.capitalizeFirstLetter = function (string) {
+ return string.charAt(0).toUpperCase() + string.slice(1);
+ };
- this.hasClosedDesc = true;
- this.currentDescription = -1;
- this.descriptions.push({
- cues: cues,
- language: track.language,
- });
- };
+ AblePlayer.prototype.roundDown = function (value, decimals) {
+ // round value down to the nearest X decimal points
+ // where X is the value of the decimals parameter
+ return Number(Math.floor(value + "e" + decimals) + "e-" + decimals);
+ };
- AblePlayer.prototype.setupChapters = function (track, cues) {
+ AblePlayer.prototype.defer = function() {
+ const self = this;
+ const promise = new Promise((resolve, reject) => {
+ self.resolve = resolve;
+ self.reject = reject;
+ self.promise = () => promise;
+ });
+ };
- this.hasChapters = true;
- this.chapters.push({
- cues: cues,
- language: track.language,
- });
- };
+ AblePlayer.prototype.getScript = function( source, callback ) {
+ var script = document.createElement('script');
+ var prior = document.getElementsByTagName('script')[0];
+ script.async = 1;
- AblePlayer.prototype.setupMetadata = function (cues) {
- if (this.metaType === 'text') {
- if (this.metaDiv) {
- if ($('#' + this.metaDiv)) {
- this.$metaDiv = $('#' + this.metaDiv);
- this.hasMeta = true;
- this.meta = cues;
- }
- }
- } else if (this.metaType === 'selector') {
- this.hasMeta = true;
- this.visibleSelectors = [];
- this.meta = cues;
- }
- };
+ script.onload = script.onreadystatechange = function( _, isAbort ) {
+ if ( isAbort || !script.readyState || /loaded|complete/.test(script.readyState) ) {
+ script.onload = script.onreadystatechange = null;
+ script = undefined;
- AblePlayer.prototype.loadTextObject = function (src) {
- var deferred, promise, thisObj, $tempDiv;
+ if ( !isAbort && callback ) {
+ setTimeout(callback, 0);
+ }
+ }
+ };
- deferred = new this.defer();
- promise = deferred.promise();
- thisObj = this;
+ script.src = source;
+ prior.parentNode.insertBefore(script, prior);
+ };
- $tempDiv = $('
', {
- style: 'display:none',
- });
+ AblePlayer.prototype.hasAttr = function (object, attribute) {
+ // surprisingly, there is no hasAttr() function in Jquery as of 3.2.1
+ // return true if object has attribute; otherwise false
+ // selector is a Jquery object
+ // attribute is a string
- fetch(src)
- .then( response => {
+ var attr = object.attr(attribute);
- return response.text();
- })
- .then( vtt => {
- var preParsed = vtt.split(/\r?\n\s*\r?\n/);
- var lines = '', line;
-
- preParsed.forEach((l) => {
- line = validate.sanitizeVttContent(l);
- lines += line + "\n\n";
- });
- $tempDiv.html(lines);
- let data = { 'src': src, 'text': lines };
- deferred.resolve(data);
- $tempDiv.remove();
- })
- .catch( error => {
- if (thisObj.debug) {
-
- }
- deferred.reject(src);
- $tempDiv.remove();
- });
-
- return promise;
- };
-})(jQuery);
-
-(function ($) {
-
- AblePlayer.prototype.initYouTubePlayer = function () {
-
- var thisObj, deferred, promise, youTubeId;
- thisObj = this;
- deferred = new this.defer();
- promise = deferred.promise();
-
- this.youTubePlayerReady = false;
-
- youTubeId = (this.youTubeDescId && this.prefDesc) ? this.youTubeDescId : this.youTubeId;
-
- this.activeYouTubeId = youTubeId;
- if (AblePlayer.youTubeIframeAPIReady) {
- thisObj.finalizeYoutubeInit().then(function() {
- deferred.resolve();
- });
- } else {
- if (!AblePlayer.loadingYouTubeIframeAPI) {
- thisObj.getScript('https://www.youtube.com/iframe_api', function () {
-
- });
- }
-
- $('body').on('youTubeIframeAPIReady', function () {
- thisObj.finalizeYoutubeInit().then(function() {
- deferred.resolve();
- });
- });
- }
- return promise;
- };
-
- AblePlayer.prototype.finalizeYoutubeInit = function () {
-
- var deferred, promise, thisObj, containerId, ccLoadPolicy, autoplay;
-
- deferred = new this.defer();
- promise = deferred.promise();
- thisObj = this;
- containerId = this.mediaId + '_youtube';
-
- this.$mediaContainer.prepend($('
').attr('id', containerId));
-
- ccLoadPolicy = 1;
- autoplay = (this.okToPlay) ? 1 : 0;
-
-
- if (typeof this.captionLang == 'undefined') {
- this.captionLang = this.lang;
- }
- this.youTubePlayer = new YT.Player(containerId, {
- videoId: this.activeYouTubeId,
- host: this.youTubeNoCookie ? 'https://www.youtube-nocookie.com' : 'https://www.youtube.com',
- playerVars: {
- autoplay: autoplay,
- cc_lang_pref: this.captionLang,
- cc_load_policy: ccLoadPolicy,
- controls: 0,
- disableKb: 1,
- enablejsapi: 1,
- hl: this.lang,
- iv_load_policy: 3,
- origin: window.location.origin,
- playsinline: this.playsInline,
- rel: 0,
- start: this.startTime
- },
- events: {
- onReady: function () {
- thisObj.youTubePlayerReady = true;
- if (!thisObj.playerWidth || !thisObj.playerHeight) {
- thisObj.getYouTubeDimensions();
- }
- if (thisObj.playerWidth && thisObj.playerHeight) {
- thisObj.youTubePlayer.setSize(thisObj.playerWidth,thisObj.playerHeight);
- }
- if (thisObj.swappingSrc) {
- thisObj.swappingSrc = false;
- thisObj.restoreFocus();
- thisObj.cueingPlaylistItem = false;
- if (thisObj.playing || thisObj.okToPlay) {
- thisObj.playMedia();
- }
- }
- if (thisObj.userClickedPlaylist) {
- thisObj.userClickedPlaylist = false;
- }
- if (thisObj.recreatingPlayer) {
- thisObj.recreatingPlayer = false;
- }
- deferred.resolve();
- },
- onError: function (x) {
- deferred.reject();
- },
- onStateChange: function (x) {
- thisObj.getPlayerState().then(function(playerState) {
- if (playerState === 'playing') {
- if (thisObj.hasSignLanguage && thisObj.signVideo) {
- thisObj.signVideo.play(true);
- }
- thisObj.playing = true;
- thisObj.startedPlaying = true;
- thisObj.paused = false;
- } else if (playerState == 'ended') {
- thisObj.onMediaComplete();
- } else {
- thisObj.playing = false;
- thisObj.paused = true;
- }
- if (thisObj.stoppingYouTube && playerState === 'paused') {
- if (thisObj.hasSignLanguage && thisObj.signVideo) {
- thisObj.signVideo.pause(true);
- }
- if (typeof thisObj.$posterImg !== 'undefined') {
- thisObj.$posterImg.show();
- }
- thisObj.stoppingYouTube = false;
- thisObj.seeking = false;
- thisObj.playing = false;
- thisObj.paused = true;
- }
- });
- if (thisObj.player === 'youtube' && !thisObj.usingYouTubeCaptions) {
- if (thisObj.youTubePlayer.getOptions('captions')) {
- thisObj.youTubePlayer.unloadModule('captions');
- }
- }
- },
- onApiChange: function() {
- thisObj.duration = thisObj.youTubePlayer.getDuration();
- },
- onPlaybackQualityChange: function () {
- },
- }
- });
- if (!this.hasPlaylist) {
- this.$media.remove();
- }
- return promise;
- };
-
- AblePlayer.prototype.getYouTubeDimensions = function (youTubeContainerId) {
-
- var $iframe, width, height;
-
- $iframe = this.$ableWrapper.find('iframe');
- if (typeof $iframe !== 'undefined') {
- if ($iframe.prop('width')) {
- width = $iframe.prop('width');
- if ($iframe.prop('height')) {
- height = $iframe.prop('height');
- this.resizePlayer(width,height);
- }
- }
- }
- };
-
- AblePlayer.prototype.getYouTubeCaptionTracks = function () {
-
- var deferred = new this.defer();
- var promise = deferred.promise();
- var thisObj, ytTracks, i, trackLang, trackLabel, isDefaultTrack, apiTriggered = false;
-
- thisObj = this;
- if (!this.youTubePlayer.getOption('captions','tracklist') ) {
- this.youTubePlayer.addEventListener('onApiChange',function() {
- apiTriggered = true;
- thisObj.duration = thisObj.youTubePlayer.getDuration();
-
- if (thisObj.loadingYouTubeCaptions) {
- ytTracks = thisObj.youTubePlayer.getOption('captions','tracklist');
- if ( ! thisObj.okToPlay ) {
- thisObj.youTubePlayer.pauseVideo();
- }
- if (ytTracks && ytTracks.length) {
- for (i=0; i < ytTracks.length; i++) {
- trackLang = ytTracks[i].languageCode;
- trackLabel = ytTracks[i].languageName;
- isDefaultTrack = false;
- if (typeof thisObj.captionLang !== 'undefined' && (trackLang === thisObj.captionLang) ) {
- isDefaultTrack = true;
- } else if (typeof thisObj.lang !== 'undefined') {
- if (trackLang === thisObj.lang) {
- isDefaultTrack = true;
- }
- }
- thisObj.tracks.push({
- 'kind': 'captions',
- 'language': trackLang,
- 'label': trackLabel,
- 'def': isDefaultTrack
- });
- thisObj.captions.push({
- 'language': trackLang,
- 'label': trackLabel,
- 'def': isDefaultTrack,
- 'cues': null
- });
- }
- thisObj.hasCaptions = true;
- thisObj.setupPopups('captions');
- } else {
- thisObj.usingYouTubeCaptions = false;
- thisObj.hasCaptions = false;
- }
- thisObj.loadingYouTubeCaptions = false;
- if (thisObj.okToPlay) {
- thisObj.youTubePlayer.playVideo();
- }
- }
- if (thisObj.captionLangPending) {
- thisObj.youTubePlayer.setOption('captions', 'track', {'languageCode': thisObj.captionLangPending});
- thisObj.captionLangPending = null;
- }
- if (typeof thisObj.prefCaptionsSize !== 'undefined') {
- thisObj.youTubePlayer.setOption('captions','fontSize',thisObj.translatePrefs('size',thisObj.prefCaptionsSize,'youtube'));
- }
- deferred.resolve();
- });
- this.loadingYouTubeCaptions = true;
- this.youTubePlayer.playVideo();
- setTimeout(() => {
- if ( ! apiTriggered ) {
- setTimeout(() => {
- thisObj.youTubePlayer.pauseVideo();
- deferred.resolve();
- }, 500);
- }
- },500);
- }
- return promise;
- };
-
- AblePlayer.prototype.getYouTubePosterUrl = function (youTubeId, width) {
-
- var url = 'https://img.youtube.com/vi/' + youTubeId;
- if (width == '120') {
- return url + '/default.jpg';
- } else if (width == '320') {
- return url + '/mqdefault.jpg';
- } else if (width == '480') {
- return url + '/hqdefault.jpg';
- } else if (width == '640') {
- return url + '/sddefault.jpg';
- } else if (width == '1280') {
- return url + '/hq720.jpg';
- } else if ( width == '1920' ) {
- return url + '/maxresdefault.jpg';
- }
- return false;
- };
-
- AblePlayer.prototype.getYouTubeId = function (url) {
-
-
- var idStartPos, id;
-
- if (url.indexOf('youtu') !== -1) {
- url = url.trim();
- idStartPos = url.length - 11;
- id = url.substring(idStartPos);
- return id;
- } else {
- return url;
- }
-};
-
-})(jQuery);
-
-(function ($) {
-
-
-
- window.AccessibleSlider = function(div, orientation, length, min, max, bigInterval, label, className, trackingMedia, initialState) {
-
-
- var thisObj, coords;
-
- thisObj = this;
-
- this.position = 0;
- this.tracking = false;
- this.trackDevice = null;
- this.keyTrackPosition = 0;
- this.lastTrackPosition = 0;
- this.nextStep = 1;
- this.inertiaCount = 0;
-
- this.bodyDiv = $(div);
-
- if (trackingMedia) {
- this.loadedDiv = $('
');
- this.playedDiv = $('
');
- }
-
- this.seekHead = $('
',{
- 'aria-orientation': orientation,
- 'class': 'able-' + className + '-head'
- });
-
- if (initialState === 'visible') {
- this.seekHead.attr('tabindex', '0');
- } else {
- this.seekHead.attr('tabindex', '-1');
- }
- this.seekHead.attr({
- 'role': 'slider',
- 'aria-label': label,
- 'aria-valuemin': min,
- 'aria-valuemax': max
- });
-
- this.timeTooltipTimeoutId = null;
- this.overTooltip = false;
- this.timeTooltip = $('
');
- this.bodyDiv.append(this.timeTooltip);
-
- this.timeTooltip.attr('role', 'tooltip');
- this.timeTooltip.addClass('able-tooltip');
- this.timeTooltip.on('mouseenter focus', function(){
- thisObj.overTooltip = true;
- clearInterval(thisObj.timeTooltipTimeoutId);
- });
- this.timeTooltip.on('mouseleave blur', function(){
- thisObj.overTooltip = false;
- $(this).hide();
- });
- this.timeTooltip.hide();
-
- this.bodyDiv.append(this.loadedDiv);
- this.bodyDiv.append(this.playedDiv);
- this.bodyDiv.append(this.seekHead);
-
- this.bodyDiv.wrap('
');
- this.wrapperDiv = this.bodyDiv.parent();
-
- if (this.skin === 'legacy') {
- if (orientation === 'horizontal') {
- this.wrapperDiv.width(length);
- this.loadedDiv.width(0);
- } else {
- this.wrapperDiv.height(length);
- this.loadedDiv.height(0);
- }
- }
- this.wrapperDiv.addClass('able-' + className + '-wrapper');
-
- if (trackingMedia) {
- this.loadedDiv.addClass('able-' + className + '-loaded');
-
- this.playedDiv.width(0);
- this.playedDiv.addClass('able-' + className + '-played');
-
- this.setDuration(max);
- }
-
- this.seekHead.on('mouseenter mouseleave mousemove mousedown mouseup focus blur touchstart touchmove touchend', function (e) {
-
- coords = thisObj.pointerEventToXY(e);
-
- if (e.type === 'mouseenter' || e.type === 'focus') {
- thisObj.overHead = true;
- } else if (e.type === 'mouseleave' || e.type === 'blur') {
- thisObj.overHead = false;
- if (!thisObj.overBody && thisObj.tracking && thisObj.trackDevice === 'mouse') {
- thisObj.stopTracking(thisObj.pageXToPosition(coords.x));
- }
- } else if (e.type === 'mousemove' || e.type === 'touchmove') {
- if (thisObj.tracking && thisObj.trackDevice === 'mouse') {
- thisObj.trackHeadAtPageX(coords.x);
- }
- } else if (e.type === 'mousedown' || e.type === 'touchstart') {
- thisObj.startTracking('mouse', thisObj.pageXToPosition(thisObj.seekHead.offset() + (thisObj.seekHead.width() / 2)));
- if (!thisObj.bodyDiv.is(':focus')) {
- thisObj.bodyDiv.focus();
- }
- e.preventDefault();
- } else if (e.type === 'mouseup' || e.type === 'touchend') {
- if (thisObj.tracking && thisObj.trackDevice === 'mouse') {
- thisObj.stopTracking(thisObj.pageXToPosition(coords.x));
- }
- }
- if (e.type !== 'mousemove' && e.type !== 'mousedown' && e.type !== 'mouseup' && e.type !== 'touchstart' && e.type !== 'touchend') {
- thisObj.refreshTooltip();
- }
- });
-
- this.bodyDiv.on(
- 'mouseenter mouseleave mousemove mousedown mouseup keydown keyup touchstart touchmove touchend', function (e) {
-
- if ( e.button == 2 && e.type == 'mousedown' ) {
- return;
- }
- coords = thisObj.pointerEventToXY(e);
- let keyPressed = e.key;
-
- if (e.type === 'mouseenter') {
- thisObj.overBody = true;
- thisObj.overBodyMousePos = {
- x: coords.x,
- y: coords.y
- };
- } else if (e.type === 'mouseleave') {
- thisObj.overBody = false;
- thisObj.overBodyMousePos = null;
- if (!thisObj.overHead && thisObj.tracking && thisObj.trackDevice === 'mouse') {
- thisObj.stopTracking(thisObj.pageXToPosition(coords.x));
- }
- } else if (e.type === 'mousemove' || e.type === 'touchmove') {
- thisObj.overBodyMousePos = {
- x: coords.x,
- y: coords.y
- };
- if (thisObj.tracking && thisObj.trackDevice === 'mouse') {
- thisObj.trackHeadAtPageX(coords.x);
- }
- } else if (e.type === 'mousedown' || e.type === 'touchstart') {
- thisObj.startTracking('mouse', thisObj.pageXToPosition(coords.x));
- thisObj.trackHeadAtPageX(coords.x);
- if (!thisObj.seekHead.is(':focus')) {
- thisObj.seekHead.focus();
- }
- e.preventDefault();
- } else if (e.type === 'mouseup' || e.type === 'touchend') {
- if (thisObj.tracking && thisObj.trackDevice === 'mouse') {
- thisObj.stopTracking(thisObj.pageXToPosition(coords.x));
- }
- } else if (e.type === 'keydown') {
- if (e.key === 'Home') {
- thisObj.trackImmediatelyTo(0);
- } else if (e.key === 'End') {
- thisObj.trackImmediatelyTo(thisObj.duration);
- } else if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') {
- thisObj.arrowKeyDown(-1);
- } else if (e.key === 'ArrowRight' || e.key === 'ArrowUp') {
- thisObj.arrowKeyDown(1);
- } else if (e.key === 'PageUp' && bigInterval > 0) {
- thisObj.arrowKeyDown(bigInterval);
- } else if (e.key === 'PageDown' && bigInterval > 0) {
- thisObj.arrowKeyDown(-bigInterval);
- } else {
- return;
- }
- e.preventDefault();
- } else if (e.type === 'keyup') {
- if ( keyPressed === e.key ) {
- if (thisObj.tracking && thisObj.trackDevice === 'keyboard') {
- thisObj.stopTracking(thisObj.keyTrackPosition);
- }
- e.preventDefault();
- }
- }
- if (!thisObj.overTooltip && e.type !== 'mouseup' && e.type !== 'keydown' && e.type !== 'keydown') {
- thisObj.refreshTooltip();
- }
- });
- }
-
- AccessibleSlider.prototype.arrowKeyDown = function (multiplier) {
- if (this.tracking && this.trackDevice === 'keyboard') {
- this.keyTrackPosition = this.boundPos(this.keyTrackPosition + (this.nextStep * multiplier));
- this.inertiaCount += 1;
- if (this.inertiaCount === 20) {
- this.inertiaCount = 0;
- this.nextStep *= 2;
- }
- this.trackHeadAtPosition(this.keyTrackPosition);
- } else {
- this.nextStep = 1;
- this.inertiaCount = 0;
- this.keyTrackPosition = this.boundPos(this.position + (this.nextStep * multiplier));
- this.startTracking('keyboard', this.keyTrackPosition);
- this.trackHeadAtPosition(this.keyTrackPosition);
- }
- };
-
- AccessibleSlider.prototype.pageXToPosition = function (pageX) {
- var offset = pageX - this.bodyDiv.offset().left;
- var position = this.duration * (offset / this.bodyDiv.width());
- return this.boundPos(position);
- };
-
- AccessibleSlider.prototype.boundPos = function (position) {
- return Math.max(0, Math.min(position, this.duration));
- }
-
- AccessibleSlider.prototype.setDuration = function (duration) {
- if (duration !== this.duration) {
- this.duration = duration;
- this.resetHeadLocation();
- this.seekHead.attr('aria-valuemax', duration);
- }
- };
-
- AccessibleSlider.prototype.setWidth = function (width) {
- this.wrapperDiv.width(width);
- this.resizeDivs();
- this.resetHeadLocation();
- };
-
- AccessibleSlider.prototype.getWidth = function () {
- return this.wrapperDiv.width();
- };
-
- AccessibleSlider.prototype.resizeDivs = function () {
- this.playedDiv.width(this.bodyDiv.width() * (this.position / this.duration));
- this.loadedDiv.width(this.bodyDiv.width() * this.buffered);
- };
-
- AccessibleSlider.prototype.resetHeadLocation = function () {
- var ratio = this.position / this.duration;
- var center = this.bodyDiv.width() * ratio;
- this.seekHead.css('left', center - (this.seekHead.width() / 2));
-
- if (this.tracking) {
- this.stopTracking(this.position);
- }
- };
-
- AccessibleSlider.prototype.setPosition = function (position, updateLive) {
- this.position = position;
- this.resetHeadLocation();
- if (this.overHead) {
- this.refreshTooltip();
- }
- this.resizeDivs();
- this.updateAriaValues(position, updateLive);
- }
-
- AccessibleSlider.prototype.setBuffered = function (ratio) {
- if (!isNaN(ratio)) {
- this.buffered = ratio;
- this.redrawDivs;
- }
- }
-
- AccessibleSlider.prototype.startTracking = function (device, position) {
- if (!this.tracking) {
- this.trackDevice = device;
- this.tracking = true;
- this.bodyDiv.trigger('startTracking', [position]);
- }
- };
-
- AccessibleSlider.prototype.stopTracking = function (position) {
- this.trackDevice = null;
- this.tracking = false;
- this.bodyDiv.trigger('stopTracking', [position]);
- this.setPosition(position, true);
- };
-
- AccessibleSlider.prototype.trackHeadAtPageX = function (pageX) {
- var position = this.pageXToPosition(pageX);
- var newLeft = pageX - this.bodyDiv.offset().left - (this.seekHead.width() / 2);
- newLeft = Math.max(0, Math.min(newLeft, this.bodyDiv.width() - this.seekHead.width()));
- this.lastTrackPosition = position;
- this.seekHead.css('left', newLeft);
- this.reportTrackAtPosition(position);
- };
-
- AccessibleSlider.prototype.trackHeadAtPosition = function (position) {
- var ratio = position / this.duration;
- var center = this.bodyDiv.width() * ratio;
- this.lastTrackPosition = position;
- this.seekHead.css('left', center - (this.seekHead.width() / 2));
- this.reportTrackAtPosition(position);
- };
-
- AccessibleSlider.prototype.reportTrackAtPosition = function (position) {
- this.bodyDiv.trigger('tracking', [position]);
- this.updateAriaValues(position, true);
- };
-
- AccessibleSlider.prototype.updateAriaValues = function (position, updateLive) {
- var pHours = Math.floor(position / 3600);
- var pMinutes = Math.floor((position % 3600) / 60);
- var pSeconds = Math.floor(position % 60);
-
- var pHourWord = pHours === 1 ? 'hour' : 'hours';
- var pMinuteWord = pMinutes === 1 ? 'minute' : 'minutes';
- var pSecondWord = pSeconds === 1 ? 'second' : 'seconds';
-
- var descriptionText;
- if (pHours > 0) {
- descriptionText = pHours +
- ' ' + pHourWord +
- ', ' + pMinutes +
- ' ' + pMinuteWord +
- ', ' + pSeconds +
- ' ' + pSecondWord;
- } else if (pMinutes > 0) {
- descriptionText = pMinutes +
- ' ' + pMinuteWord +
- ', ' + pSeconds +
- ' ' + pSecondWord;
- } else {
- descriptionText = pSeconds + ' ' + pSecondWord;
- }
-
- if (!this.liveAriaRegion) {
- this.liveAriaRegion = $('
', {
- 'class': 'able-offscreen',
- 'aria-live': 'polite'
- });
- this.wrapperDiv.append(this.liveAriaRegion);
- }
- if (updateLive && (this.liveAriaRegion.text() !== descriptionText)) {
- this.liveAriaRegion.text(descriptionText);
- }
-
- this.seekHead.attr('aria-valuetext', descriptionText);
- this.seekHead.attr('aria-valuenow', Math.floor(position).toString());
- };
-
- AccessibleSlider.prototype.trackImmediatelyTo = function (position) {
- this.startTracking('keyboard', position);
- this.trackHeadAtPosition(position);
- this.keyTrackPosition = position;
- };
-
- AccessibleSlider.prototype.refreshTooltip = function () {
- if (this.overHead) {
- this.timeTooltip.show();
- if (this.tracking) {
- this.timeTooltip.text(this.positionToStr(this.lastTrackPosition));
- } else {
- this.timeTooltip.text(this.positionToStr(this.position));
- }
- this.setTooltipPosition(this.seekHead.position().left + (this.seekHead.width() / 2));
- } else if (this.overBody && this.overBodyMousePos) {
- this.timeTooltip.show();
- this.timeTooltip.text(this.positionToStr(this.pageXToPosition(this.overBodyMousePos.x)));
- this.setTooltipPosition(this.overBodyMousePos.x - this.bodyDiv.offset().left);
- } else {
-
- clearTimeout(this.timeTooltipTimeoutId);
- var _this = this;
- this.timeTooltipTimeoutId = setTimeout(function() {
- _this.timeTooltip.hide();
- }, 500);
- }
- };
-
- AccessibleSlider.prototype.hideSliderTooltips = function () {
- this.overHead = false;
- this.overBody = false;
- this.timeTooltip.hide();
- };
-
- AccessibleSlider.prototype.setTooltipPosition = function (x) {
- this.timeTooltip.css({
- left: x - (this.timeTooltip.width() / 2) - 10,
- bottom: this.seekHead.height()
- });
- };
-
- AccessibleSlider.prototype.positionToStr = function (seconds) {
-
- var dHours = Math.floor(seconds / 3600);
- var dMinutes = Math.floor(seconds / 60) % 60;
- var dSeconds = Math.floor(seconds % 60);
- if (dSeconds < 10) {
- dSeconds = '0' + dSeconds;
- }
- if (dHours > 0) {
- if (dMinutes < 10) {
- dMinutes = '0' + dMinutes;
- }
- return dHours + ':' + dMinutes + ':' + dSeconds;
- } else {
- return dMinutes + ':' + dSeconds;
- }
- };
-
- AccessibleSlider.prototype.pointerEventToXY = function(e) {
-
- var out = {x:0, y:0};
- if (e.type == 'touchstart' || e.type == 'touchmove' || e.type == 'touchend' || e.type == 'touchcancel') {
- var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
- out.x = touch.pageX;
- out.y = touch.pageY;
- } else if (e.type == 'mousedown' || e.type == 'mouseup' || e.type == 'mousemove' || e.type == 'mouseover'|| e.type=='mouseout' || e.type=='mouseenter' || e.type=='mouseleave') {
- out.x = e.pageX;
- out.y = e.pageY;
- }
- return out;
- };
-
-})(jQuery);
-
-(function ($) {
-
- AblePlayer.prototype.addVolumeSlider = function($div) {
-
-
- var thisObj, volumeSliderId, volumeHelpId, volumePct, volumeLabel, volumeHeight;
-
- thisObj = this;
-
- volumeSliderId = this.mediaId + '-volume-slider';
- volumeHelpId = this.mediaId + '-volume-help';
-
- this.$volumeSlider = $('',{
- 'id': volumeSliderId,
- 'class': 'able-volume-slider',
- 'aria-hidden': 'true'
- }).hide();
- this.$volumeSliderTooltip = $('
',{
- 'class': 'able-tooltip',
- 'role': 'tooltip'
- }).hide();
- this.$volumeRange = $('
',{
- 'type': 'range',
- 'min': '0',
- 'max': '10',
- 'step': '1',
- 'orient': 'vertical',
- 'aria-label': this.translate( 'volumeUpDown', 'Volume up down' ),
- 'value': this.volume
- });
- volumePct = parseInt(thisObj.volume) / 10 * 100;
- this.$volumeHelp = $('
',{
- 'id': volumeHelpId,
- 'class': 'able-volume-help',
- 'aria-live': 'polite'
- }).text(volumePct + '%');
- volumeLabel = this.$volumeButton.attr( 'aria-label' );
- this.$volumeButton.attr( 'aria-label', volumeLabel + ' ' + volumePct + '%');
- this.$volumeSlider.append(this.$volumeSliderTooltip,this.$volumeRange,this.$volumeHelp);
- volumeHeight = this.$volumeButton.parents( '.able-control-row' )[0];
- this.$volumeSlider.css( 'bottom', volumeHeight.offsetHeight );
-
- $div.append(this.$volumeSlider);
-
- this.$volumeRange.on('change',function (e) {
- thisObj.handleVolumeChange($(this).val());
- });
-
- this.$volumeRange.on('input',function (e) {
- thisObj.handleVolumeChange($(this).val());
- });
-
- this.$volumeRange.on('keydown',function (e) {
-
- if (e.key === 'Escape' || e.key === 'Tab' || e.key === 'Enter') {
- if (thisObj.$volumeSlider.is(':visible')) {
- thisObj.closingVolume = true;
- thisObj.hideVolumePopup();
- } else {
- if (!thisObj.closingVolume) {
- thisObj.showVolumePopup();
- }
- }
- } else {
- return;
- }
- });
- };
-
- AblePlayer.prototype.refreshVolumeHelp = function(volume) {
-
- var volumePct;
- volumePct = (volume/10) * 100;
-
- if (this.$volumeHelp) {
- this.$volumeHelp.text(volumePct + '%');
- }
-
- this.$volumeRange.attr('value',volume);
- };
-
- AblePlayer.prototype.refreshVolumeButton = function(volume) {
-
- var volumeName, volumePct, volumeLabel;
-
- volumeName = this.getVolumeName(volume);
- volumePct = (volume/10) * 100;
- volumeLabel = this.translate( 'volume', 'Volume' ) + ' ' + volumePct + '%';
-
- this.getIcon( this.$volumeButton, 'volume-' + volumeName );
- this.$volumeButton.attr( 'aria-label', volumeLabel );
- };
-
- AblePlayer.prototype.handleVolumeButtonClick = function() {
-
- if (this.$volumeSlider.is(':visible')) {
- this.hideVolumePopup();
- } else {
- this.showVolumePopup();
- }
- };
-
- AblePlayer.prototype.handleVolumeKeystroke = function(volume) {
- if (this.isMuted() && volume > 0) {
- this.setMute(false);
- } else if (volume === 0) {
- this.setMute(true);
- } else {
- this.setVolume(volume);
- this.refreshVolumeHelp(volume);
- this.refreshVolumeButton(volume);
- }
- };
-
-
- AblePlayer.prototype.handleVolumeChange = function(volume) {
-
-
- if (this.isMuted() && volume > 0) {
- this.setMute(false);
- } else if (volume === 0) {
- this.setMute(true);
- } else {
- this.setVolume(volume);
- this.refreshVolumeHelp(volume);
- this.refreshVolumeButton(volume);
- }
- };
-
- AblePlayer.prototype.handleMute = function() {
-
- if (this.isMuted()) {
- this.setMute(false);
- } else {
- this.setMute(true);
- }
- };
-
- AblePlayer.prototype.showVolumePopup = function() {
-
- this.closePopups();
- this.$tooltipDiv.hide();
- this.$volumeSlider.show().attr('aria-hidden','false');
- this.$volumeButton.attr('aria-expanded','true');
- this.$volumeButton.focus();
- this.waitThenFocus(this.$volumeRange);
- };
-
- AblePlayer.prototype.hideVolumePopup = function() {
-
- var thisObj = this;
-
- this.$volumeSlider.hide().attr('aria-hidden','true');
- this.$volumeButton.attr('aria-expanded','false').focus();
- setTimeout(function() {
- thisObj.closingVolume = false;
- }, 1000);
- };
-
- AblePlayer.prototype.isMuted = function () {
-
- if (this.player === 'html5') {
- return this.media.muted;
- } else if (this.player === 'youtube') {
- return this.youTubePlayer.isMuted();
- }
- };
-
- AblePlayer.prototype.setMute = function(mute) {
-
- if (mute) {
- this.lastVolume = this.volume;
- this.volume = 0;
- } else {
- if (typeof this.lastVolume !== 'undefined') {
- this.volume = this.lastVolume;
- }
- }
-
- if (this.player === 'html5') {
- this.media.muted = mute;
- } else if (this.player === 'youtube') {
- if (mute) {
- this.youTubePlayer.mute();
- } else {
- this.youTubePlayer.unMute();
- }
- }
- this.setVolume(this.volume);
- this.refreshVolumeHelp(this.volume);
- this.refreshVolumeButton(this.volume);
- };
-
- AblePlayer.prototype.setVolume = function (volume) {
-
-
- var newVolume;
- this.syncSignVideo( {'volume' : 0 } );
- if (this.player === 'html5') {
- newVolume = volume / 10;
- this.media.volume = newVolume;
- } else if (this.player === 'youtube') {
- newVolume = volume * 10;
- this.youTubePlayer.setVolume(newVolume);
- this.volume = volume;
- } else if (this.player === 'vimeo') {
- newVolume = volume / 10;
- this.vimeoPlayer.setVolume(newVolume).then(function() {
- });
- }
- this.lastVolume = volume;
- };
-
- AblePlayer.prototype.getVolume = function (volume) {
-
- if (this.player === 'html5') {
- return this.media.volume * 10;
- } else if (this.player === 'youtube') {
- if (this.youTubePlayerReady) {
- return this.youTubePlayer.getVolume() / 10;
- }
- }
- if (this.player === 'vimeo') {
- return this.volume;
- }
- };
-
- AblePlayer.prototype.getVolumeName = function (volume) {
-
- if (volume == 0) {
- return 'mute';
- } else if (volume == 10) {
- return 'loud';
- } else if (volume < 5) {
- return 'soft';
- } else {
- return 'medium';
- }
- };
-
-})(jQuery);
-
-(function ($) {
- var focusableElementsSelector = "a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]";
-
- window.AccessibleDialog = function( modalDiv, $returnElement, title, closeButtonLabel) {
-
- this.title = title;
- this.closeButtonLabel = closeButtonLabel;
- this.focusedElementBeforeModal = $returnElement;
- this.baseId = $(modalDiv).attr('id') || Math.floor(Math.random() * 1000000000).toString();
- var thisObj = this;
- var modal = modalDiv;
- this.modal = modal;
-
- modal.addClass('able-modal-dialog');
-
- var closeButton = $('
',{
- 'class': 'modalCloseButton',
- 'title': thisObj.closeButtonLabel,
- 'aria-label': thisObj.closeButtonLabel
- }).text('×');
- closeButton.on( 'keydown', function (e) {
- if (e.key === ' ') {
- thisObj.hide();
- }
- }).on( 'click', function () {
- thisObj.hide();
- });
-
- var titleH1 = $(' ');
- titleH1.attr('id', 'modalTitle-' + this.baseId);
- titleH1.text(title);
- this.titleH1 = titleH1;
-
- modal.attr({
- 'aria-labelledby': 'modalTitle-' + this.baseId,
- });
- var modalHeader = $( '', {
- 'class': 'able-modal-header'
- });
- modalHeader.prepend(titleH1);
- modalHeader.prepend(closeButton);
- modal.prepend(modalHeader);
-
- modal.attr({
- 'aria-hidden': 'true',
- 'role': 'dialog',
- 'aria-modal': 'true'
- });
-
- modal.on( 'keydown', function (e) {
- if (e.key === 'Escape') {
- thisObj.hide();
- e.preventDefault();
- } else if (e.key === 'Tab') {
- var parts = modal.find('*');
- var focusable = parts.filter(focusableElementsSelector).filter(':visible');
-
- if (focusable.length === 0) {
- return;
- }
-
- var focused = $(':focus');
- var currentIndex = focusable.index(focused);
- if (e.shiftKey) {
- if (currentIndex === 0) {
- focusable.get(focusable.length - 1).trigger('focus');
- e.preventDefault();
- }
- } else {
- if (currentIndex === focusable.length - 1) {
- focusable.get(0).trigger('focus');
- e.preventDefault();
- }
- }
- }
- e.stopPropagation();
- });
-
- if ( $( 'body' ).hasClass( 'able-modal-active' ) ) {
- $( 'body > *') .not('.able-modal-overlay').not('.able-modal-dialog').removeAttr('inert');
- $( 'body' ).removeClass( 'able-modal-active' );
- }
- };
-
- AccessibleDialog.prototype.show = function () {
- if (!this.overlay) {
- var overlay = $('
').attr({
- 'class': 'able-modal-overlay',
- 'tabindex': '-1'
- });
- this.overlay = overlay;
- $('body').append(overlay);
-
- overlay.on('mousedown.accessibleModal', function (e) {
- e.preventDefault();
- thisObj.hide();
- });
- }
-
- $('body > *').not('.able-modal-overlay').not('.able-modal-dialog').attr('inert', true);
- $( 'body' ).addClass( 'able-modal-active' );
-
- this.overlay.css('display', 'block');
- this.modal.css('display', 'block');
- this.modal.attr({
- 'aria-hidden': 'false',
- 'tabindex': '-1'
- });
-
- var focusable = this.modal.find("*").filter(focusableElementsSelector).filter(':visible');
- if (focusable.length === 0) {
- this.focusedElementBeforeModal.blur();
- }
- var thisObj = this;
- setTimeout(function () {
- thisObj.modal.find('button.modalCloseButton').first().trigger('focus');
- }, 300);
- };
-
- AccessibleDialog.prototype.hide = function () {
- if (this.overlay) {
- this.overlay.css('display', 'none');
- }
- this.modal.css('display', 'none');
- this.modal.attr('aria-hidden', 'true');
- $('body > *').not('.able-modal-overlay').not('.able-modal-dialog').removeAttr('inert');
- $( 'body' ).removeClass( 'able-modal-active' );
-
- this.focusedElementBeforeModal.trigger('focus');
- };
-
- AccessibleDialog.prototype.getInputs = function () {
-
- if (this.modal) {
- var inputs = this.modal.find('input');
- return inputs;
- }
- return false;
- };
-
-})(jQuery);
-
-(function ($) {
- AblePlayer.prototype.getNextHeadingLevel = function ($element) {
-
- var $parents, $foundHeadings, numHeadings, headingType, headingNumber;
-
- $parents = $element.parents();
- $parents.each(function () {
- $foundHeadings = $(this).children(":header");
- numHeadings = $foundHeadings.length;
- if (numHeadings) {
- headingType = $foundHeadings.eq(numHeadings - 1).prop("tagName");
+ // For some browsers, `attr` is undefined; for others,
+ // `attr` is false. Check for both.
+ if (typeof attr !== typeof undefined && attr !== false) {
+ return true;
+ } else {
return false;
}
- });
- if (typeof headingType === "undefined") {
- headingNumber = 1;
- } else {
- headingNumber = parseInt(headingType[1]);
- headingNumber += 1;
- if (headingNumber > 6) {
- headingNumber = 6;
- }
- }
- return headingNumber;
- };
+ };
- AblePlayer.prototype.countProperties = function (obj) {
- var count, prop;
- count = 0;
- for (prop in obj) {
- if (obj.hasOwnProperty(prop)) {
- ++count;
- }
- }
- return count;
- };
+ }
+
+ /* global Cookies */
+
+ function addPreferenceFunctions(AblePlayer) {
+ AblePlayer.prototype.setPrefs = function(preferences) {
+ if ( typeof Cookies !== 'undefined' ) {
+ Cookies.set('Able-Player', JSON.stringify(preferences), {
+ expires: 90,
+ sameSite: 'strict'
+ });
+ } else {
+ localStorage.setItem( 'Able-Player', JSON.stringify( preferences ) );
+ }
+ };
+
+ AblePlayer.prototype.getPref = function() {
+
+ var defaultPrefs = {
+ preferences: {},
+ sign: {},
+ transcript: {},
+ voices: []
+ };
+
+ var preferences;
+ try {
+ if ( typeof Cookies !== 'undefined' ) {
+ preferences = JSON.parse( Cookies.get('Able-Player') );
+ } else {
+ preferences = JSON.parse( localStorage.getItem('Able-Player') );
+ }
+ }
+ catch (err) {
+ // Original preferences can't be parsed; update to default
+ this.setPrefs( defaultPrefs );
+ preferences = defaultPrefs;
+ }
+ return (preferences) ? preferences : defaultPrefs;
+ };
+
+ AblePlayer.prototype.updatePreferences = function( setting ) {
+ // useful for settings updated independently of Preferences dialog
+ // e.g., prefAutoScrollTranscript, which is updated in control.js > handleTranscriptLockToggle()
+ // setting is any supported preference name (e.g., "prefCaptions")
+ // OR 'transcript' or 'sign' (not user-defined preferences, used to save position of draggable windows)
+ var preferences, $window, windowPos, available, i, prefName, voiceLangFound, newVoice;
+ preferences = this.getPref();
+ if (setting === 'transcript' || setting === 'sign') {
+ if (setting === 'transcript') {
+ $window = this.$transcriptArea;
+ windowPos = $window.position();
+ if (typeof preferences.transcript === 'undefined') {
+ preferences.transcript = {};
+ }
+ preferences.transcript['position'] = $window.css('position'); // either 'relative' or 'absolute'
+ preferences.transcript['zindex'] = $window.css('z-index');
+ preferences.transcript['top'] = windowPos.top;
+ preferences.transcript['left'] = windowPos.left;
+ preferences.transcript['width'] = $window.width();
+ preferences.transcript['height'] = $window.height();
+ } else if (setting === 'sign') {
+ $window = this.$signWindow;
+ windowPos = $window.position();
+ if (typeof preferences.sign === 'undefined') {
+ preferences.sign = {};
+ }
+ preferences.sign['position'] = $window.css('position'); // either 'relative' or 'absolute'
+ preferences.sign['zindex'] = $window.css('z-index');
+ preferences.sign['top'] = windowPos.top;
+ preferences.sign['left'] = windowPos.left;
+ preferences.sign['width'] = $window.width();
+ preferences.sign['height'] = $window.height();
+ }
+ } else if (setting === 'voice') {
+ if (typeof preferences.voices === 'undefined') {
+ preferences.voices = [];
+ }
+ // replace preferred voice for this lang in preferences.voices array, if one exists
+ // otherwise, add it to the array
+ voiceLangFound = false;
+ for (var v=0; v < preferences.voices.length; v++) {
+ if (preferences.voices[v].lang === this.prefDescVoiceLang) {
+ voiceLangFound = true;
+ preferences.voices[v].name = this.prefDescVoice;
+ }
+ }
+ if (!voiceLangFound) {
+ // no voice has been saved yet for this language. Add it to array.
+ newVoice = {'name':this.prefDescVoice, 'lang':this.prefDescVoiceLang};
+ preferences.voices.push(newVoice);
+ }
+ } else {
+ available = this.getAvailablePreferences();
+ // Rebuild preferences with current preferences values,
+ // replacing the one value that's been changed
+ for (i = 0; i < available.length; i++) {
+ prefName = available[i]['name'];
+ if (prefName == setting) {
+ // this is the one that requires an update
+ preferences.preferences[prefName] = this[prefName];
+ }
+ }
+ }
+ // Save updated preferences
+ this.setPrefs(preferences);
+ };
+
+ AblePlayer.prototype.getPreferencesGroups = function() {
+
+ // return array of groups in the order in which they will appear
+ // in the Preferences popup menu
+ // Human-readable label for each group is defined in translation table
+ if (this.usingYouTubeCaptions) {
+ // no transcript is possible
+ return ['captions','descriptions','keyboard'];
+ } else if (this.usingVimeoCaptions) {
+ // users cannot control caption appearance
+ // and no transcript is possible
+ return ['descriptions','keyboard'];
+ } else {
+ return ['captions','descriptions','keyboard','transcript'];
+ }
+ };
+
+ AblePlayer.prototype.getAvailablePreferences = function() {
+
+ // Return the list of currently available preferences.
+ // Preferences with no 'label' are set within player, not shown in Prefs dialog
+ var prefs = [];
+
+ // Modifier keys preferences
+ prefs.push({
+ 'name': 'prefAltKey', // use alt key with shortcuts
+ 'label': this.translate( 'prefAltKey', 'Alt' ),
+ 'group': 'keyboard',
+ 'default': 1
+ });
+ prefs.push({
+ 'name': 'prefCtrlKey', // use ctrl key with shortcuts
+ 'label': this.translate( 'prefCtrlKey', 'Control' ),
+ 'group': 'keyboard',
+ 'default': 1
+ });
+ prefs.push({
+ 'name': 'prefShiftKey',
+ 'label': this.translate( 'prefShiftKey', 'Shift' ),
+ 'group': 'keyboard',
+ 'default': 0
+ });
+ prefs.push({
+ 'name': 'prefNoKeyShortcuts',
+ 'label': this.translate( 'prefNoKeyShortcuts', 'Disable Keyboard Shortcuts' ),
+ 'group': 'keyboard',
+ 'default': 0
+ });
+
+ // Transcript preferences
+ prefs.push({
+ 'name': 'prefTranscript', // transcript default state
+ 'label': null,
+ 'group': 'transcript',
+ 'default': 0 // off because turning it on has a certain WOW factor
+ });
+ prefs.push({
+ 'name': 'prefHighlight', // highlight transcript as media plays
+ 'label': this.translate( 'prefHighlight', 'Highlight transcript as media plays' ),
+ 'group': 'transcript',
+ 'default': 1 // on because many users can benefit
+ });
+ prefs.push({
+ 'name': 'prefAutoScrollTranscript',
+ 'label': null,
+ 'group': 'transcript',
+ 'default': 1
+ });
+ prefs.push({
+ 'name': 'prefTabbable', // tab-enable transcript
+ 'label': this.translate( 'prefTabbable', 'Keyboard-enable transcript' ),
+ 'group': 'transcript',
+ 'default': 0 // off because if users don't need it, it impedes tabbing elsewhere on the page
+ });
+
+ // Caption preferences
+ prefs.push({
+ 'name': 'prefCaptions', // closed captions default state
+ 'label': null,
+ 'group': 'captions',
+ 'default': this.defaultStateCaptions
+ });
+
+ if (!this.usingYouTubeCaptions) {
+
+ /* // not supported yet
+ prefs.push({
+ 'name': 'prefCaptionsStyle',
+ 'label': this.translate( 'prefCaptionsStyle', 'Style' ),
+ 'group': 'captions',
+ 'default': this.translate( 'captionsStylePopOn', 'Pop-on' )
+ });
+ */
+ // captions are always positioned above the player for audio
+ if (this.mediaType === 'video') {
+ prefs.push({
+ 'name': 'prefCaptionsPosition',
+ 'label': this.translate( 'prefCaptionsPosition', 'Position' ),
+ 'group': 'captions',
+ 'default': this.defaultCaptionsPosition
+ });
+ }
+ prefs.push({
+ 'name': 'prefCaptionsFont',
+ 'label': this.translate( 'prefCaptionsFont', 'Font' ),
+ 'group': 'captions',
+ 'default': 'sans-serif'
+ });
+ }
+ // This is the one option that is supported by YouTube IFrame API
+ prefs.push({
+ 'name': 'prefCaptionsSize',
+ 'label': this.translate( 'prefCaptionsSize', 'Font size' ),
+ 'group': 'captions',
+ 'default': '100%'
+ });
+
+ if (!this.usingYouTubeCaptions) {
+
+ prefs.push({
+ 'name': 'prefCaptionsColor',
+ 'label': this.translate( 'prefCaptionsColor', 'Text Color' ),
+ 'group': 'captions',
+ 'default': 'white'
+ });
+ prefs.push({
+ 'name': 'prefCaptionsBGColor',
+ 'label': this.translate( 'prefCaptionsBGColor', 'Background' ),
+ 'group': 'captions',
+ 'default': 'black'
+ });
+ prefs.push({
+ 'name': 'prefCaptionsOpacity',
+ 'label': this.translate( 'prefCaptionsOpacity', 'Opacity' ),
+ 'group': 'captions',
+ 'default': '100%'
+ });
+ prefs.push({
+ 'name': 'prefCaptionsSpeak',
+ 'label': this.translate( 'prefVoicedCaptions', 'Spoken Captions' ),
+ 'group': 'captions',
+ 'default': 0
+ });
+ prefs.push({
+ 'name': 'prefCaptionsVoice',
+ 'label': this.translate( 'prefDescVoice', 'Voice' ),
+ 'group': 'captions',
+ 'default': null // will be set later, in injectPrefsForm()
+ });
+ prefs.push({
+ 'name': 'prefCaptionsPitch',
+ 'label': this.translate( 'prefDescPitch', 'Pitch' ),
+ 'group': 'captions',
+ 'default': 1 // 0 to 2
+ });
+ prefs.push({
+ 'name': 'prefCaptionsRate',
+ 'label': this.translate( 'prefCaptionRate', 'Spoken Caption Rate' ),
+ 'group': 'captions',
+ 'default': 1.2 // 0.1 to 10 (1 is normal speech; 2 is fast but decipherable; >2 is super fast)
+ });
+ prefs.push({
+ 'name': 'prefCaptionsVolume',
+ 'label': this.translate( 'volume', 'Volume' ),
+ 'group': 'captions',
+ 'default': 1 // 0 to 1
+ });
+ }
+
+ if (this.mediaType === 'video') {
+ // Description preferences
+ prefs.push({
+ 'name': 'prefDesc', // audio description default state
+ 'label': null,
+ 'group': 'descriptions',
+ 'default': this.defaultStateDescriptions
+ });
+ prefs.push({
+ 'name': 'prefDescMethod', // audio description default format (if both 'video' and 'text' are available)
+ 'label': null,
+ 'group': 'descriptions',
+ 'default': 'video' // video (an alternative described version) always wins
+ });
+ prefs.push({
+ 'name': 'prefDescVoice',
+ 'label': this.translate( 'prefDescVoice', 'Voice' ),
+ 'group': 'descriptions',
+ 'default': null // will be set later, in injectPrefsForm()
+ });
+ prefs.push({
+ 'name': 'prefDescPitch',
+ 'label': this.translate( 'prefDescPitch', 'Pitch' ),
+ 'group': 'descriptions',
+ 'default': 1 // 0 to 2
+ });
+ prefs.push({
+ 'name': 'prefDescRate',
+ 'label': this.translate( 'prefDescRate', 'Spoken Description Rate' ),
+ 'group': 'descriptions',
+ 'default': 1 // 0.1 to 10 (1 is normal speech; 2 is fast but decipherable; >2 is super fast)
+ });
+ prefs.push({
+ 'name': 'prefDescVolume',
+ 'label': this.translate( 'volume', 'Volume' ),
+ 'group': 'descriptions',
+ 'default': 1 // 0 to 1
+ });
+ // Don't enable pause option if video described files in use.
+ if ( this.descMethod !== 'video' ) {
+ prefs.push({
+ 'name': 'prefDescPause', // automatically pause when closed description starts
+ 'label': this.translate( 'prefDescPause', 'Automatically pause video when description starts' ),
+ 'group': 'descriptions',
+ 'default': this.defaultDescPause
+ });
+ }
+ prefs.push({
+ 'name': 'prefDescVisible', // visibly show closed description (if avilable and used)
+ 'label': this.translate( 'prefDescVisible', 'Make description visible' ),
+ 'group': 'descriptions',
+ 'default': 0 // off as of 4.3.16, to avoid overloading the player with visible features
+ });
+ }
+ // Preferences without a category (not shown in Preferences dialogs)
+ prefs.push({
+ 'name': 'prefSign', // open sign language window by default if avilable
+ 'label': null,
+ 'group': null,
+ 'default': 0 // off because clicking an icon to see the sign window has a powerful impact
+ });
+
+ return prefs;
+ };
+
+ AblePlayer.prototype.loadCurrentPreferences = function () {
+
+ // Load current/default preferences into the AblePlayer object.
+
+ var available = this.getAvailablePreferences();
+ var preferences = this.getPref();
+ // Copy current preferences values into this object, and fill in any default values.
+ for (var ii = 0; ii < available.length; ii++) {
+ var prefName = available[ii]['name'];
+ var defaultValue = available[ii]['default'];
+ if (preferences.preferences[prefName] !== undefined) {
+ this[prefName] = preferences.preferences[prefName];
+ } else {
+ preferences.preferences[prefName] = defaultValue;
+ this[prefName] = defaultValue;
+ }
+ }
+
+ // Also load array of preferred voices from preferences
+ if (typeof preferences.voices !== 'undefined') {
+ this.prefVoices = preferences.voices;
+ }
+
+ this.setPrefs(preferences);
+ };
+
+ AblePlayer.prototype.injectPrefsForm = function (form) {
+
+ // Creates a preferences form and injects it.
+ // form is one of the supported forms (groups) defined in getPreferencesGroups()
+
+ var thisObj, available,
+ $prefsDiv, formTitle, introText, $prefsIntro,$prefsIntroP2,p3Text,$prefsIntroP3,i, j,
+ $fieldset, fieldsetClass, fieldsetId, $legend, legendId, thisPref, $thisDiv, thisClass,
+ thisId, $thisLabel, $thisField, captionsOptions,options,$thisOption,optionValue,optionLang,optionText,
+ changedPref,changedSpan,changedText, currentDescState, prefDescVoice, prefCaptionVoice, $kbHeading,$kbList,
+ kbLabels,keys,kbListText,$kbListItem, dialog,$saveButton,$cancelButton,$buttonContainer;
+
+ thisObj = this;
+ available = this.getAvailablePreferences();
+
+ // outer container, will be assigned role="dialog"
+ $prefsDiv = $('
',{
+ 'class': 'able-prefs-form '
+ });
+ var customClass = 'able-prefs-form-' + form;
+ $prefsDiv.addClass(customClass);
+
+ // add titles and intros
+ if (form == 'captions') {
+ formTitle = this.translate( 'prefTitleCaptions', 'Captions Preferences' );
+ } else if (form == 'descriptions') {
+ formTitle = this.translate( 'prefTitleDescriptions', 'Audio Description Preferences' );
+ $prefsIntro = $('
',{
+ text: this.translate( 'prefIntroDescription1', 'This media player supports audio description in two ways: ' )
+ });
+ var $prefsIntroUL = $('
');
+ var $prefsIntroLI1 = $('',{
+ text: this.translate( 'prefDescFormatOption1', 'alternative described version of video' )
+ });
+ var $prefsIntroLI2 = $(' ',{
+ text: this.translate( 'prefDescFormatOption2', 'text-based description, announced by screen reader' )
+ });
+
+ $prefsIntroUL.append($prefsIntroLI1,$prefsIntroLI2);
+ let prefDescription1 = '';
+ let prefDescription2 = '';
+ let prefDescription3 = '';
+ let prefDescriptionNone = '';
+ if (this.hasOpenDesc && this.hasClosedDesc) {
+ prefDescription1 = this.translate( 'prefDescription1', 'The current video has an alternative described version and text-based description, announced by screen reader');
+ } else if (this.hasOpenDesc) {
+ prefDescription2 = this.translate( 'prefDescription2', 'The current video has an alternative described version.' );
+ } else if (this.hasClosedDesc) {
+ prefDescription3 = this.translate( 'prefDescription3', 'The current video has text-based description, announced by screen reader.');
+ } else {
+ prefDescriptionNone = this.translate( 'prefDescriptionNone', 'The current video has no audio description in either format.' );
+ }
+ currentDescState = prefDescription1 + prefDescription2 + prefDescription3 + prefDescriptionNone;
+ $prefsIntroP2 = $('',{
+ html: currentDescState
+ });
+
+ p3Text = this.translate( 'prefIntroDescription3', 'Use the following form to set your preferences related to text-based audio description.' );
+ if (this.hasOpenDesc || this.hasClosedDesc) {
+ p3Text += ' ' + this.translate( 'prefIntroDescription4', 'After you save your settings, audio description can be toggled on/off using the Description button.' );
+ }
+ $prefsIntroP3 = $('
',{
+ text: p3Text
+ });
+
+ $prefsDiv.append( $prefsIntro, $prefsIntroUL, $prefsIntroP2, $prefsIntroP3 );
+ } else if (form == 'keyboard') {
+ formTitle = this.translate( 'prefTitleKeyboard', 'Keyboard Preferences' );
+ introText = this.translate( 'prefIntroKeyboard1', 'The media player on this web page can be operated from anywhere on the page using keyboard shortcuts (see below for a list).' );
+ introText += ' ' + this.translate( 'prefIntroKeyboard2', 'Modifier keys (Shift, Alt, and Control) can be assigned below.' );
+ introText += ' ' + this.translate( 'prefIntroKeyboard3', 'NOTE: Some key combinations might conflict with keys used by your browser and/or other software applications. Try various combinations of modifier keys to find one that works for you.' );
+ $prefsIntro = $('
',{
+ text: introText
+ });
+ $prefsDiv.append($prefsIntro);
+ } else if (form == 'transcript') {
+ formTitle = this.translate( 'prefTitleTranscript', 'Transcript Preferences' );
+ }
+
+ $fieldset = $('
').attr('role','group');
+ fieldsetClass = 'able-prefs-' + form;
+ fieldsetId = this.mediaId + '-prefs-' + form;
+ legendId = fieldsetId + '-legend';
+ $fieldset.addClass(fieldsetClass).attr('id',fieldsetId);
+ if (form === 'keyboard') {
+ $legend = $('
' + this.translate( 'prefHeadingKeyboard1', 'Modifier keys used for shortcuts' ) + ' ');
+ $legend.attr('id',legendId);
+ $fieldset.attr('aria-labelledby',legendId);
+ $fieldset.append($legend);
+ } else if (form === 'descriptions') {
+ $legend = $('
' + this.translate( 'prefHeadingTextDescription', 'Text-based audio description' ) + ' ');
+ $legend.attr('id',legendId);
+ $fieldset.attr('aria-labelledby',legendId);
+ $fieldset.append($legend);
+ }
+ for (i=0; i
').addClass(thisClass + ' able-player-setting');
+ if (form === 'captions' ) {
+ $thisLabel = $(' ' + available[i]['label'] + ' ');
+ $thisField = $('',{
+ name: thisPref,
+ id: thisId,
+ });
+ // add a change handler that updates the style of the sample caption text
+ let viewingOptions = ['prefCaptionsPosition','prefCaptionsFont','prefCaptionsSize','prefCaptionsColor','prefCaptionsBGColor','prefCaptionsOpacity'];
+ if ( viewingOptions.indexOf(thisPref) !== -1 ) {
+ $thisField.on( 'change', function() {
+ changedPref = $(this).attr('name');
+ thisObj.stylizeCaptions(thisObj.$sampleCapsDiv,changedPref);
+ });
+ }
+ captionsOptions = this.getCaptionsOptions(thisPref);
+ if ( ! ( thisPref === 'prefCaptionsVoice' && ! this.descVoices.length ) ) {
+ $thisDiv.append($thisLabel,$thisField);
+ }
+ for (j=0; j < captionsOptions.length; j++) {
+ if (thisPref === 'prefCaptionsPosition') {
+ optionValue = captionsOptions[j];
+ if (optionValue === 'overlay') {
+ optionText = this.translate( 'captionsPositionOverlay', 'Overlay' );
+ } else if (optionValue === 'below') {
+ optionValue = captionsOptions[j];
+ optionText = this.translate( 'captionsPositionBelow', 'Below video' );
+ }
+ } else if (thisPref === 'prefCaptionsFont' || thisPref === 'prefCaptionsColor' || thisPref === 'prefCaptionsBGColor' || thisPref === 'prefCaptionsSpeak' ) {
+ optionValue = captionsOptions[j][0];
+ optionText = captionsOptions[j][1];
+ } else if (thisPref === 'prefCaptionsOpacity') {
+ optionValue = captionsOptions[j];
+ optionText = captionsOptions[j];
+ optionText += (optionValue === '0%') ? ' (' + this.translate( 'transparent', 'transparent' ) + ')' : ' (' + this.translate( 'solid', 'solid' ) + ')';
+ } else if (thisPref === 'prefCaptionsSize') {
+ optionValue = captionsOptions[j];
+ optionText = captionsOptions[j];
+ }
+ let voicingOptions = ['prefCaptionsPitch','prefCaptionsRate','prefCaptionsVolume'];
+ if ( optionValue && voicingOptions.indexOf(thisPref) === -1 ) {
+ $thisOption = $('',{
+ value: optionValue,
+ text: optionText
+ });
+ if (this[thisPref] === optionValue) {
+ $thisOption.prop('selected',true);
+ }
+ $thisField.append($thisOption);
+ }
+ // If synth is possible, show voicing options.
+ if ( this.synth ) {
+ if ( thisPref === 'prefCaptionsVoice' && this.descVoices.length ) {
+ prefCaptionVoice = this.getPrefVoice();
+ for (j=0; j < this.descVoices.length; j++) {
+ optionValue = this.descVoices[j].name;
+ optionLang = this.descVoices[j].lang.substring(0,2).toLowerCase();
+ optionText = optionValue + ' (' + this.descVoices[j].lang + ')';
+ $thisOption = $(' ',{
+ 'value': optionValue,
+ 'data-lang': optionLang,
+ text: optionText
+ });
+ if (prefCaptionVoice === optionValue) {
+ $thisOption.prop('selected',true);
+ }
+ $thisField.append($thisOption);
+ }
+ this.$voiceSelectField = $thisField;
+ } else {
+ if ( thisPref == 'prefCaptionsPitch' || thisPref == 'prefCaptionsRate' || thisPref == 'prefCaptionsVolume' ) {
+ options = false;
+ // Options values described in audio description preferences.
+ options = (thisPref == 'prefCaptionsPitch') ? [0,0.5,1,1.5,2] : options;
+ options = (thisPref == 'prefCaptionsRate') ? [0.7,0.8,0.9,1,1.1,1.2,1.5,2,2.5,3] : options;
+ options = (thisPref == 'prefCaptionsVolume') ? [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1] : options;
+ if ( options ) {
+ for (j=0; j < options.length; j++) {
+ optionValue = options[j];
+ optionText = this.makePrefsValueReadable(thisPref,optionValue);
+ $thisOption = $(' ',{
+ value: optionValue,
+ text: optionText
+ });
+ if (this[thisPref] == optionValue) {
+ $thisOption.prop('selected',true);
+ }
+ $thisField.append($thisOption);
+ }
+ // add a change handler that announces the sample text
+ $thisField.on('change',function() {
+ let captionSample = thisObj.translate( 'sampleCaptionText', 'Sample caption text' );
+ thisObj.announceText('captionSample',captionSample);
+ });
+ $thisDiv.append($thisLabel,$thisField);
+ }
+ }
+ }
+ }
+ }
+ } else if (form === 'descriptions') {
+ $thisLabel = $(' ' + available[i]['label'] + ' ');
+ if (thisPref === 'prefDescPause' || thisPref === 'prefDescVisible') {
+ // these preferences are checkboxes
+ $thisDiv.addClass('able-prefs-checkbox');
+ $thisField = $(' ',{
+ type: 'checkbox',
+ name: thisPref,
+ id: thisId,
+ value: 'true'
+ });
+ // check current active value for this preference
+ if (this[thisPref] === 1) {
+ $thisField.prop('checked',true);
+ }
+ $thisDiv.append($thisField,$thisLabel);
+ } else if (this.synth) {
+ // Only show these options if browser supports speech synthesis
+ $thisDiv.addClass('able-prefs-select');
+ $thisField = $('',{
+ name: thisPref,
+ id: thisId,
+ });
+ if ( thisPref === 'prefDescVoice' && this.descVoices.length) {
+ prefDescVoice = this.getPrefVoice();
+ for (j=0; j < this.descVoices.length; j++) {
+ optionValue = this.descVoices[j].name;
+ optionLang = this.descVoices[j].lang.substring(0,2).toLowerCase();
+ optionText = optionValue + ' (' + this.descVoices[j].lang + ')';
+ $thisOption = $('',{
+ 'value': optionValue,
+ 'data-lang': optionLang,
+ text: optionText
+ });
+ if (prefDescVoice === optionValue) {
+ $thisOption.prop('selected',true);
+ }
+ $thisField.append($thisOption);
+ }
+ this.$voiceSelectField = $thisField;
+ } else {
+ if (thisPref == 'prefDescPitch') { // 0 to 2
+ options = [0,0.5,1,1.5,2];
+ } else if (thisPref == 'prefDescRate') { // 0.1 to 10
+ // Tests with a variety of voices on MacOS and Windows
+ // yielded the following choices that seem reasonable for audio description:
+ // 0.5 - too slow (exclude this)
+ // 0.7 - casual
+ // 0.8 - add this
+ // 0.9 - add this
+ // 1 - normal
+ // 1.1 - add this
+ // 1.2 - add this
+ // 1.5 - quick
+ // 2 - speedy
+ // 2.5 - fleet
+ // 3 - fast! (some voices don't get any faster than this
+
+ // Note: if these values are modified, must also modfiy them
+ // in makePrefsValueReadable()
+ options = [0.7,0.8,0.9,1,1.1,1.2,1.5,2,2.5,3];
+ } else if (thisPref == 'prefDescVolume') { // 0 (mute) to 1
+ options = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1];
+ }
+ if (typeof options !== 'undefined') {
+ for (j=0; j < options.length; j++) {
+ optionValue = options[j];
+ optionText = this.makePrefsValueReadable(thisPref,optionValue);
+ $thisOption = $(' ',{
+ value: optionValue,
+ text: optionText
+ });
+ if (this[thisPref] == optionValue) {
+ $thisOption.prop('selected',true);
+ }
+ $thisField.append($thisOption);
+ $thisDiv.append($thisLabel,$thisField);
+ }
+ }
+ }
+ // add a change handler that announces the sample description text
+ $thisField.on('change',function() {
+ thisObj.announceText('sample',thisObj.currentSampleText);
+ });
+ $thisDiv.append($thisLabel,$thisField);
+ }
+ } else { // all other fields are checkboxes
+ $thisLabel = $(' ' + available[i]['label'] + ' ');
+ $thisField = $(' ',{
+ type: 'checkbox',
+ name: thisPref,
+ id: thisId,
+ value: 'true'
+ });
+ // check current active value for this preference
+ if (this[thisPref] === 1) {
+ $thisField.prop('checked',true);
+ }
+ if (form === 'keyboard') {
+ // add a change handler that updates the list of current keyboard shortcuts
+ $thisField.on('change',function() {
+ changedPref = $(this).attr('name');
+ if (changedPref === 'prefAltKey') {
+ changedSpan = '.able-modkey-alt';
+ changedText = thisObj.translate( 'prefAltKey', 'Alt' ) + ' + ';
+ } else if (changedPref === 'prefCtrlKey') {
+ changedSpan = '.able-modkey-ctrl';
+ changedText = thisObj.translate( 'prefCtrlKey', 'Control' ) + ' + ';
+ } else if (changedPref === 'prefShiftKey') {
+ changedSpan = '.able-modkey-shift';
+ changedText = thisObj.translate( 'prefShiftKey', 'Shift' ) + ' + ';
+ }
+ if ( changedPref !== 'prefNoKeyShortcuts' ) {
+ if ($(this).is(':checked')) {
+ $(changedSpan).text(changedText);
+ } else {
+ $(changedSpan).text('');
+ }
+ } else {
+ if ($(this).is(':checked')) {
+ $('.able-modkey-item').addClass('hidden');
+ } else {
+ $('.able-modkey-item').removeClass('hidden');
+ }
+ }
+ });
+ }
+ $thisDiv.append($thisField,$thisLabel);
+ }
+ if (thisPref === 'prefDescVoice' && !this.descVoices.length) ; else {
+ $fieldset.append($thisDiv);
+ }
+ }
+ }
+ $prefsDiv.append($fieldset);
+
+ if (form === 'captions') {
+ // add a sample closed caption div to prefs dialog
+ // do not show this for YouTube captions, since it's not an accurate reflection
+ if (!this.usingYouTubeCaptions) {
+ this.$sampleCapsDiv = $('',{
+ 'class': 'able-captions-sample'
+ }).text( this.translate( 'sampleCaptionText', 'Sample caption text' ) );
+ $prefsDiv.append(this.$sampleCapsDiv);
+ this.stylizeCaptions(this.$sampleCapsDiv);
+ }
+ } else if (form === 'descriptions') {
+ if (this.synth) {
+ // add a div with sample audio description text
+ this.$sampleDescDiv = $('
',{
+ 'class': 'able-desc-sample'
+ }).text( this.translate( 'sampleDescriptionText', 'Adjust settings to hear this sample text.' ) );
+ $prefsDiv.append(this.$sampleDescDiv);
+ this.currentSampleText = this.translate( 'sampleDescriptionText', 'Adjust settings to hear this sample text.' );
+ }
+ } else if (form === 'keyboard') {
+ let shortcutClass = (this.prefNoKeyShortcuts === 1 ) ? 'able-modkey-item hidden' : 'able-modkey-item';
+
+ // add a current list of keyboard shortcuts
+ $kbHeading = $('
',{
+ text: this.translate( 'prefHeadingKeyboard2', 'Current keyboard shortcuts' )
+ });
+ $kbList = $('');
+ // create arrays of kbLabels and keys
+ kbLabels = [];
+ keys = [];
+ for (i=0; i, ' + this.translate( 'spacebar', 'spacebar' ));
+ } else if (this.controls[i] === 'restart') {
+ kbLabels.push(this.translate( 'restart', 'Restart' ));
+ keys.push('s');
+ } else if (this.controls[i] === 'previous') {
+ kbLabels.push( this.translate( 'prevTrack', 'Previous track' ) );
+ keys.push('b'); // b = back
+ } else if (this.controls[i] === 'next') {
+ kbLabels.push( this.translate( 'nextTrack', 'Next track' ) );
+ keys.push('n');
+ } else if (this.controls[i] === 'rewind') {
+ kbLabels.push(this.translate( 'rewind', 'Rewind' ));
+ keys.push('r');
+ } else if (this.controls[i] === 'forward') {
+ kbLabels.push(this.translate( 'forward', 'Forward' ));
+ keys.push('f');
+ } else if (this.controls[i] === 'volume') {
+ kbLabels.push(this.translate( 'volume', 'Volume' ));
+ keys.push('v ,' + ' 1-9');
+ // mute toggle
+ kbLabels.push(this.translate( 'mute', 'Mute' ) + '/' + this.translate( 'unmute', 'Unmute' ));
+ keys.push('m');
+ } else if (this.controls[i] === 'captions') {
+ if (this.captions.length > 1) {
+ // caption button launches a Captions popup menu
+ kbLabels.push(this.translate( 'captions', 'Captions' ));
+ } else {
+ // there is only one caption track
+ // therefore caption button is a toggle
+ if (this.captionsOn) {
+ kbLabels.push(this.translate( 'hideCaptions', 'Hide captions' ));
+ } else {
+ kbLabels.push(this.translate( 'showCaptions', 'Show captions' ));
+ }
+ }
+ keys.push('c');
+ } else if (this.controls[i] === 'descriptions') {
+ if (this.descOn) {
+ kbLabels.push(this.translate( 'turnOffDescriptions', 'Turn off descriptions' ));
+ } else {
+ kbLabels.push(this.translate( 'turnOnDescriptions', 'Turn on descriptions' ));
+ }
+ keys.push('d');
+ } else if (this.controls[i] === 'prefs') {
+ kbLabels.push(this.translate( 'preferences', 'Preferences' ));
+ keys.push('e');
+ }
+ }
+ for (i=0; i';
+ // ctrl
+ kbListText += '';
+ if (this.prefCtrlKey === 1) {
+ kbListText += this.translate( 'prefCtrlKey', 'Control' ) + ' + ';
+ }
+ kbListText += ' ';
+ // shift
+ kbListText += '';
+ if (this.prefShiftKey === 1) {
+ kbListText += this.translate( 'prefShiftKey', 'Shift' ) + ' + ';
+ }
+ kbListText += ' ';
+ kbListText += '' + keys[i] + ' ';
+ kbListText += ' = ' + kbLabels[i];
+ $kbListItem = $('',{
+ 'class': shortcutClass,
+ html: kbListText,
+ });
+ $kbList.append($kbListItem);
+ }
+ // add Escape key
+ kbListText = '' + this.translate( 'escapeKey', 'Escape' ) + ' ';
+ kbListText += ' = ' + this.translate( 'escapeKeyFunction', 'Close current dialog or popup menu' );
+ $kbListItem = $(' ',{
+ html: kbListText
+ });
+ $kbList.append($kbListItem);
+ // put it all together
+ $prefsDiv.append($kbHeading,$kbList);
+ }
+
+ // $prefsDiv (dialog) must be appended to the BODY!
+ $('body').append($prefsDiv);
+ dialog = new AccessibleDialog(
+ $prefsDiv,
+ this.$prefsButton,
+ formTitle,
+ thisObj.translate( 'closeButtonLabel', 'Close' )
+ );
+
+ // Add save and cancel buttons.
+ $buttonContainer = $( '
' );
+ $saveButton = $('' + this.translate( 'save', 'Save' ) + ' ');
+ $cancelButton = $('' + this.translate( 'cancel', 'Cancel' ) + ' ');
+ $saveButton.on( 'click', function () {
+ dialog.hide();
+ thisObj.savePrefsFromForm();
+ });
+ $cancelButton.on( 'click', function () {
+ dialog.hide();
+ thisObj.resetPrefsForm();
+ });
+ $buttonContainer.append( $saveButton,$cancelButton );
+ $prefsDiv.append($buttonContainer);
+ // Associate the dialog's H1 as aria-labelledby for groups of fields
+ // (alternative to fieldset and legend)
+ if (form === 'captions' || form === 'transcript') {
+ $fieldset.attr('aria-labelledby',dialog.titleH1.attr('id'));
+ }
+
+ // add global reference for future control
+ if (form === 'captions') {
+ this.captionPrefsDialog = dialog;
+ } else if (form === 'descriptions') {
+ this.descPrefsDialog = dialog;
+ } else if (form === 'keyboard') {
+ this.keyboardPrefsDialog = dialog;
+ } else if (form === 'transcript') {
+ this.transcriptPrefsDialog = dialog;
+ }
+
+ // Add click handler for dialog close button
+ // (button is added in dialog.js)
+ $('div.able-prefs-form button.modalCloseButton').on( 'click', function() {
+ thisObj.resetPrefsForm();
+ });
+ // Add handler for escape key
+ $('div.able-prefs-form').on( 'keydown', function(e) {
+ if (e.key === 'Escape') {
+ thisObj.resetPrefsForm();
+ }
+ });
+ };
+
+ AblePlayer.prototype.getPrefVoice = function () {
+
+ // return user's preferred voice for the current language from preferences.voices
+ var lang, preferences, i;
+
+ if (this.selectedDescriptions) {
+ lang = this.selectedDescriptions.language;
+ } else if (this.captionLang) {
+ lang = this.captionLang;
+ } else {
+ lang = this.lang;
+ }
+ preferences = this.getPref();
+ if (preferences.voices) {
+ for (i=0; i < preferences.voices.length; i++) {
+ if (preferences.voices[i].lang === lang) {
+ return preferences.voices[i].name;
+ }
+ }
+ }
+ return null; // user has no saved preference
+ };
+
+ AblePlayer.prototype.rebuildVoicePrefsForm = function ( field ) {
+
+ // Called if this.descVoices changes, which may happen if:
+ // getBrowserVoices() succeeds after an earlier failure
+ // user changes language of captions/subtitles and descVoices changes to match the new language
+
+ var i, optionValue, optionText, $thisOption;
+
+ this.$voiceSelectField = $('#' + this.mediaId + field);
+ this.$voiceSelectField.empty();
+ for (i=0; i < this.descVoices.length; i++) {
+ optionValue = this.descVoices[i].name;
+ optionText = optionValue + ' (' + this.descVoices[i].lang + ')';
+ $thisOption = $('',{
+ 'value': optionValue,
+ 'data-lang': this.descVoices[i].lang.substring(0,2).toLowerCase(),
+ text: optionText
+ });
+ if (this.prefDescVoice == optionValue) {
+ $thisOption.prop('selected',true);
+ }
+ this.$voiceSelectField.append($thisOption);
+ }
+ };
+
+ AblePlayer.prototype.makePrefsValueReadable = function(pref,value) {
+
+ // The values for pitch, rate, and volume (web speech API)
+ // are strange and inconsistent between variables
+ // this function returns text that is more readable than the values themselves
+
+ if (pref === 'prefDescPitch' || pref === 'prefCaptionsPitch' ) {
+ if (value === 0) {
+ return this.translate( 'prefDescPitch1', 'Very low' );
+ } else if (value === 0.5) {
+ return this.translate( 'prefDescPitch2', 'Low' );
+ } else if (value === 1) {
+ return this.translate( 'prefDescPitch3', 'Default' );
+ } else if (value === 1.5) {
+ return this.translate( 'prefDescPitch4', 'High' );
+ } else if (value === 2) {
+ return this.translate( 'prefDescPitch5', 'Very high' );
+ }
+ } else if (pref === 'prefDescRate' || pref === 'prefCaptionsRate' ) {
+ // default in the API is 0.1 to 10, where 1 is normal speaking voice
+ // our custom range offers several rates close to 1
+ // plus a couple of crazy fast ones for sport
+ // Our more readable options (1-10) or mapped here to API values
+ if (value === 0.7) {
+ return 1;
+ } else if (value === 0.8) {
+ return 2;
+ } else if (value === 0.9) {
+ return 3;
+ } else if (value === 1) {
+ return 4;
+ } else if (value === 1.1) {
+ return 5;
+ } else if (value === 1.2) {
+ return 6;
+ } else if (value === 1.5) {
+ return 7;
+ } else if (value === 2) {
+ return 8;
+ } else if (value === 2.5) {
+ return 9;
+ } else if (value === 3) {
+ return 10;
+ }
+ } else if (pref === 'prefDescVolume' || pref === 'prefCaptionsVolume' ) {
+ // values range from 0.1 to 1.0
+ return value * 100 + '%';
+ }
+ return value;
+ };
+
+ AblePlayer.prototype.resetPrefsForm = function () {
+
+ // Reset preferences form with default values from preferences
+ // Called when:
+ // User clicks cancel or close button in Prefs Dialog
+ // User presses Escape to close Prefs dialog
+ // User clicks Save in Prefs dialog, & there's more than one player on page
+
+ var preferences, available, i, prefName;
+
+ preferences = this.getPref();
+ available = this.getAvailablePreferences();
+ for (i=0; i 0) {
+ this.setPrefs(preferences);
+ this.showAlert( this.translate( 'prefSuccess', 'Your changes have been saved.' ) );
+ } else {
+ this.showAlert( this.translate( 'prefNoChange', "You didn't make any changes" ) );
+ }
+ if (this.player === 'youtube' &&
+ (typeof this.usingYouTubeCaptions !== 'undefined' && this.usingYouTubeCaptions) &&
+ capSizeChanged) {
+ // update font size of YouTube captions
+ this.youTubePlayer.setOption('captions','fontSize',this.translatePrefs('size',capSizeValue,'youtube'));
+ }
+ if (!AblePlayer.hasSingleInstance()) {
+ // there are multiple players on this page.
+ // update prefs for ALL of them
+ for (const instance of AblePlayer.ablePlayerInstances) {
+ instance.updatePlayerPrefs();
+ instance.loadCurrentPreferences();
+ instance.resetPrefsForm();
+ if (numCapChanges > 0) {
+ instance.stylizeCaptions(instance.$captionsDiv);
+ // also apply same changes to descriptions, if present
+ if (typeof instance.$descDiv !== 'undefined') {
+ instance.stylizeCaptions(instance.$descDiv);
+ }
+ }
+ }
+ } else {
+ // there is only one player
+ this.updatePlayerPrefs();
+ if (numCapChanges > 0) {
+ this.stylizeCaptions(this.$captionsDiv);
+ // also apply same changes to descriptions, if present
+ if (typeof this.$descDiv !== 'undefined') {
+ this.stylizeCaptions(this.$descDiv);
+ }
+ }
+ }
+ };
+
+ AblePlayer.prototype.updatePlayerPrefs = function () {
+
+ // Update player based on current prefs. Safe to call multiple times.
+ if (this.$transcriptDiv) {
+ // tabbable transcript
+ if (this.prefTabbable === 1) {
+ this.$transcriptDiv.find('span.able-transcript-seekpoint').attr('tabindex','0');
+ } else {
+ this.$transcriptDiv.find('span.able-transcript-seekpoint').removeAttr('tabindex');
+ }
+
+ // transcript highlights
+ if (this.prefHighlight === 0) {
+ // user doesn't want highlights; remove any existing highlights
+ this.$transcriptDiv.find('span').removeClass('able-highlight');
+ }
+ }
+
+ // Re-initialize caption and description in case relevant settings have changed
+ this.updateCaption();
+ this.initDescription();
+ };
+
+ AblePlayer.prototype.usingModifierKeys = function(e) {
+
+ // return true if user is holding down required modifier keys
+ if ((this.prefAltKey === 1) && !e.altKey) {
+ return false;
+ }
+ if ((this.prefCtrlKey === 1) && !e.ctrlKey) {
+ return false;
+ }
+ if ((this.prefShiftKey === 1) && !e.shiftKey) {
+ return false;
+ }
+ return true;
+ };
+ }
- AblePlayer.prototype.formatSecondsAsColonTime = function (
- seconds,
- showFullTime
- ) {
-
- var dHours, dMinutes, dSeconds, parts, milliSeconds, numShort, i;
-
- if (showFullTime) {
- parts = seconds.toString().split(".");
- if (parts.length === 2) {
- milliSeconds = parts[1];
- if (milliSeconds.length < 3) {
- numShort = 3 - milliSeconds.length;
- for (i = 1; i <= numShort; i++) {
- milliSeconds += "0";
+ function addSearchFunctions(AblePlayer) {
+ AblePlayer.prototype.showSearchResults = function () {
+ // search VTT file for all instances of searchTerms
+ // Currently just supports search terms separated with one or more spaces
+
+ // TODO: Add support for more robust search syntax:
+ // Search terms wrapped in quotation marks ("") must occur exactly as they appear in the quotes
+ // Search terms with an attached minus sign (e.g., -term) are to be excluded from results
+ // Boolean AND/OR operators
+ // ALSO: Add localization support
+
+ var thisObj = this;
+ if (this.searchDiv && this.searchString) {
+ // sanitize search string
+ var cleanSearchString = purify.sanitize(this.searchString);
+ if ($("#" + this.SearchDiv)) {
+ var searchStringHtml = "" + this.translate( 'resultsSummary1', 'You searched for:') + ' ';
+ searchStringHtml +=
+ '' + cleanSearchString + " ";
+ searchStringHtml += "
";
+ var resultsArray = this.searchFor(
+ cleanSearchString,
+ this.searchIgnoreCaps
+ );
+ if (resultsArray.length > 0) {
+ var $resultsSummary = $("", {
+ class: "able-search-results-summary",
+ });
+ var resultsSummaryText = this.translate( 'resultsSummary2', 'Found %1 matching items.', [ '' + resultsArray.length + ' ' ] );
+ resultsSummaryText += ' ' + this.translate( 'resultsSummary3', 'Click the time associated with any item to play the video from that point.' );
+ $resultsSummary.html( resultsSummaryText );
+ var $resultsList = $("
");
+ for (var i = 0; i < resultsArray.length; i++) {
+ var resultId = "aria-search-result-" + i;
+ var $resultsItem = $("", {});
+ var itemStartTime = this.secondsToTime(resultsArray[i]["start"]);
+ var itemLabel =
+ this.translate( 'searchButtonLabel', 'Play at %1', [ itemStartTime["title"] ] );
+ var itemStartSpan = $("", {
+ class: "able-search-results-time",
+ "data-start": resultsArray[i]["start"],
+ "aria-label": itemLabel,
+ "aria-describedby": resultId,
+ });
+ itemStartSpan.text(itemStartTime["value"]);
+ // add a listener for clisk on itemStart
+ itemStartSpan.on("click", function (e) {
+ thisObj.seekTrigger = "search";
+ var spanStart = parseFloat($(this).attr("data-start"));
+ // Add a tiny amount so that we're inside the span.
+ spanStart += 0.01;
+ thisObj.seeking = true;
+ thisObj.seekTo(spanStart);
+ });
+
+ var itemText = $("", {
+ class: "able-search-result-text",
+ id: resultId,
+ });
+ itemText.html('...' + resultsArray[i]["caption"] + '...');
+ $resultsItem.append(itemStartSpan, itemText);
+ $resultsList.append($resultsItem);
+ }
+ $('#' + this.searchDiv)
+ .html(searchStringHtml)
+ .append($resultsSummary, $resultsList);
+ } else {
+ var noResults = $('').text( this.translate( 'noResultsFound', 'No results found.' ) );
+ $('#' + this.searchDiv)
+ .html(searchStringHtml)
+ .append(noResults);
}
}
- } else {
- milliSeconds = "000";
- }
- }
- dHours = Math.floor(seconds / 3600);
- dMinutes = Math.floor(seconds / 60) % 60;
- dSeconds = Math.floor(seconds % 60);
- if (dSeconds < 10) {
- dSeconds = "0" + dSeconds;
- }
- if (dHours > 0) {
- if (dMinutes < 10) {
- dMinutes = "0" + dMinutes;
- }
- if (showFullTime) {
- return dHours + ":" + dMinutes + ":" + dSeconds + "." + milliSeconds;
- } else {
- return dHours + ":" + dMinutes + ":" + dSeconds;
}
- } else {
- if (showFullTime) {
- if (dHours < 1) {
- dHours = "00";
- } else if (dHours < 10) {
- dHours = "0" + dHours;
+ };
+
+ AblePlayer.prototype.searchFor = function (searchString, ignoreCaps) {
+ // return chronological array of caption cues that match searchTerms
+ var captionLang, captions, results, caption, c, i, j;
+ results = [];
+ // split searchTerms into an array
+ var searchTerms = searchString.split(" ");
+ if (this.captions.length > 0) {
+ // Get caption track that matches this.searchLang
+ for (i = 0; i < this.captions.length; i++) {
+ if (this.captions[i].language === this.searchLang) {
+ captionLang = this.searchLang;
+ captions = this.captions[i].cues;
+ }
}
- if (dMinutes < 1) {
- dMinutes = "00";
- } else if (dMinutes < 10) {
- dMinutes = "0" + dMinutes;
+ if (captions.length > 0) {
+ c = 0;
+ for (i = 0; i < captions.length; i++) {
+ if (
+ $.inArray(captions[i].components.children[0]["type"], [
+ "string",
+ "i",
+ "b",
+ "u",
+ "v",
+ "c",
+ ]) !== -1
+ ) {
+ caption = this.flattenCueForCaption(captions[i]);
+ var captionNormalized = ignoreCaps
+ ? caption.toLowerCase()
+ : caption;
+ for (j = 0; j < searchTerms.length; j++) {
+ var searchTermNormalized = ignoreCaps
+ ? searchTerms[j].toLowerCase()
+ : searchTerms[j];
+ if (captionNormalized.indexOf(searchTermNormalized) !== -1) {
+ results[c] = [];
+ results[c]["start"] = captions[i].start;
+ results[c]["lang"] = captionLang;
+ results[c]["caption"] = this.highlightSearchTerm(
+ searchTerms,
+ caption
+ );
+ c++;
+ break;
+ }
+ }
+ }
+ }
}
- return dHours + ":" + dMinutes + ":" + dSeconds + "." + milliSeconds;
- } else {
- return dMinutes + ":" + dSeconds;
}
- }
- };
+ return results;
+ };
- AblePlayer.prototype.getSecondsFromColonTime = function (timeStr) {
- var timeParts, hours, minutes, seconds;
-
- timeParts = timeStr.split(":");
- if (timeParts.length === 3) {
- hours = parseInt(timeParts[0]);
- minutes = parseInt(timeParts[1]);
- seconds = parseFloat(timeParts[2]);
- return hours * 3600 + minutes * 60 + seconds;
- } else if (timeParts.length === 2) {
- minutes = parseInt(timeParts[0]);
- seconds = parseFloat(timeParts[1]);
- return minutes * 60 + seconds;
- } else if (timeParts.length === 1) {
- seconds = parseFloat(timeParts[0]);
- return seconds;
- }
- };
+ AblePlayer.prototype.highlightSearchTerm = function (
+ searchTerms,
+ resultString
+ ) {
+ // highlight ALL found searchTerms in the current resultString
+ // Need to step through the remaining terms to see if they're present as well
+ searchTerms.forEach(function (searchTerm) {
+ var reg = new RegExp(searchTerm, "gi");
+ resultString = resultString.replace(
+ reg,
+ '$& '
+ );
+ });
+ return resultString;
+ };
- AblePlayer.prototype.capitalizeFirstLetter = function (string) {
- return string.charAt(0).toUpperCase() + string.slice(1);
- };
+ /**
+ * Convert a number of seconds into readable time information.
+ *
+ * @param {int} totalSecondsFloat
+ *
+ * @returns {string[]} array 'value' HH:MM:SS and 'title' speakable time.
+ */
+ AblePlayer.prototype.secondsToTime = function (totalSecondsFloat) {
+ // return an array of totalSeconds converted into two formats
+ // time['value'] = HH:MM:SS with hours dropped if there are none
+ // time['title'] = a speakable rendering, so speech rec users can easily speak the link
+ var totalSeconds = Math.floor(totalSecondsFloat);
+
+ var h = parseInt(totalSeconds / 3600, 10) % 24;
+ var m = parseInt(totalSeconds / 60, 10) % 60;
+ var s = totalSeconds % 60;
+ var value = '';
+ var title = '';
+ if (h > 0) {
+ value += String(h).padStart(2, '0') + ':';
+ title += h > 0 ? h + ' ' + (h === 1 ? this.translate( 'hour', 'hour' ) : this.translate( 'hours', 'hours' ) ) : '';
+ }
- AblePlayer.prototype.roundDown = function (value, decimals) {
- return Number(Math.floor(value + "e" + decimals) + "e-" + decimals);
- };
+ value += String(m).padStart(2, '0') + ':';
+ title += m > 0 ? m + ' ' + (m === 1 ? this.translate( 'minute', 'minute' ) : this.translate( 'minutes', 'minutes' ) ) : '';
- AblePlayer.prototype.defer = function() {
- const self = this;
- const promise = new Promise((resolve, reject) => {
- self.resolve = resolve;
- self.reject = reject;
- self.promise = () => promise;
- });
- }
+ value += String(s).padStart(2, '0');
+ title += s > 0 ? s + ' ' + (s === 1 ? this.translate( 'second', 'second' ) : this.translate( 'seconds', 'seconds' ) ) : '';
- AblePlayer.prototype.getScript = function( source, callback ) {
- var script = document.createElement('script');
- var prior = document.getElementsByTagName('script')[0];
- script.async = 1;
+ var time = [];
+ time["value"] = value;
+ time["title"] = title;
- script.onload = script.onreadystatechange = function( _, isAbort ) {
- if ( isAbort || !script.readyState || /loaded|complete/.test(script.readyState) ) {
- script.onload = script.onreadystatechange = null;
- script = undefined;
+ return time;
+ };
+ }
- if ( !isAbort && callback ) {
- setTimeout(callback, 0);
- }
- }
- };
+ /* global YT */
+
+ function addSignFunctions(AblePlayer) {
+ AblePlayer.prototype.initSignLanguage = function() {
+ this.hasSignLanguage = false;
+ // Sign language is only currently supported in HTML5 player and YouTube.
+ var hasLocalSrc = ( this.$sources.first().attr('data-sign-src') !== undefined && this.$sources.first().attr('data-sign-src') !== "" );
+ // YouTube src can either be on a `source` element or on the `video` element.
+ var hasRemoteSrc = ( this.$media.data('youtube-sign-src') !== undefined && this.$media.data('youtube-sign-src') !== "" );
+ var hasRemoteSource = ( this.$sources.first().attr('data-youtube-sign-src') !== undefined && this.$sources.first().attr('data-youtube-sign-src') !== '' );
+ if ( ! this.isIOS() && ( hasLocalSrc || hasRemoteSrc || hasRemoteSource ) && ( this.player === 'html5' || this.player === 'youtube' ) ) {
+ // check to see if there's a sign language video accompanying this video
+ // check only the first source
+ // If sign language is provided, it must be provided for all sources
+ let ytSignSrc = this.youTubeSignId ?? purify.sanitize( this.$sources.first().attr('data-youtube-sign-src') );
+ let signSrc = purify.sanitize( this.$sources.first().attr('data-sign-src') );
+ let signVideo = purify.sanitize( this.$media.data('youtube-sign-src') );
+ this.signFile = (hasLocalSrc ) ? signSrc : false;
+ if ( hasRemoteSrc ) {
+ this.signYoutubeId = signVideo;
+ } else if ( hasRemoteSource ) {
+ this.signYoutubeId = ytSignSrc;
+ }
+ if ( this.signFile || this.signYoutubeId ) {
+ if (this.isIOS()) {
+ // iOS does not allow multiple videos to play simultaneously
+ // Therefore, sign language as rendered by Able Player unfortunately won't work
+ if (this.debug) ;
+ } else {
+ if (this.debug) ;
+ this.hasSignLanguage = true;
+ this.injectSignPlayerCode();
+ }
+ }
+ }
+ };
+
+ AblePlayer.prototype.injectSignPlayerCode = function() {
+
+ // create and inject surrounding HTML structure
+ var signVideoId, i, signSrc, srcType, $signSource;
+
+ signVideoId = this.mediaId + '-sign';
+
+ if ( this.signFile || this.signYoutubeId ) {
+ if ( null !== this.$signDivLocation ) {
+ this.$signDivLocation.addClass( 'able-sign-window able-fixed' );
+ this.$signWindow = this.$signDivLocation;
+ } else {
+ this.$signWindow = $('
',{
+ 'class' : 'able-sign-window',
+ 'role': 'dialog',
+ 'aria-label': this.translate( 'sign', 'Sign language' )
+ });
+ this.$signToolbar = $('
',{
+ 'class': 'able-window-toolbar able-' + this.toolbarIconColor + '-controls'
+ });
+ this.$signWindow.append(this.$signToolbar);
+ }
+
+ this.$ableWrapper.append(this.$signWindow);
+ }
+
+ if ( this.signFile ) {
+ this.$signVideo = $('
',{
+ 'id' : signVideoId,
+ 'tabindex' : '-1',
+ 'muted' : true,
+ });
+ this.signVideo = this.$signVideo[0];
+
+ if ( this.signFile ) {
+ $signSource = $('',{
+ 'src' : this.signFile,
+ 'type' : 'video/' + this.signFile.substr(-3)
+ });
+ this.$signVideo.append($signSource);
+ } else {
+ // for each original , add a to the sign
+ for (i=0; i < this.$sources.length; i++) {
+ signSrc = purify.sanitize( this.$sources[i].getAttribute('data-sign-src') );
+ srcType = this.$sources[i].getAttribute('type');
+ if (signSrc) {
+ $signSource = $('',{
+ 'src' : signSrc,
+ 'type' : srcType
+ });
+ this.$signVideo.append($signSource);
+ } else {
+ // source is missing a sign language version
+ // can't include sign language
+ this.hasSignLanguage = false;
+ return;
+ }
+ }
+ }
+ this.$signWindow.append( this.$signVideo );
+ } else if ( this.signYoutubeId ) {
+ this.signYoutube = this.initYouTubeSignPlayer();
+ }
+
+ // make it draggable
+ if ( null === this.$signDivLocation ) {
+ this.initDragDrop('sign');
+ }
+
+ if (this.prefSign === 1) {
+ // sign window is on. Go ahead and position it and show it
+ if ( null === this.$signDivLocation ) {
+ this.positionDraggableWindow('sign',this.getDefaultWidth('sign'));
+ }
+ } else {
+ this.$signWindow.hide();
+ }
+ };
+
+
+ AblePlayer.prototype.initYouTubeSignPlayer = function () {
+
+ var thisObj, deferred, promise;
+ thisObj = this;
+ deferred = new this.defer();
+ promise = deferred.promise();
+
+ this.youTubeSignPlayerReady = false;
+
+ if (AblePlayer.youTubeIframeAPIReady) {
+ // Script already loaded and ready.
+ thisObj.finalizeYoutubeSignInit().then(function() {
+ deferred.resolve();
+ });
+ } else {
+ // Has another player already started loading the script? If so, abort...
+ if ( ! AblePlayer.loadingYouTubeIframeAPI ) {
+ thisObj.getScript('https://www.youtube.com/iframe_api', function () {
+ });
+ }
+
+ // Otherwise, keeping waiting for script load event...
+ $('body').on('youTubeIframeAPIReady', function () {
+ thisObj.finalizeYoutubeSignInit().then(function() {
+ deferred.resolve();
+ });
+ });
+ }
+ return promise;
+ };
+
+ AblePlayer.prototype.finalizeYoutubeSignInit = function () {
+
+ // This is called once we're sure the Youtube iFrame API is loaded -- see above
+ var deferred, promise, thisObj, containerId, autoplay;
+
+ deferred = new this.defer();
+ promise = deferred.promise();
+ thisObj = this;
+ containerId = this.mediaId + '_youtube_sign';
+
+ this.$signWindow.append($('').attr('id', containerId));
+ autoplay = (this.okToPlay) ? 1 : 0;
+
+ // Documentation https://developers.google.com/youtube/player_parameters
+ this.youTubeSignPlayer = new YT.Player(containerId, {
+ videoId: this.getYouTubeId(this.signYoutubeId),
+ host: this.youTubeNoCookie ? 'https://www.youtube-nocookie.com' : 'https://www.youtube.com',
+ playerVars: {
+ autoplay: autoplay,
+ cc_lang_pref: this.captionLang, // set the caption language
+ cc_load_policy: 0,
+ controls: 0, // no controls, using our own
+ disableKb: 1, // disable keyboard shortcuts, using our own
+ enablejsapi: 1,
+ hl: this.lang, // set the UI language to match Able Player
+ iv_load_policy: 3, // do not show video annotations
+ origin: window.location.origin,
+ playsinline: this.playsInline,
+ rel: 0, // when video ends, show only related videos from same channel (1 shows any)
+ start: this.startTime
+ },
+ events: {
+ onReady: function (player) {
+ player.target.mute();
+ player.target.unloadModule( 'captions' );
+ thisObj.youTubeSignPlayerReady = true;
+
+ deferred.resolve();
+ },
+ onError: function (e) {
+ deferred.reject();
+ },
+ onStateChange: function (e) {
+ thisObj.getPlayerState().then(function() {
+ // no actions
+ });
+ },
+ onApiChange: function() {
+ // No actions
+ },
+ onPlaybackQualityChange: function () {
+ // no actions
+ },
+ }
+ });
+
+ return promise;
+ };
- script.src = source;
- prior.parentNode.insertBefore(script, prior);
}
- AblePlayer.prototype.hasAttr = function (object, attribute) {
+ function addTrackFunctions(AblePlayer) {
+ // Loads files referenced in track elements, and performs appropriate setup.
+ // For example, captions and text descriptions.
+ // This will be called whenever the player is recreated.
- var attr = object.attr(attribute);
+ AblePlayer.prototype.setupTracks = function () {
+ var thisObj, deferred, promise, loadingPromises, loadingPromise, i, tracks, track, kind;
- if (typeof attr !== typeof undefined && attr !== false) {
- return true;
- } else {
- return false;
- }
- };
+ thisObj = this;
-})(jQuery);
-
-(function ($) {
- AblePlayer.prototype.initDescription = function() {
-
-
-
-
- var deferred, promise, thisObj;
-
- deferred = new this.defer();
- promise = deferred.promise();
- thisObj = this;
-
- if (this.mediaType === 'audio') {
- deferred.resolve();
- }
-
- this.descFile = this.$sources.first().attr('data-desc-src');
- if (typeof this.descFile !== 'undefined') {
- this.hasOpenDesc = true;
- } else {
- this.hasOpenDesc = (this.youTubeDescId || this.vimeoDescId) ? true : false;
- }
-
- this.descMethod = null;
- if (this.hasOpenDesc && this.hasClosedDesc) {
- this.descMethod = (this.prefDescMethod) ? this.prefDescMethod : 'video';
- } else if (this.hasOpenDesc) {
- this.descMethod = 'video';
- } else if (this.hasClosedDesc) {
- this.descMethod = 'text';
- }
-
- this.descOn = false;
- if (this.descMethod) {
- if (this.prefDesc === 1) {
- this.descOn = true;
- } else if (this.prefDesc === 0) {
- this.descOn = false;
- } else {
- this.descOn = (this.defaultStateDescriptions === 1) ? true : false;
- }
- }
-
- if (typeof this.$descDiv === 'undefined' && this.hasClosedDesc ) {
- this.injectTextDescriptionArea();
- }
-
- if (this.descOn) {
- if (this.descMethod === 'video' && !this.usingDescribedVersion() ) {
- this.swapDescription();
- }
- if (this.hasClosedDesc) {
- if (this.prefDescVisible) {
- if (typeof this.$descDiv !== 'undefined') {
- this.$descDiv.show();
- this.$descDiv.removeClass('able-offscreen');
- }
- } else {
- if (typeof this.$descDiv !== 'undefined') {
- this.$descDiv.addClass('able-offscreen');
- }
- }
- }
- } else {
- if (this.descMethod === 'video') {
- if (this.usingDescribedVersion()) {
- this.swapDescription();
- }
- } else if (this.descMethod === 'text') {
- if (typeof this.$descDiv !== 'undefined') {
- this.$descDiv.hide();
- this.$descDiv.removeClass('able-offscreen');
- }
- }
- }
- deferred.resolve();
- return promise;
- };
-
- AblePlayer.prototype.usingDescribedVersion = function () {
-
-
- if (this.player === 'youtube') {
- return (this.activeYouTubeId === this.youTubeDescId);
- } else if (this.player === 'vimeo') {
- return (this.activeVimeoId === this.vimeoDescId);
- } else {
- return (this.$sources.first().attr('data-desc-src') === this.$sources.first().attr('src'));
- }
- };
-
- AblePlayer.prototype.initSpeech = function (context) {
- var thisObj = this;
-
- function attemptEnableSpeech() {
- var greeting = new SpeechSynthesisUtterance("\x20");
- greeting.onend = function () {
- thisObj.getBrowserVoices();
- if (
- (Array.isArray(thisObj.descVoices) && thisObj.descVoices.length) ||
- context !== "init"
- ) {
- thisObj.speechEnabled = true;
- }
- };
- thisObj.synth.speak(greeting);
- }
-
- function handleInitialClick() {
- attemptEnableSpeech();
- $(document).off("click", handleInitialClick);
- }
-
- if (this.speechEnabled === null) {
- if (window.speechSynthesis) {
- this.synth = window.speechSynthesis;
- this.synth.cancel();
-
- if (context === "init") {
- attemptEnableSpeech();
- $(document).on("click", handleInitialClick);
- } else {
- attemptEnableSpeech();
- }
- } else {
- this.speechEnabled = false;
- }
- }
- };
-
- AblePlayer.prototype.getBrowserVoices = function () {
-
-
- var voices, descLangs, voiceLang, preferredLang;
-
- preferredLang = (this.captionLang) ? this.captionLang.substring(0,2).toLowerCase() : this.lang.substring(0,2).toLowerCase();
-
- this.descVoices = [];
- voices = this.synth.getVoices();
- descLangs = this.getDescriptionLangs();
- if (voices.length > 0) {
- this.descVoices = [];
- for (var i=0; i
0) {
- if (prefDescVoice) {
- prefVoiceFound = false;
- for (var i=0; i 0) {
- this.swapTime = this.elapsed;
- } else {
- this.swapTime = 0;
- }
- if (this.duration > 0) {
- this.prevDuration = this.duration;
- }
-
- if (!this.okToPlay) {
- this.okToPlay = this.playing;
- }
-
- if (this.descOn) {
- this.showAlert( this.translate( 'alertDescribedVersion', 'Using the audio described version of this video' ) );
- } else {
- this.showAlert( this.translate( 'alertNonDescribedVersion', 'Using the non-described version of this video' ) );
- }
-
- if (this.player === 'html5') {
-
- this.swappingSrc = true;
- this.paused = true;
-
- if (this.usingDescribedVersion()) {
- for (i=0; i < this.$sources.length; i++) {
- origSrc = DOMPurify.sanitize( this.$sources[i].getAttribute('data-orig-src') );
- srcType = this.$sources[i].getAttribute('type');
- if (origSrc) {
- this.$sources[i].setAttribute('src',origSrc);
- }
- }
- } else {
- for (i=0; i < this.$sources.length; i++) {
- origSrc = DOMPurify.sanitize( this.$sources[i].getAttribute('src') );
- descSrc = DOMPurify.sanitize( this.$sources[i].getAttribute('data-desc-src') );
- srcType = this.$sources[i].getAttribute('type');
- if (descSrc) {
- this.$sources[i].setAttribute('src',descSrc);
- this.$sources[i].setAttribute('data-orig-src',origSrc);
- }
- }
- }
-
- if (this.recreatingPlayer) {
- return;
- }
- if (this.playerCreated) {
- this.deletePlayer('swap-desc-html');
- this.recreatePlayer().then(function() {
- if (!thisObj.loadingMedia) {
- thisObj.media.load();
- thisObj.loadingMedia = true;
- }
- });
- } else {
- }
- } else if (this.player === 'youtube') {
-
- this.activeYouTubeId = (this.usingDescribedVersion()) ? this.youTubeId : this.youTubeDescId;
-
- if (typeof this.youTubePlayer !== 'undefined') {
- thisObj.swappingSrc = true;
- if (thisObj.playing) {
- thisObj.youTubePlayer.loadVideoById(thisObj.activeYouTubeId,thisObj.swapTime);
- } else {
- thisObj.youTubePlayer.cueVideoById(thisObj.activeYouTubeId,thisObj.swapTime);
- }
- }
- if (this.playerCreated) {
- this.deletePlayer('swap-desc-youtube');
- }
- if (this.recreatingPlayer) {
- return;
- }
- this.recreatePlayer().then(function() {
- });
- } else if (this.player === 'vimeo') {
- if (this.usingDescribedVersion()) {
- this.activeVimeoId = this.vimeoId;
- this.showAlert( this.translate( 'alertNonDescribedVersion', 'Using the non-described version of this video' ) );
- } else {
- this.activeVimeoId = this.vimeoDescId;
- this.showAlert( this.translate( 'alertDescribedVersion', 'Using the audio described version of this video' ) );
- }
- if (this.playerCreated) {
- this.deletePlayer('swap-desc-vimeo');
- }
- if (this.recreatingPlayer) {
- return;
- }
- this.recreatePlayer().then(function() {
- thisObj.vimeoPlayer.loadVideo(thisObj.activeVimeoId).then(function() {
- if (thisObj.playing) {
- thisObj.vimeoPlayer.setCurrentTime(thisObj.swapTime);
- } else {
- thisObj.vimeoPlayer.pause();
- }
- });
- });
- }
- };
-
- AblePlayer.prototype.showDescription = function(now) {
- if (!this.playing || !this.hasClosedDesc || this.swappingSrc || !this.descOn || ( this.descMethod === 'video' && !this.prefDescVisible ) ) {
- return;
- }
-
- var thisObj, cues, d, thisDescription, descText;
- thisObj = this;
-
- var flattenComponentForDescription = function (component) {
- var result = [];
- if (component.type === 'string') {
- result.push(component.value);
- } else {
- for (var i = 0; i < component.children.length; i++) {
- result.push(flattenComponentForDescription(component.children[i]));
- }
- }
- return result.join('');
- };
- cues = [];
- if (this.selectedDescriptions) {
- cues = this.selectedDescriptions.cues;
- } else if (this.descriptions.length >= 1) {
- cues = this.descriptions[0].cues;
- }
- for (d = 0; d < cues.length; d++) {
- if ((cues[d].start <= now) && (cues[d].end > now)) {
- thisDescription = d;
- break;
- }
- }
- if (typeof thisDescription !== 'undefined') {
- if (this.currentDescription !== thisDescription) {
- this.$status.removeAttr('aria-live');
- descText = flattenComponentForDescription(cues[thisDescription].components);
- if (this.descReader === 'screenreader') {
- this.$descDiv.html(descText);
- } else if (this.speechEnabled) {
- if ( 'video' !== this.descMethod ) {
- this.announceDescriptionText('description',descText);
- }
- if (this.prefDescVisible) {
- this.$descDiv.html(descText).removeAttr('aria-live aria-atomic');
- }
- } else {
- this.$descDiv.html(descText);
- }
- if (this.prefDescPause && this.descMethod === 'text') {
- this.pauseMedia();
- this.pausedForDescription = true;
- }
- this.currentDescription = thisDescription;
- }
- } else {
- this.$descDiv.html('');
- this.currentDescription = -1;
- this.$status.attr('aria-live','polite');
- }
- };
-
- AblePlayer.prototype.syncSpeechToPlaybackRate = function(rate) {
-
- var speechRate;
-
- if (rate === 0.5) {
- speechRate = 0.7;
- } else if (rate === 0.75) {
- speechRate = 0.8;
- } else if (rate === 1.0) {
- speechRate = 1;
- } else if (rate === 1.25) {
- speechRate = 1.1;
- } else if (rate === 1.5) {
- speechRate = 1.2;
- } else if (rate === 1.75) {
- speechRate = 1.5;
- } else if (rate === 2.0) {
- speechRate = 2;
- } else if (rate === 2.25) {
- speechRate = 2.5;
- } else if (rate >= 2.5) {
- speechRate = 3;
- }
- this.prefDescRate = speechRate;
- };
-
- AblePlayer.prototype.announceDescriptionText = function(context, text) {
-
-
- var thisObj, voiceName, i, voice, pitch, rate, volume, utterance,
- timeElapsed, secondsElapsed;
-
- thisObj = this;
-
- var useFirstVoice = false;
-
- if (!this.speechEnabled) {
- this.initSpeech('desc');
- }
-
- if (context === 'sample') {
- voiceName = $('#' + this.mediaId + '_prefDescVoice').val();
- pitch = $('#' + this.mediaId + '_prefDescPitch').val();
- rate = $('#' + this.mediaId + '_prefDescRate').val();
- volume = $('#' + this.mediaId + '_prefDescVolume').val();
- } else {
- voiceName = this.prefDescVoice;
- pitch = this.prefDescPitch;
- rate = this.prefDescRate;
- volume = this.prefDescVolume;
- }
-
- if (this.descVoices) {
- if (this.descVoices.length > 0) {
- if (useFirstVoice) {
- voice = this.descVoices[0];
- } else if (voiceName) {
- for (i = 0; i < this.descVoices.length; i++) {
- if (this.descVoices[i].name == voiceName) {
- voice = this.descVoices[i];
- break;
- }
- }
- }
- if (typeof voice === 'undefined') {
- voice = this.descVoices[0];
- }
- }
- } else {
- voice = null;
- }
- utterance = new SpeechSynthesisUtterance();
- if (voice) {
- utterance.voice = voice;
- }
- utterance.voiceURI = 'native';
- utterance.volume = volume;
- utterance.rate = rate;
- utterance.pitch = pitch;
- utterance.text = text;
- utterance.lang = this.lang;
- utterance.onstart = function(e) {
- };
- utterance.onpause = function(e) {
- };
- utterance.onend = function(e) {
- this.speakingDescription = false;
- timeElapsed = e.elapsedTime;
- secondsElapsed = (timeElapsed > 100) ? (e.elapsedTime/1000).toFixed(2) : (e.elapsedTime).toFixed(2);
-
- if (this.debug) {
-
- }
- if (context === 'description') {
- if (thisObj.prefDescPause) {
- if (thisObj.pausedForDescription) {
- thisObj.playMedia();
- this.pausedForDescription = false;
- }
- }
- }
- };
- utterance.onerror = function(e) {
-
- };
- if (this.synth.paused) {
- this.synth.resume();
- }
- this.synth.speak(utterance);
- this.speakingDescription = true;
- };
-
-})(jQuery);
-
-(function ($) {
-
- AblePlayer.prototype.isIOS = function(version) {
-
-
- var userAgent, iOS;
-
- userAgent = navigator.userAgent.toLowerCase();
- iOS = /ipad|iphone|ipod/.exec(userAgent);
- if (iOS) {
- if (typeof version !== 'undefined') {
- if (userAgent.indexOf('os ' + version) !== -1) {
- return true;
- } else {
- return false;
- }
- } else {
- return true;
- }
- } else {
- return false;
- }
- };
-
- AblePlayer.prototype.browserSupportsVolume = function() {
-
-
- var audio, testVolume;
-
- if (this.isIOS()) {
- return false;
- }
-
- testVolume = 0.9;
- audio = new Audio();
- audio.volume = testVolume;
-
- return ( audio.volume === testVolume );
- };
-
- AblePlayer.prototype.nativeFullscreenSupported = function () {
-
- return document.fullscreenEnabled || document.webkitFullscreenEnabled;
- };
-
-})(jQuery);
-
-(function ($) {
-
- AblePlayer.prototype.seekTo = function (newTime) {
-
- var thisObj = this;
-
- this.seekFromTime = this.media.currentTime;
- this.seekToTime = newTime;
-
- this.seeking = true;
- this.liveUpdatePending = true;
-
- if (this.speakingDescription) {
- this.synth.cancel();
- }
-
- this.syncSignVideo( {'time' : this.startTime } );
-
- if (this.player === 'html5') {
- var seekable;
-
- this.startTime = newTime;
- seekable = this.media.seekable;
- if (seekable.length > 0 && this.startTime >= seekable.start(0) && this.startTime <= seekable.end(0)) {
- this.media.currentTime = this.startTime;
- this.seekStatus = 'complete';
- this.syncSignVideo( { 'time' : this.startTime } );
- }
- } else if (this.player === 'youtube') {
- this.youTubePlayer.seekTo(newTime,true);
- if (newTime > 0) {
- if (typeof this.$posterImg !== 'undefined') {
- this.$posterImg.hide();
- }
- }
- this.syncSignVideo( {'time' : newTime } );
- } else if (this.player === 'vimeo') {
- this.vimeoPlayer.setCurrentTime(newTime).then(function() {
- thisObj.elapsed = newTime;
- thisObj.refreshControls('timeline');
- })
- }
- this.refreshControls('timeline');
- };
-
- AblePlayer.prototype.getMediaTimes = function (duration, elapsed) {
-
-
-
- var deferred, promise, thisObj, mediaTimes;
- mediaTimes = {};
-
- deferred = new this.defer();
- promise = deferred.promise();
- thisObj = this;
- if (typeof duration !== 'undefined' && typeof elapsed !== 'undefined') {
- mediaTimes['duration'] = duration;
- mediaTimes['elapsed'] = elapsed;
- deferred.resolve(mediaTimes);
- } else {
- this.getDuration().then(function(duration) {
- mediaTimes['duration'] = thisObj.roundDown(duration,6);
- thisObj.getElapsed().then(function(elapsed) {
- mediaTimes['elapsed'] = thisObj.roundDown(elapsed,6);
- deferred.resolve(mediaTimes);
- });
- });
- }
- return promise;
- };
-
- AblePlayer.prototype.getDuration = function () {
-
- var deferred, promise, thisObj;
-
- deferred = new this.defer();
- promise = deferred.promise();
- thisObj = this;
-
- if (this.player === 'vimeo') {
- if (this.vimeoPlayer) {
- this.vimeoPlayer.getDuration().then(function(duration) {
- if (duration === undefined || isNaN(duration) || duration === -1) {
- deferred.resolve(0);
- } else {
- deferred.resolve(duration);
- }
- });
- } else {
- deferred.resolve(0);
- }
- } else {
- var duration;
- if (this.player === 'html5') {
- duration = this.media.duration;
- } else if (this.player === 'youtube') {
- if (this.youTubePlayerReady) {
- if (this.duration > 0) {
- duration = this.duration;
- } else {
- duration = this.youTubePlayer.getDuration();
- }
- } else {
- duration = 0;
- }
- }
- if (duration === undefined || isNaN(duration) || duration === -1) {
- deferred.resolve(0);
- } else {
- deferred.resolve(duration);
- }
- }
- return promise;
- };
-
- AblePlayer.prototype.getElapsed = function () {
-
-
- var deferred, promise, thisObj;
-
- deferred = new this.defer();
- promise = deferred.promise();
- thisObj = this;
-
- if (this.player === 'vimeo') {
- if (this.vimeoPlayer) {
- this.vimeoPlayer.getCurrentTime().then(function(elapsed) {
- if (elapsed === undefined || isNaN(elapsed) || elapsed === -1) {
- deferred.resolve(0);
- } else {
- deferred.resolve(elapsed);
- }
- });
- } else {
- deferred.resolve(0);
- }
- } else {
- var elapsed;
- if (this.player === 'html5') {
- elapsed = this.media.currentTime;
- } else if (this.player === 'youtube') {
- if (this.youTubePlayerReady) {
- elapsed = this.youTubePlayer.getCurrentTime();
- } else {
- elapsed = 0;
- }
- }
- if (elapsed === undefined || isNaN(elapsed) || elapsed === -1) {
- deferred.resolve(0);
- } else {
- deferred.resolve(elapsed);
- }
- }
- return promise;
- };
-
- AblePlayer.prototype.getPlayerState = function () {
-
-
- var deferred, promise, thisObj;
- deferred = new this.defer();
- promise = deferred.promise();
- thisObj = this;
-
- if (this.player === 'html5') {
- if (this.media.ended) {
- deferred.resolve('ended');
- } else if (this.media.paused) {
- deferred.resolve('paused');
- } else if (this.media.readyState !== 4) {
- deferred.resolve('buffering');
- } else {
- deferred.resolve('playing');
- }
- } else if (this.player === 'youtube' && this.youTubePlayerReady) {
- var state = this.youTubePlayer.getPlayerState();
- if (state === -1 || state === 5) {
- deferred.resolve('stopped');
- } else if (state === 0) {
- deferred.resolve('ended');
- } else if (state === 1) {
- deferred.resolve('playing');
- } else if (state === 2) {
- deferred.resolve('paused');
- } else if (state === 3) {
- deferred.resolve('buffering');
- }
- } else if (this.player === 'vimeo' && this.vimeoPlayer) {
- this.vimeoPlayer.getPaused().then(function(paused) {
- if (paused) {
- deferred.resolve('paused');
- } else {
- thisObj.vimeoPlayer.getEnded().then(function(ended) {
- if (ended) {
- deferred.resolve('ended');
- } else {
- deferred.resolve('playing');
- }
- });
- }
- });
- }
- return promise;
- };
-
- AblePlayer.prototype.isPlaybackRateSupported = function () {
-
- if (this.player === 'html5') {
- return (this.media.playbackRate) ? true : false;
- } else if (this.player === 'youtube') {
- if (this.youTubePlayerReady) {
- return (this.youTubePlayer.getAvailablePlaybackRates().length > 1) ? true : false;
- } else {
- return false;
- }
- } else if (this.player === 'vimeo') {
- return this.vimeoSupportsPlaybackRateChange;
- }
- };
-
- AblePlayer.prototype.setPlaybackRate = function (rate) {
-
- rate = Math.max(0.5, rate);
-
- if (this.hasClosedDesc && this.descMethod === 'text') {
- this.syncSpeechToPlaybackRate(rate);
- }
-
- this.syncSignVideo( {'rate' : rate } );
-
- if (this.player === 'html5') {
- this.media.playbackRate = rate;
- } else if (this.player === 'youtube') {
- this.youTubePlayer.setPlaybackRate(rate);
- } else if (this.player === 'vimeo') {
- this.vimeoPlayer.setPlaybackRate(rate);
- }
- this.syncSignVideo( { 'rate' : rate } );
- this.playbackRate = rate;
- this.$speed.text( this.translate( 'speed', 'Speed' ) + ': ' + rate.toFixed(2).toString() + 'x');
- };
-
- AblePlayer.prototype.getPlaybackRate = function () {
-
- if (this.player === 'html5') {
- return this.media.playbackRate;
- } else if (this.player === 'youtube' && (this.youTubePlayerReady)) {
- return this.youTubePlayer.getPlaybackRate();
- }
- };
-
- AblePlayer.prototype.isPaused = function () {
-
-
- if (this.player === 'vimeo') {
- return (this.playing) ? false : true;
- } else {
- this.getPlayerState().then(function(state) {
- return state === 'paused' || state === 'stopped' || state === 'ended';
- });
- }
- };
-
- AblePlayer.prototype.syncSignVideo = function(options) {
- if (this.hasSignLanguage && ( this.signVideo || this.signYoutube ) ) {
- if (options && typeof options.time !== 'undefined') {
- if ( this.signVideo ) {
- this.signVideo.currentTime = options.time;
- } else {
- this.youTubeSignPlayer.seekTo(options.time,true);
- }
- }
- if (options && typeof options.rate !== 'undefined') {
- if ( this.signVideo ) {
- this.signVideo.playbackRate = options.rate;
- } else {
- this.youTubeSignPlayer.setPlaybackRate(options.rate);
- }
- }
- if (options && typeof options.pause !== 'undefined') {
- if ( this.signVideo ) {
- this.signVideo.pause(true);
- } else {
- this.youTubeSignPlayer.pauseVideo();
- }
- }
- if (options && typeof options.play !== 'undefined') {
- if ( this.signVideo ) {
- this.signVideo.play(true);
- } else {
- this.youTubeSignPlayer.playVideo();
- }
- }
- if (options && typeof options.volume !== 'undefined') {
- if ( this.signVideo ) {
- this.signVideo.volume = 0;
- }
- }
- }
- };
-
- AblePlayer.prototype.pauseMedia = function () {
-
- this.syncSignVideo( { 'pause' : true } );
-
- if (this.player === 'html5') {
- this.media.pause(true);
- } else if (this.player === 'youtube') {
- this.youTubePlayer.pauseVideo();
- } else if (this.player === 'vimeo') {
- this.vimeoPlayer.pause();
- }
- };
-
- AblePlayer.prototype.playMedia = function () {
-
- this.syncSignVideo( { 'play' : true } );
-
- if (this.player === 'html5') {
- this.media.play(true);
- } else if (this.player === 'youtube') {
-
- this.youTubePlayer.playVideo();
- if (typeof this.$posterImg !== 'undefined') {
- this.$posterImg.hide();
- }
- this.stoppingYouTube = false;
- } else if (this.player === 'vimeo') {
- this.vimeoPlayer.play();
- }
- this.startedPlaying = true;
- if (this.hideControls) {
- this.hidingControls = true;
- this.invokeHideControlsTimeout();
- }
- };
-
- AblePlayer.prototype.fadeControls = function(direction) {
-
-
-
- var thisObj = this;
-
- if (direction == 'out') {
- this.$playerDiv.addClass( 'fade-out' ).removeClass( 'fade-in' );
- } else if (direction == 'in') {
- this.$playerDiv.addClass( 'fade-in' ).removeClass( 'fade-out' );
- }
- };
-
- AblePlayer.prototype.invokeHideControlsTimeout = function () {
-
- var thisObj = this;
- this.hideControlsTimeout = window.setTimeout(function() {
- if (typeof thisObj.playing !== 'undefined' && thisObj.playing === true && thisObj.hideControls) {
- thisObj.fadeControls('out');
- thisObj.controlsHidden = true;
- }
- },5000);
- this.hideControlsTimeoutStatus = 'active';
- };
-
- AblePlayer.prototype.refreshControls = function(context = 'init', duration, elapsed) {
-
-
- context = 'init';
-
-
- var thisObj, duration, textByState, timestamp, captionsCount, newTop, statusBarWidthBreakpoint;
-
- thisObj = this;
- if ( this.swappingSrc && this.playing ) {
- return;
- }
-
- if ( context === 'timeline' || context === 'init' ) {
- var lastChapterIndex, displayElapsed, updateLive, widthUsed,
- leftControls, rightControls, seekbarWidth, buffered;
- if (typeof this.duration === 'undefined') {
- return;
- }
- if (this.useChapterTimes) {
- this.chapterDuration = this.getChapterDuration();
- this.chapterElapsed = this.getChapterElapsed();
- }
-
- if ( !this.useFixedSeekInterval && !this.seekIntervalCalculated && this.duration > 0) {
- this.setSeekInterval();
- }
-
- if (this.seekBar) {
- if (this.useChapterTimes) {
- lastChapterIndex = this.selectedChapters.cues.length-1;
- if (this.selectedChapters.cues[lastChapterIndex] == this.currentChapter) {
- if (this.currentChapter.end !== this.duration) {
- this.seekBar.setDuration(this.duration - this.currentChapter.start);
- } else {
- this.seekBar.setDuration(this.chapterDuration);
- }
- } else {
- this.seekBar.setDuration(this.chapterDuration);
- }
- } else if ( !(this.duration === undefined || isNaN(this.duration) || this.duration === -1) ) {
- this.seekBar.setDuration(this.duration);
- }
- if (!(this.seekBar.tracking)) {
- updateLive = this.liveUpdatePending || this.seekBar.seekHead.is($(document.activeElement));
- this.liveUpdatePending = false;
- if (this.useChapterTimes) {
- this.seekBar.setPosition(this.chapterElapsed, updateLive);
- } else {
- this.seekBar.setPosition(this.elapsed, updateLive);
- }
- }
-
- if (this.seekBar.tracking) {
- displayElapsed = this.seekBar.lastTrackPosition;
- } else {
- displayElapsed = ( this.useChapterTimes ) ? this.chapterElapsed : this.elapsed;
- }
- }
- if (typeof this.$durationContainer !== 'undefined') {
- if (this.useChapterTimes) {
- this.$durationContainer.text(' / ' + this.formatSecondsAsColonTime(this.chapterDuration));
- } else {
- this.$durationContainer.text(' / ' + this.formatSecondsAsColonTime(this.duration));
- }
- }
- if (typeof this.$elapsedTimeContainer !== 'undefined') {
- this.$elapsedTimeContainer.text(this.formatSecondsAsColonTime(displayElapsed));
- }
-
- if (this.skin === 'legacy') {
- if (this.seekBar) {
- let controlWrapper = this.seekBar.wrapperDiv.parent().parent();
- leftControls = this.seekBar.wrapperDiv.parent().prev('div.able-left-controls');
- rightControls = leftControls.next('div.able-right-controls');
- widthUsed = leftControls.outerWidth(true);
- rightControls.children().each(function () {
- if ($(this).attr('role')=='button') {
- widthUsed += $(this).outerWidth(true) + 5;
- }
- });
- if (this.fullscreen) {
- seekbarWidth = $(window).width() - widthUsed;
- } else {
- seekbarWidth = controlWrapper.width() - widthUsed - 10;
- }
- if (Math.abs(seekbarWidth - this.seekBar.getWidth()) > 5) {
- this.seekBar.setWidth(seekbarWidth);
- }
- }
- }
-
- if (this.player === 'html5' && this.media.buffered.length > 0) {
- buffered = this.media.buffered.end(0);
- if (this.useChapterTimes) {
- if (buffered > this.chapterDuration) {
- buffered = this.chapterDuration;
- }
- if (this.seekBar) {
- this.seekBar.setBuffered(buffered / this.chapterDuration);
- }
- } else if ( this.seekBar && !isNaN(buffered) ) {
- this.seekBar.setBuffered(buffered / duration);
- }
- } else if (this.player === 'youtube' && this.seekBar && this.youTubePlayerReady ) {
- this.seekBar.setBuffered(this.youTubePlayer.getVideoLoadedFraction());
- } else if (this.player === 'vimeo') {
- }
- }
-
- if (context === 'descriptions' || context == 'init') {
- if (this.$descButton) {
- this.toggleButtonState(
- this.$descButton,
- this.descOn,
- this.translate( 'turnOffDescriptions', 'Turn off descriptions' ),
- this.translate( 'turnOnDescriptions', 'Turn on descriptions' ),
- );
- }
- }
-
- if (context === 'captions' || context == 'init') {
-
- if (this.$ccButton) {
-
- captionsCount = this.captions.length;
- if (captionsCount > 1) {
- this.$ccButton.attr({
- 'aria-haspopup': 'true',
- 'aria-controls': this.mediaId + '-captions-menu'
- });
- }
- var ariaLabelOn = ( captionsCount > 1 ) ? this.translate( 'captions', 'Captions' ) : this.translate( 'showCaptions', 'Show captions' );
- var ariaLabelOff = ( captionsCount > 1 ) ? this.translate( 'captions', 'Captions' ) : this.translate( 'hideCaptions', 'Hide captions' );
- var ariaPressed = ( captionsCount > 1 ) ? true : false;
-
- this.toggleButtonState(
- this.$ccButton,
- this.captionsOn,
- ariaLabelOff,
- ariaLabelOn,
- ariaPressed
- );
- }
- }
-
- if (context === 'fullscreen' || context == 'init'){
- if (this.$fullscreenButton) {
- if (!this.fullscreen) {
- this.$fullscreenButton.attr( 'aria-label', this.translate( 'enterFullScreen', 'Enter full screen' ) );
- this.getIcon( this.$fullscreenButton, 'fullscreen-expand' );
- } else {
- this.$fullscreenButton.attr('aria-label', this.translate( 'exitFullScreen', 'Exit full screen' ) );
- this.getIcon( this.$fullscreenButton, 'fullscreen-collapse' );
- }
- }
- }
- if (context === 'playpause' || context == 'init'){
- if (typeof this.$bigPlayButton !== 'undefined' && typeof this.seekBar !== 'undefined') {
- if (this.paused && !this.seekBar.tracking) {
- if (!this.hideBigPlayButton) {
- this.$bigPlayButton.show();
- this.$bigPlayButton.attr('aria-hidden', 'false');
- }
- } else {
- this.$bigPlayButton.hide();
- this.$bigPlayButton.attr('aria-hidden', 'true');
- }
- }
- }
-
- if (context === 'transcript' || context == 'init'){
-
- if (this.transcriptType) {
- if (this.prefAutoScrollTranscript === 1) {
- this.autoScrollTranscript = true;
- this.$autoScrollTranscriptCheckbox.prop('checked',true);
- } else {
- this.autoScrollTranscript = false;
- this.$autoScrollTranscriptCheckbox.prop('checked',false);
- }
-
- if (this.autoScrollTranscript && this.currentHighlight) {
- newTop = Math.floor(this.$transcriptDiv.scrollTop() +
- $(this.currentHighlight).position().top -
- (this.$transcriptDiv.height() / 2) +
- ($(this.currentHighlight).height() / 2));
- if (newTop !== Math.floor(this.$transcriptDiv.scrollTop())) {
- this.scrollingTranscript = true;
- if (this.movingHighlight) {
- this.$transcriptDiv.scrollTop(newTop);
- this.movingHighlight = false;
- }
- }
- }
- }
- }
-
- if (context === 'init') {
-
- if (this.$chaptersButton) {
- this.$chaptersButton.attr({
- 'aria-label': this.translate( 'chapters', 'Chapters' ),
- 'aria-haspopup': 'true',
- 'aria-controls': this.mediaId + '-chapters-menu'
- });
- }
- }
-
- if (context === 'timeline' || context === 'playpause' || context === 'init') {
-
- textByState = {
- 'stopped': this.translate( 'statusStopped', 'Stopped' ),
- 'paused': this.translate( 'statusPaused', 'Paused' ),
- 'playing': this.translate( 'statusPlaying', 'Playing' ),
- 'buffering': this.translate( 'statusBuffering', 'Buffering' ),
- 'ended': this.translate( 'statusEnd', 'End of track' )
- };
-
- if (this.stoppingYouTube) {
- if (this.$status.text() !== this.translate( 'statusStopped', 'Stopped' ) ) {
- this.$status.text( this.translate( 'statusStopped', 'Stopped' ) );
- }
- this.getIcon( this.$playpauseButton, 'play' );
- } else if (typeof this.$status !== 'undefined' && typeof this.seekBar !== 'undefined') {
- this.getPlayerState().then(function(currentState) {
- if (thisObj.$status.text() !== textByState[currentState] && !thisObj.seekBar.tracking) {
- if (thisObj.swappingSrc) {
- if (!thisObj.debouncingStatus) {
- thisObj.statusMessageThreshold = 2000;
- }
- } else if (!thisObj.debouncingStatus) {
- thisObj.statusMessageThreshold = 250;
- }
- timestamp = (new Date()).getTime();
- if (!thisObj.statusDebounceStart) {
- thisObj.statusDebounceStart = timestamp;
- thisObj.debouncingStatus = true;
- thisObj.statusTimeout = setTimeout(function () {
- thisObj.debouncingStatus = false;
- thisObj.refreshControls(context);
- }, thisObj.statusMessageThreshold);
- } else if ((timestamp - thisObj.statusDebounceStart) > thisObj.statusMessageThreshold) {
- thisObj.$status.text(textByState[currentState]);
- thisObj.statusDebounceStart = null;
- clearTimeout(thisObj.statusTimeout);
- thisObj.statusTimeout = null;
- }
- } else {
- thisObj.statusDebounceStart = null;
- thisObj.debouncingStatus = false;
- clearTimeout(thisObj.statusTimeout);
- thisObj.statusTimeout = null;
- }
- if (!thisObj.seekBar.tracking && !thisObj.stoppingYouTube) {
- if (currentState === 'paused' || currentState === 'stopped' || currentState === 'ended') {
- thisObj.$playpauseButton.attr('aria-label',thisObj.tt.play);
- thisObj.getIcon( thisObj.$playpauseButton, 'play' );
- } else {
- thisObj.$playpauseButton.attr('aria-label',thisObj.tt.pause);
- thisObj.getIcon( thisObj.$playpauseButton, 'pause' );
- }
- }
- });
- }
- }
-
- if (!this.fullscreen) {
- statusBarWidthBreakpoint = 300;
- if (this.$statusBarDiv.width() < statusBarWidthBreakpoint) {
- this.$statusBarDiv.find('span.able-speed').hide();
- this.hidingSpeed = true;
- } else {
- if (this.hidingSpeed) {
- this.$statusBarDiv.find('span.able-speed').show();
- this.hidingSpeed = false;
- }
- }
- }
-
- };
-
- AblePlayer.prototype.handlePlay = function(e) {
- if (this.paused) {
- this.okToPlay = true;
- this.playMedia();
- if (this.synth.paused) {
- this.synth.resume();
- }
- } else {
- this.okToPlay = false;
- this.pauseMedia();
- if (this.speakingDescription) {
- this.synth.pause();
- }
- }
- if (this.speechEnabled === null) {
- this.initSpeech('play');
- }
- };
-
- AblePlayer.prototype.handleRestart = function() {
-
- if (this.speakingDescription) {
- this.synth.cancel();
- }
- this.seekTo(0);
- };
-
- AblePlayer.prototype.handlePrevTrack = function() {
-
- this.playlistIndex = (this.playlistIndex === 0) ? this.$playlist.length - 1 : this.playlistIndex--;
- this.cueingPlaylistItem = true;
- this.cuePlaylistItem(this.playlistIndex);
- };
-
- AblePlayer.prototype.handleNextTrack = function() {
-
- this.playlistIndex = (this.playlistIndex === this.$playlist.length - 1) ? 0 : this.playlistIndex++;
- this.cueingPlaylistItem = true;
- this.cuePlaylistItem(this.playlistIndex);
- };
-
- AblePlayer.prototype.handleRewind = function() {
-
- var targetTime;
-
- targetTime = this.elapsed - this.seekInterval;
- if (this.useChapterTimes && (targetTime < this.currentChapter.start)) {
- targetTime = this.currentChapter.start;
- } else if (targetTime < 0) {
- targetTime = 0;
- }
- this.seekTo(targetTime);
- };
-
- AblePlayer.prototype.handleFastForward = function() {
-
- var targetTime, lastChapterIndex;
-
- lastChapterIndex = this.chapters.length-1;
- targetTime = this.elapsed + this.seekInterval;
- if (this.useChapterTimes) {
- if (this.chapters[lastChapterIndex] == this.currentChapter) {
- if (targetTime > this.duration || targetTime > this.currentChapter.end) {
- targetTime = Math.min(this.duration, this.currentChapter.end);
- } else if (this.duration % targetTime < this.seekInterval) {
- targetTime = Math.min(this.duration, this.currentChapter.end);
- }
- } else {
- if (targetTime > this.currentChapter.end) {
- targetTime = this.currentChapter.end;
- }
- }
- } else {
- if (targetTime > this.duration) {
- targetTime = this.duration;
- }
- }
- this.seekTo(targetTime);
- };
-
- AblePlayer.prototype.handleRateIncrease = function() {
- this.changeRate(1);
- };
-
- AblePlayer.prototype.handleRateDecrease = function() {
- this.changeRate(-1);
- };
-
- AblePlayer.prototype.changeRate = function (dir) {
-
- var rates, currentRate, index, newRate, vimeoMin, vimeoMax;
-
- if (this.player === 'html5') {
- this.setPlaybackRate(this.getPlaybackRate() + (0.25 * dir));
- } else if (this.player === 'youtube') {
- if (this.youTubePlayerReady) {
- rates = this.youTubePlayer.getAvailablePlaybackRates();
- currentRate = this.getPlaybackRate();
- index = rates.indexOf(currentRate);
- if (index === -1) {
-
- } else {
- index += dir;
- if (index < rates.length && index >= 0) {
- this.setPlaybackRate(rates[index]);
- }
- }
- }
- } else if (this.player === 'vimeo') {
- vimeoMin = 0.5;
- vimeoMax = 2;
- if (dir === 1) {
- newRate = (this.vimeoPlaybackRate + 0.5 <= vimeoMax) ? this.vimeoPlaybackRate + 0.5 : vimeoMax;
- } else if (dir === -1) {
- newRate = (this.vimeoPlaybackRate - 0.5 >= vimeoMin) ? this.vimeoPlaybackRate - 0.5 : vimeoMin;
- }
- this.setPlaybackRate(newRate);
- }
- };
-
- AblePlayer.prototype.handleCaptionToggle = function() {
-
- var thisObj = this;
- var captions, ariaPressed;
- if (this.hidingPopup) {
- this.hidingPopup = false;
- return false;
- }
-
- captions = (this.captions.length) ? this.captions : [];
- if (captions.length === 1) {
- if (this.captionsOn === true) {
- this.captionsOn = false;
- this.prefCaptions = 0;
- ariaPressed = false;
- this.updatePreferences('prefCaptions');
- if (this.usingYouTubeCaptions) {
- this.youTubePlayer.unloadModule('captions');
- } else if (this.usingVimeoCaptions) {
- this.vimeoPlayer.disableTextTrack();
- } else {
- this.$captionsWrapper.hide();
- }
- } else {
- this.captionsOn = true;
- this.prefCaptions = 1;
- ariaPressed = true;
- this.updatePreferences('prefCaptions');
- if (this.usingYouTubeCaptions) {
- this.youTubePlayer.loadModule('captions');
- } else if (this.usingVimeoCaptions) {
- this.vimeoPlayer.enableTextTrack(this.captionLang).then(function(track) {
- }).catch(function(error) {
- switch (error.name) {
- case 'InvalidTrackLanguageError':
-
- break;
- case 'InvalidTrackError':
-
- break;
- default:
-
- break;
- }
- });
- } else {
- this.$captionsWrapper.show();
- }
- for (var i=0; i= 0) {
- this.selectedDescriptions = this.descriptions[0];
- }
- }
- } else {
- if (this.captionsPopup && this.captionsPopup.is(':visible')) {
- this.captionsPopup.hide();
- this.hidingPopup = false;
- this.$ccButton.attr('aria-expanded', 'false')
- this.waitThenFocus(this.$ccButton);
- } else {
- this.closePopups();
- if (this.captionsPopup) {
- this.captionsPopup.show();
- this.$ccButton.attr('aria-expanded','true');
-
- setTimeout(function() {
- thisObj.captionsPopup.css('top', thisObj.$ccButton.position().top - thisObj.captionsPopup.outerHeight());
- thisObj.captionsPopup.css('left', thisObj.$ccButton.position().left)
- thisObj.captionsPopup.find('li').removeClass('able-focus');
- thisObj.captionsPopup.find('li').first().trigger('focus').addClass('able-focus');
- }, 50);
- }
- }
- }
- var ariaLabelOn = ( captions.length > 1 ) ? this.translate( 'captions', 'Captions' ) : this.translate( 'showCaptions', 'Show captions' );
- var ariaLabelOff = ( captions.length > 1 ) ? this.translate( 'captions', 'Captions' ) : this.translate( 'hideCaptions', 'Hide captions' );
-
- this.toggleButtonState(
- this.$ccButton,
- this.captionsOn,
- ariaLabelOff,
- ariaLabelOn,
- ariaPressed
- );
- };
-
- AblePlayer.prototype.waitThenFocus = function($el, timeout) {
-
- var _timeout = (timeout === undefined || timeout === null) ? 50 : timeout;
-
- setTimeout(function() {
- $el.trigger('focus');
- }, _timeout);
- }
-
- AblePlayer.prototype.handleChapters = function () {
- if (this.hidingPopup) {
- this.hidingPopup = false;
- return false;
- }
- if (this.chaptersPopup.is(':visible')) {
- this.chaptersPopup.hide();
- this.hidingPopup = false;
- this.$chaptersButton.attr('aria-expanded','false').trigger('focus');
- } else {
- this.closePopups();
- this.chaptersPopup.show();
- this.$chaptersButton.attr('aria-expanded','true');
- this.chaptersPopup.css('top', this.$chaptersButton.position().top - this.chaptersPopup.outerHeight());
- this.chaptersPopup.css('left', this.$chaptersButton.position().left)
-
- this.chaptersPopup.find('li').removeClass('able-focus');
- if (this.chaptersPopup.find('li[aria-checked="true"]').length) {
- this.chaptersPopup.find('li[aria-checked="true"]').trigger('focus').addClass('able-focus');
- } else {
- this.chaptersPopup.find('li').first().addClass('able-focus').attr('aria-checked','true').trigger('focus');
- }
- }
- };
-
- AblePlayer.prototype.handleDescriptionToggle = function() {
-
- this.descOn = !this.descOn;
- this.prefDesc = + this.descOn;
- this.updatePreferences('prefDesc');
- if (typeof this.$descDiv !== 'undefined') {
- if (!this.$descDiv.is(':hidden')) {
- this.$descDiv.hide();
- }
- }
- this.initDescription();
- this.refreshControls('descriptions');
- };
-
- AblePlayer.prototype.handlePrefsClick = function(pref) {
-
-
-
- var thisObj, prefsButtonPosition, prefsMenuRight, prefsMenuLeft;
-
- thisObj = this;
-
- if (this.speechEnabled === null) {
- this.initSpeech('prefs');
- }
- if (this.hidingPopup) {
- this.hidingPopup = false;
- return false;
- }
- if (this.prefsPopup.is(':visible')) {
- this.prefsPopup.hide();
- this.$prefsButton.attr('aria-expanded','false');
- this.prefsPopup.find('li').removeClass('able-focus').attr('tabindex','-1');
- if (!this.showingPrefsDialog) {
- this.$prefsButton.trigger('focus');
- }
- setTimeout(function() {
- thisObj.hidingPopup = false;
- },100);
- } else {
- this.closePopups();
- this.prefsPopup.show();
- this.$prefsButton.attr('aria-expanded','true');
- this.$prefsButton.trigger('focus');
- setTimeout(function() {
- prefsButtonPosition = thisObj.$prefsButton.position();
- prefsMenuRight = thisObj.$ableDiv.width() - 5;
- prefsMenuLeft = prefsMenuRight - thisObj.prefsPopup.width();
- thisObj.prefsPopup.css('top', prefsButtonPosition.top - thisObj.prefsPopup.outerHeight());
- thisObj.prefsPopup.css('left', prefsMenuLeft);
- thisObj.prefsPopup.find('li').removeClass('able-focus').attr('tabindex','0');
- thisObj.prefsPopup.find('li').first().trigger('focus').addClass('able-focus');
- }, 50);
- }
- };
-
- AblePlayer.prototype.handleTranscriptToggle = function () {
- var thisObj = this;
- var visible = this.$transcriptDiv.is(':visible');
- if ( visible ) {
- this.$transcriptArea.hide();
- this.toggleButtonState( this.$transcriptButton, ! visible, this.translate( 'hideTranscript', 'Hide transcript' ), this.translate( 'showTranscript', 'Show transcript' ) );
- this.prefTranscript = 0;
- if ( this.transcriptType === 'popup' ) {
- this.$transcriptButton.trigger('focus').addClass('able-focus');
- setTimeout(function() {
- thisObj.closingTranscript = false;
- }, 100);
- }
- } else {
- if ( this.transcriptType === 'popup' ) {
- this.positionDraggableWindow('transcript');
- this.$transcriptArea.show();
- this.$transcriptPopup.hide();
- this.toggleButtonState( this.$transcriptButton, ! visible, this.translate( 'hideTranscript', 'Hide transcript' ), this.translate( 'showTranscript', 'Show transcript' ) );
- this.prefTranscript = 1;
- this.focusNotClick = true;
- this.$transcriptArea.find('button').first().trigger('focus');
- setTimeout(function() {
- thisObj.focusNotClick = false;
- }, 100);
- } else {
- this.toggleButtonState( this.$transcriptButton, ! visible, this.translate( 'hideTranscript', 'Hide transcript' ), this.translate( 'showTranscript', 'Show transcript' ) );
- this.$transcriptArea.show();
- }
- }
- this.updatePreferences('prefTranscript');
- };
-
- AblePlayer.prototype.handleSignToggle = function () {
-
- var thisObj = this;
- var visible = this.$signWindow.is(':visible');
- if ( visible ) {
- this.$signWindow.hide();
- this.toggleButtonState( this.$signButton, ! visible, this.translate( 'hideSign', 'Hide sign language' ), this.translate( 'showSign', 'Show sign language' ) );
- this.prefSign = 0;
- this.$signButton.trigger('focus').addClass('able-focus');
- setTimeout(function() {
- thisObj.closingSign = false;
- }, 100);
- } else {
- this.positionDraggableWindow('sign');
- this.$signWindow.show();
- this.$signPopup.hide();
- this.toggleButtonState( this.$signButton, ! visible, this.translate( 'hideSign', 'Hide sign language' ), this.translate( 'showSign', 'Show sign language' ) );
- this.prefSign = 1;
- this.focusNotClick = true;
- this.$signWindow.find('button').first().trigger('focus');
- setTimeout(function() {
- thisObj.focusNotClick = false;
- }, 100);
- }
- this.updatePreferences('prefSign');
- };
-
- AblePlayer.prototype.setFullscreen = function (fullscreen) {
-
- if (this.fullscreen == fullscreen) {
- return;
- }
- var thisObj = this;
- var $el = this.$ableWrapper;
- var el = $el[0];
-
- if (this.nativeFullscreenSupported()) {
- if (fullscreen) {
- var scroll = {
- x: window.pageXOffset || 0,
- y: window.pageYOffset || 0
- }
- if (this.prefTranscript === 1) {
- this.rePositionDraggableWindow("transcript");
- }
- if (this.prefSign === 1) {
- this.rePositionDraggableWindow("sign");
- }
- this.scrollPosition = scroll;
- if (el.requestFullscreen) {
- el.requestFullscreen();
- } else if (el.webkitRequestFullscreen) {
- el.webkitRequestFullscreen();
- }
- this.fullscreen = true;
- } else {
- this.restoringAfterFullscreen = true;
- if (document.exitFullscreen) {
- document.exitFullscreen();
- } else if (document.webkitExitFullscreen) {
- document.webkitExitFullscreen();
- } else if (document.webkitCancelFullscreen) {
- document.webkitCancelFullscreen();
- }
- if (this.prefTranscript === 1) {
- this.positionDraggableWindow("transcript");
- }
- if (this.prefSign === 1) {
- this.positionDraggableWindow("sign");
- }
- this.fullscreen = false;
- }
- } else {
- }
- $(document).on('fullscreenchange webkitfullscreenchange', function(e) {
- if (!thisObj.fullscreen) {
- thisObj.restoringAfterFullscreen = true;
- } else if (!thisObj.clickedFullscreenButton) {
- thisObj.fullscreen = false;
- thisObj.restoringAfterFullscreen = true;
- }
- thisObj.resizePlayer();
- thisObj.refreshControls('fullscreen');
- if ( thisObj.scrollPosition ) {
- scroll = thisObj.scrollPosition;
- window.scrollTo( scroll.x, scroll.y );
- }
- setTimeout(function() {
- thisObj.clickedFullscreenButton = false;
- thisObj.restoringAfterFullscreen = false;
- },100);
- });
- };
-
- AblePlayer.prototype.handleFullscreenToggle = function () {
-
- var stillPaused = this.paused;
- this.setFullscreen(!this.fullscreen);
- if (stillPaused) {
- this.pauseMedia();
- } else if (!stillPaused) {
- this.playMedia();
- }
- if (this.fullscreen) {
- this.hideControls = true;
- if (this.playing) {
- this.fadeControls('out');
- this.controlsHidden = true;
- }
- } else {
- this.hideControls = this.hideControlsOriginal;
- if (!this.hideControls) {
- if (this.controlsHidden) {
- this.fadeControls('in');
- this.controlsHidden = false;
- }
- if (this.hideControlsTimeoutStatus === 'active') {
- window.clearTimeout(this.hideControlsTimeout);
- this.hideControlsTimeoutStatus = 'clear';
- }
- }
- }
- };
-
- AblePlayer.prototype.handleTranscriptLockToggle = function (val) {
-
- this.autoScrollTranscript = val;
- this.prefAutoScrollTranscript = +val;
- this.updatePreferences('prefAutoScrollTranscript');
- this.refreshControls('transcript');
- };
-
- AblePlayer.prototype.getIcon = function( $button, id, forceImg = false ) {
- var iconType = this.iconType;
- var iconData = this.getIconData( id );
- iconType = ( null === iconData[3] ) ? 'svg' : iconType;
- iconType = ( forceImg === true ) ? 'img' : iconType;
-
- var existingIcon = $button.find( iconType + '#ableplayer-' + id );
- if ( existingIcon.length > 0 ) {
- return;
- }
- $button.find('svg, img, span').remove();
-
- if (iconType === 'font') {
- var $buttonIcon = $('', {
- 'class': iconData[2],
- });
- $button.append( $buttonIcon );
- } else if (iconType === 'svg') {
- function getNode(n, v) {
- n = document.createElementNS("http://www.w3.org/2000/svg", n);
- for (var p in v) {
- n.setAttributeNS(null, p.replace(/[A-Z]/g, function(m) {
- return "-" + m.toLowerCase();
- }), v[p]);
- }
- return n;
- }
- var icon = document.createElementNS( 'http://www.w3.org/2000/svg', 'svg' );
- icon.setAttribute( 'focusable', 'false' );
- icon.setAttribute( 'aria-hidden', 'true');
- icon.setAttribute( 'viewBox', iconData[0] );
- icon.setAttribute( 'id', 'ableplayer-' + id );
- let path = getNode( 'path', { d: iconData[1] } );
- icon.appendChild( path );
-
- $button.append( icon );
- $button.html($button.html());
- } else {
- var $buttonImg = $(' ',{
- 'src': iconData[3],
- 'alt': '',
- 'role': 'presentation'
- });
- $button.append($buttonImg);
- $button.find('img').attr('src',iconData[3]);
- }
- };
-
- AblePlayer.prototype.setText = function( $button, text ) {
- $button.attr( 'aria-label', text );
- };
-
- AblePlayer.prototype.toggleButtonState = function($button, isOn, onLabel, offLabel, ariaPressed = false, ariaExpanded = false) {
- let buttonOff = ( $button.hasClass( 'buttonOff' ) ) ? true : false;
- if ( buttonOff && ! isOn || ! buttonOff && isOn ) {
- return;
- }
- if (! isOn) {
- $button.addClass('buttonOff').attr('aria-label', offLabel);
- if ( ariaPressed ) {
- $button.attr('aria-pressed', 'false');
- }
- if ( ariaExpanded ) {
- $button.attr( 'aria-expanded', 'false' );
- }
- } else {
- $button.removeClass('buttonOff').attr('aria-label', onLabel);
- if ( ariaPressed ) {
- $button.attr('aria-pressed', 'true');
- }
- if ( ariaExpanded ) {
- $button.attr( 'aria-expanded', 'true' );
- }
- }
- };
-
- AblePlayer.prototype.showTooltip = function($tooltip) {
-
- $tooltip.show();
- };
-
- AblePlayer.prototype.showAlert = function( msg, location = 'main' ) {
-
- var thisObj, $alertBox, $parentWindow;
-
- thisObj = this;
- $alertBox = thisObj.$alertBox;
- $parentWindow = thisObj.$ableDiv;
- if (location === 'transcript') {
- $parentWindow = thisObj.$transcriptArea;
- } else if (location === 'sign') {
- $parentWindow = thisObj.$signWindow;
- } else if (location === 'screenreader') {
- $alertBox = thisObj.$srAlertBox;
- }
- $alertBox.find('span').text(msg);
- $alertBox.appendTo($parentWindow)
- $alertBox.css( {'display': 'flex'} );
-
- if (location !== 'screenreader') {
- setTimeout( function () {
- $alertBox.hide();
- }, 30000 );
- }
- };
-
- AblePlayer.prototype.showedAlert = function (which) {
-
- if (which === 'transcript') {
- return this.showedTranscriptAlert ?? false;
- } else if (which === 'sign') {
- return this.showedSignAlert ?? false;
- }
- return false;
- }
-
- AblePlayer.prototype.resizePlayer = function (width, height) {
-
- var captionSize, newWidth, newHeight, $iframe;
-
- if (this.mediaType === 'audio') {
- return;
- }
- if (typeof width !== 'undefined' && typeof height !== 'undefined') {
- this.aspectRatio = height / width;
- if (this.playerWidth) {
- newWidth = this.playerWidth;
- if (this.playerHeight) {
- newHeight = this.playerHeight;
- } else {
- newHeight = Math.round(newWidth * this.aspectRatio);
- this.playerHeight = newHeight;
- }
- } else {
- newWidth = (this.player === 'html5') ? $(window).width() : this.$ableWrapper.width();
- newHeight = Math.round(newWidth * this.aspectRatio);
- }
- } else if (this.fullscreen) {
- this.$ableWrapper.addClass('fullscreen');
- newWidth = $(window).width();
- newHeight = $(window).height() - this.$playerDiv.outerHeight() - 5;
- this.positionCaptions('overlay');
- } else {
- this.$ableWrapper.removeClass('fullscreen');
- if (this.player === 'html5') {
- newWidth = (this.playerWidth) ? this.playerWidth : $(window).width();
- } else {
- newWidth = this.$ableWrapper.width();
- }
- newHeight = Math.round(newWidth * this.aspectRatio);
- this.positionCaptions(this.prefCaptionsPosition);
- }
- if (this.debug) {
-
- }
- if (this.player === 'youtube' || this.player === 'vimeo') {
- $iframe = this.$ableWrapper.find('iframe');
- if (this.player === 'youtube' && this.youTubePlayer) {
- this.youTubePlayer.setSize(newWidth,newHeight);
- } else {
- $iframe.attr({
- 'width': newWidth,
- 'height': newHeight
- });
- }
- if (this.playerWidth && this.playerHeight) {
- if (this.fullscreen) {
- $iframe.css({
- 'max-width': '',
- 'max-height': ''
- });
- } else {
- $iframe.css({
- 'max-width': this.playerWidth + 'px',
- 'max-height': this.playerHeight + 'px'
- });
- }
- }
- } else if (this.player === 'html5') {
- if (this.fullscreen) {
- this.$media.attr({
- 'width': newWidth,
- 'height': newHeight
- });
- this.$ableWrapper.css({
- 'width': newWidth,
- 'height': newHeight
- });
- } else {
- this.$media.removeAttr('width height');
- this.$ableWrapper.removeAttr( 'style' );
- }
- }
- if (typeof this.$captionsDiv !== 'undefined') {
-
- var isSmallScreen = false;
- var windowWidth = window.screen.width;
- if ( windowWidth < 1200 ) {
- isSmallScreen = true;
- }
- captionSize = parseInt(this.prefCaptionsSize,10);
- if (this.fullscreen && ! isSmallScreen ) {
- captionSize = (captionSize / 100) + 'vw';
- } else if ( this.fullscreen && isSmallScreen ) {
- captionSize = '1.2rem';
- } else {
- captionSize = captionSize + '%';
- }
- this.$captionsDiv.css({
- 'font-size': captionSize
- });
- }
- this.refreshControls();
- };
-
- AblePlayer.prototype.retrieveOffscreenWindow = function( which, width, height ) {
-
-
- var window, windowPos, windowTop, windowLeft, windowRight, windowWidth, windowBottom, windowHeight;
-
- if (which == 'transcript') {
- window = this.$transcriptArea;
- } else if (which == 'sign') {
- window = this.$signWindow;
- }
- windowWidth = window.width();
- windowHeight = window.height();
- windowPos = window.position();
- windowTop = windowPos.top;
- windowLeft = windowPos.left;
- windowRight = windowLeft + windowWidth;
- windowBottom = windowTop + windowHeight;
-
- if (windowTop < 0) {
- windowTop = 10;
- window.css('top',windowTop);
- }
- if (windowLeft < 0) {
- windowLeft = 10;
- window.css('left',windowLeft);
- }
- if (windowRight > width) {
- windowLeft = (width - 20) - windowWidth;
- window.css('left',windowLeft);
- }
- if (windowBottom > height) {
- windowTop = (height - 10) - windowHeight;
- window.css('top',windowTop);
- }
- };
-
- AblePlayer.prototype.updateZIndex = function(which) {
-
- var defHighZ, defLowZ, transcriptZ, signZ, newHighZ, newLowZ;
-
- defHighZ = 8000;
- defLowZ = 7000;
-
-
- if (typeof this.$transcriptArea === 'undefined' || typeof this.$signWindow === 'undefined' ) {
- if (typeof this.$transcriptArea !== 'undefined') {
- transcriptZ = parseInt(this.$transcriptArea.css('z-index'));
- if (transcriptZ > defLowZ) {
- this.$transcriptArea.css('z-index',defLowZ);
- }
- } else if (typeof this.$signWindow !== 'undefined') {
- signZ = parseInt(this.$signWindow.css('z-index'));
- if (signZ > defHighZ) {
- this.$signWindow.css('z-index',defHighZ);
- }
- }
- return false;
- }
-
-
- transcriptZ = parseInt(this.$transcriptArea.css('z-index'));
- signZ = parseInt(this.$signWindow.css('z-index'));
-
- if (transcriptZ === signZ) {
- newHighZ = defHighZ;
- newLowZ = defLowZ;
- } else if (transcriptZ > signZ) {
- if (which === 'transcript') {
- return false;
- } else {
- newHighZ = transcriptZ;
- newLowZ = signZ;
- }
- } else {
- if (which === 'sign') {
- return false;
- } else {
- newHighZ = signZ;
- newLowZ = transcriptZ;
- }
- }
- if (which === 'transcript') {
- this.$transcriptArea.css('z-index',newHighZ);
- this.$signWindow.css('z-index',newLowZ);
- } else if (which === 'sign') {
- this.$signWindow.css('z-index',newHighZ);
- this.$transcriptArea.css('z-index',newLowZ);
- }
- };
-
- AblePlayer.prototype.syncTrackLanguages = function (source, language) {
-
-
- var i, captions, descriptions, chapters, meta;
-
- for (i = 0; i < this.captions.length; i++) {
- if (this.captions[i].language === language) {
- captions = this.captions[i];
- }
- }
- for (i = 0; i < this.chapters.length; i++) {
- if (this.chapters[i].language === language) {
- chapters = this.chapters[i];
- }
- }
- for (i = 0; i < this.descriptions.length; i++) {
- if (this.descriptions[i].language === language) {
- descriptions = this.descriptions[i];
- }
- }
- for (i = 0; i < this.meta.length; i++) {
- if (this.meta[i].language === language) {
- meta = this.meta[i];
- }
- }
- this.transcriptLang = language;
- if (source === 'init' || source === 'captions') {
- this.captionLang = language;
- this.selectedCaptions = captions;
- this.selectedChapters = chapters;
- this.selectedDescriptions = descriptions;
- this.selectedMeta = meta;
- this.transcriptCaptions = captions;
- this.transcriptChapters = chapters;
- this.transcriptDescriptions = descriptions;
- this.updateChaptersList();
- } else if (source === 'transcript') {
- this.transcriptCaptions = captions;
- this.transcriptChapters = chapters;
- this.transcriptDescriptions = descriptions;
- }
- if (this.selectedDescriptions) {
- this.setDescriptionVoice();
- if (this.$sampleDescDiv) {
- if (this.sampleText) {
- for (i = 0; i < this.sampleText.length; i++) {
- if (this.sampleText[i].lang === this.selectedDescriptions.language) {
- this.currentSampleText = this.sampleText[i]['text'];
- this.$sampleDescDiv.html(this.currentSampleText);
- }
- }
- }
- }
- }
- this.updateTranscript();
- };
-
-})(jQuery);
-
-(function ($) {
- AblePlayer.prototype.updateCaption = function (time) {
- if (
- !this.usingYouTubeCaptions &&
- !this.usingVimeoCaptions &&
- typeof this.$captionsWrapper !== "undefined"
- ) {
- if (this.captionsOn) {
- this.$captionsWrapper.show();
- if (typeof time !== "undefined") {
- this.showCaptions(time);
- }
- } else if (this.$captionsWrapper) {
- this.$captionsWrapper.hide();
- this.prefCaptions = 0;
+ deferred = new this.defer();
+ promise = deferred.promise();
+
+ loadingPromises = [];
+
+ if ($("#able-vts").length) {
+ // Page includes a container for a VTS instance
+ this.vtsTracks = [];
+ this.hasVts = true;
+ } else {
+ this.hasVts = false;
}
- }
- };
- AblePlayer.prototype.updateCaptionsMenu = function (lang) {
- this.captionsPopup.find("li").attr("aria-checked", "false");
- if (typeof lang === "undefined") {
- this.captionsPopup.find("li").last().attr("aria-checked", "true");
- } else {
- this.captionsPopup
- .find("li[lang=" + lang + "]")
- .attr("aria-checked", "true");
- }
- };
+ // Source array for populating the above arrays
+ // varies, depending on whether there are dedicated description tracks
+ if (this.hasDescTracks && this.descOn) {
+ tracks = this.altTracks;
+ } else {
+ tracks = this.tracks;
+ }
+ for (i = 0; i < tracks.length; i++) {
+ track = tracks[i];
+ kind = ( track.kind ) ? track.kind : 'subtitles';
+
+ if (!track.src) {
+ if (thisObj.usingYouTubeCaptions || thisObj.usingVimeoCaptions) {
+ // skip all the hullabaloo and go straight to setupCaptions
+ thisObj.setupCaptions(track);
+ }
+ continue;
+ }
+ var trackSrc = track.src;
+ loadingPromise = this.loadTextObject(trackSrc);
+ loadingPromises.push(
+ loadingPromise.catch(function (src) {
+ console.warn("Failed to load captions track from " + src);
+ })
+ );
+ loadingPromise.then(
+ (function (track, kind) {
+ trackSrc = track.src;
+ var trackLang = track.language;
+ var trackLabel = track.label;
+ var trackDesc = track.desc;
+
+ return function (data) {
+ var cues = thisObj.parseWebVTT(data).cues;
+ if (thisObj.hasVts) {
+ thisObj.setupVtsTracks(
+ kind,
+ trackLang,
+ trackDesc,
+ trackLabel,
+ trackSrc,
+ data.text
+ );
+ }
+ if (kind === 'captions' || kind === 'subtitles') {
+ thisObj.setupCaptions(track, cues);
+ } else if (kind === 'descriptions') {
+ thisObj.setupDescriptions(track, cues);
+ } else if (kind === 'chapters') {
+ thisObj.setupChapters(track, cues);
+ } else if (kind === 'metadata') {
+ thisObj.setupMetadata(cues);
+ }
+ };
+ })(track, kind)
+ );
+ }
+ if (thisObj.usingYouTubeCaptions || thisObj.usingVimeoCaptions) {
+ deferred.resolve();
+ } else {
+ $.when.apply($, loadingPromises).then(function () {
+ deferred.resolve();
+ });
+ }
+ return promise;
+ };
- AblePlayer.prototype.getCaptionClickFunction = function (track) {
+ AblePlayer.prototype.getTracks = function () {
+ // define an array tracks with the following structure:
+ // kind - string, e.g. "captions", "descriptions"
+ // src - string, URL of WebVTT source file
+ // language - string, lang code
+ // label - string to display, e.g., in CC menu
+ // def - Boolean, true if this is the default track
+ // cues - array with startTime, endTime, and payload
+ // desc - Boolean, true if track includes a data-desc attribute
+
+ var thisObj, deferred, promise, trackLang, trackLabel, isDefault, forDesc,
+ hasDefault, hasTrackInDefLang, trackFound, i;
+
+ thisObj = this;
+ hasDefault = false;
+
+ deferred = new this.defer();
+ promise = deferred.promise();
+
+ this.$tracks = this.$media.find('track');
+ this.tracks = []; // only includes tracks that do NOT have data-desc
+ this.altTracks = []; // only includes tracks that DO have data-desc
+
+ // Arrays for each kind, to be populated later
+ this.captions = [];
+ this.descriptions = [];
+ this.chapters = [];
+ this.meta = [];
+
+ this.hasCaptionsTrack = false; // will change to true if one or more tracks has kind="captions"
+ this.hasDescTracks = false; // will change to true if one or more tracks has data-desc
+
+ if (this.$tracks.length) {
+ this.usingYouTubeCaptions = false;
+ // create object from HTML5 tracks
+ this.$tracks.each(function (index, element) {
+ if ($(this).attr('kind') === 'captions') {
+ thisObj.hasCaptionsTrack = true;
+ } else if ($(this).attr('kind') === 'descriptions') {
+ thisObj.hasClosedDesc = true;
+ }
- var thisObj = this;
- return function () {
- thisObj.selectedCaptions = track;
- thisObj.captionLang = track.language;
- thisObj.currentCaption = -1;
- if (thisObj.usingYouTubeCaptions) {
- if (thisObj.captionsOn) {
- if (
- thisObj.youTubePlayer.getOptions("captions") &&
- thisObj.startedPlaying
- ) {
- thisObj.youTubePlayer.setOption("captions", "track", {
- languageCode: thisObj.captionLang,
- });
+ // srcLang should always be included with , but HTML5 spec doesn't require it
+ // if not provided, assume track is the same language as the default player language
+ if ($(this).attr('srclang')) {
+ trackLang = $(this).attr('srclang');
} else {
- thisObj.captionLangPending = thisObj.captionLang;
+ trackLang = thisObj.lang;
}
- } else {
- if (thisObj.youTubePlayer.getOptions("captions")) {
- thisObj.youTubePlayer.setOption("captions", "track", {
- languageCode: thisObj.captionLang,
- });
+ if ($(this).attr('label')) {
+ trackLabel = $(this).attr('label');
} else {
- thisObj.youTubePlayer.loadModule("captions");
- thisObj.captionLangPending = thisObj.captionLang;
+ trackLabel = thisObj.getLanguageName(trackLang);
}
- }
- } else if (thisObj.usingVimeoCaptions) {
- thisObj.vimeoPlayer
- .enableTextTrack(thisObj.captionLang)
- .then(function (track) {
- })
- .catch(function (error) {
- switch (error.name) {
- case "InvalidTrackLanguageError":
- break;
- case "InvalidTrackError":
+ if (typeof $(this).attr('default') !== 'undefined' && !hasDefault) {
+ isDefault = true;
+ hasDefault = true;
+ } else if (trackLang === thisObj.lang) {
+ // this track is in the default lang of the player
+ // if there is no other default track specified
+ // this will be the default
+ hasTrackInDefLang = true;
+ isDefault = false; // for now; this could change if there's no default attribute
+ } else {
+ isDefault = false;
+ }
+ if (isDefault) {
+ // this.captionLang will also be the default language for non-caption tracks
+ thisObj.captionLang = trackLang;
+ }
- break;
- default:
+ if ($(this).data("desc") !== undefined) {
+ forDesc = true;
+ thisObj.hasDescTracks = true;
+ } else {
+ forDesc = false;
+ }
+ if (forDesc) {
+ thisObj.altTracks.push({
+ kind: $(this).attr('kind'),
+ src: $(this).attr('src'),
+ language: trackLang,
+ label: trackLabel,
+ def: isDefault,
+ desc: forDesc,
+ });
+ } else {
+ thisObj.tracks.push({
+ kind: $(this).attr('kind'),
+ src: $(this).attr('src'),
+ language: trackLang,
+ label: trackLabel,
+ def: isDefault,
+ desc: forDesc,
+ });
+ }
- break;
+ if (index == thisObj.$tracks.length - 1) {
+ // This is the last track.
+ if (!hasDefault) {
+ if (hasTrackInDefLang) {
+ thisObj.captionLang = thisObj.lang;
+ trackFound = false;
+ i = 0;
+ while (i < thisObj.tracks.length && !trackFound) {
+ if (thisObj.tracks[i]['language'] === thisObj.lang) {
+ thisObj.tracks[i]['def'] = true;
+ trackFound = true;
+ }
+ i++;
+ }
+ } else {
+ // use the first track
+ thisObj.tracks[0]['def'] = true;
+ thisObj.captionLang = thisObj.tracks[0]['language'];
+ }
+ }
+ // Remove 'default' attribute from all elements
+ // This data has already been saved to this.tracks
+ // and some browsers will display the default captions,
+ // despite all standard efforts to suppress them
+ thisObj.$media.find("track").removeAttr("default");
+ }
+ });
+ }
+ if (!this.$tracks.length || !this.hasCaptionsTrack) {
+ // this media has no track elements
+ // if this is a youtube or vimeo player, check there for captions/subtitles
+ if (this.player === 'youtube') {
+ this.getYouTubeCaptionTracks().then(function () {
+ if (thisObj.hasCaptions) {
+ thisObj.usingYouTubeCaptions = true;
+ if (thisObj.$captionsWrapper) {
+ thisObj.$captionsWrapper.remove();
+ }
}
+ deferred.resolve();
});
- } else {
- thisObj.syncTrackLanguages("captions", thisObj.captionLang);
- if (!thisObj.swappingSrc) {
- thisObj.updateCaption(thisObj.elapsed);
- thisObj.showDescription(thisObj.elapsed);
+ } else if (this.player === 'vimeo') {
+ this.getVimeoCaptionTracks().then(function () {
+ if (thisObj.hasCaptions) {
+ thisObj.usingVimeoCaptions = true;
+ if (thisObj.$captionsWrapper) {
+ thisObj.$captionsWrapper.remove();
+ }
+ }
+ deferred.resolve();
+ });
+ } else {
+ // this is neither YouTube nor Vimeo
+ // there just ain't no tracks (captions or otherwise)
+ this.hasCaptions = false;
+ if (thisObj.$captionsWrapper) {
+ thisObj.$captionsWrapper.remove();
+ }
+ deferred.resolve();
}
+ } else {
+ // there is at least one track with kind="captions"
+ deferred.resolve();
}
- thisObj.captionsOn = true;
- thisObj.hidingPopup = true;
- thisObj.captionsPopup.hide();
- thisObj.$ccButton.attr("aria-expanded", "false");
- if (thisObj.mediaType === "audio") {
- thisObj.$captionsContainer.removeClass("captions-off");
- }
- setTimeout(function () {
- thisObj.hidingPopup = false;
- }, 100);
- thisObj.updateCaptionsMenu(thisObj.captionLang);
- thisObj.waitThenFocus(thisObj.$ccButton);
-
- thisObj.prefCaptions = 1;
- thisObj.updatePreferences("prefCaptions");
- thisObj.refreshControls("captions");
+ return promise;
};
- };
- AblePlayer.prototype.getCaptionOffFunction = function () {
- var thisObj = this;
- return function () {
- if (thisObj.player == "youtube") {
- thisObj.youTubePlayer.unloadModule("captions");
- } else if (thisObj.usingVimeoCaptions) {
- thisObj.vimeoPlayer.disableTextTrack();
- }
- thisObj.captionsOn = false;
- thisObj.currentCaption = -1;
-
- if (thisObj.mediaType === "audio") {
- thisObj.$captionsContainer.addClass("captions-off");
- }
-
- thisObj.hidingPopup = true;
- thisObj.captionsPopup.hide();
- thisObj.$ccButton.attr("aria-expanded", "false");
- setTimeout(function () {
- thisObj.hidingPopup = false;
- }, 100);
- thisObj.updateCaptionsMenu();
- thisObj.waitThenFocus(thisObj.$ccButton);
-
- thisObj.prefCaptions = 0;
- thisObj.updatePreferences("prefCaptions");
- if (!this.swappingSrc) {
- thisObj.refreshControls("captions");
- thisObj.updateCaption();
- }
- };
- };
+ AblePlayer.prototype.setupCaptions = function (track, cues) {
+ // Setup player for display of captions (one track at a time)
+ var inserted, i, capLabel;
- AblePlayer.prototype.showCaptions = function (now) {
- var c, thisCaption, captionText;
- var cues;
- if (this.selectedCaptions.cues.length) {
- cues = this.selectedCaptions.cues;
- } else if (this.captions.length >= 1) {
- cues = this.captions[0].cues;
- } else {
- cues = [];
- }
- for (c = 0; c < cues.length; c++) {
- if (cues[c].start <= now && cues[c].end > now) {
- thisCaption = c;
- break;
+ // Insert track into captions array
+ // in its proper alphabetical sequence by label
+ if (typeof cues === "undefined") {
+ cues = null;
}
- }
- if (typeof thisCaption !== "undefined") {
- if (this.currentCaption !== thisCaption) {
- captionText = this.flattenCueForCaption(cues[thisCaption]).replace( /\n/g, " " );
-
- this.$captionsDiv.html(captionText);
- this.currentCaption = thisCaption;
- if (captionText.length === 0) {
- this.$captionsDiv.css("display", "none");
+
+ if (this.usingYouTubeCaptions || this.usingVimeoCaptions) ; else {
+ if (this.captions.length === 0) {
+ // this is the first
+ this.captions.push({
+ language: track.language,
+ label: track.label,
+ def: track.def,
+ cues: cues,
+ });
} else {
- this.$captionsDiv.css("display", "inline-block");
+ // there are already captions in the array
+ inserted = false;
+ for (i = 0; i < this.captions.length; i++) {
+ capLabel = track.label;
+ if (capLabel.toLowerCase() < this.captions[i].label.toLowerCase()) {
+ // insert before track i
+ this.captions.splice(i, 0, {
+ language: track.language,
+ label: track.label,
+ def: track.def,
+ cues: cues,
+ });
+ inserted = true;
+ break;
+ }
+ }
+ if (!inserted) {
+ // just add track to the end
+ this.captions.push({
+ language: track.language,
+ label: track.label,
+ def: track.def,
+ cues: cues,
+ });
+ }
}
}
- } else {
- this.$captionsDiv.html("").css("display", "none");
- this.currentCaption = -1;
- }
- };
- AblePlayer.prototype.flattenCueForCaption = function (cue) {
+ // there are captions available
+ this.hasCaptions = true;
+ this.currentCaption = -1;
+ if (this.prefCaptions === 1) {
+ this.captionsOn = true;
+ } else if (this.prefCaptions === 0) {
+ this.captionsOn = false;
+ } else {
+ // user has no prefs. Use default state.
+ if (this.defaultStateCaptions === 1) {
+ this.captionsOn = true;
+ } else {
+ this.captionsOn = false;
+ }
+ }
+ if (this.mediaType === 'audio' && this.captionsOn) {
+ this.$captionsContainer.removeClass('captions-off');
+ }
+ if (
+ !this.$captionsWrapper ||
+ (this.$captionsWrapper &&
+ !$.contains(this.$ableDiv[0], this.$captionsWrapper[0]))
+ ) {
+ // captionsWrapper either doesn't exist, or exists in an orphaned state
+ // Either way, it needs to be rebuilt...
+ this.$captionsDiv = $('', {
+ class: "able-captions",
+ });
+ this.$captionsWrapper = $('
', {
+ class: 'able-captions-wrapper',
+ 'aria-hidden': 'true',
+ }).hide();
+ if (this.prefCaptionsPosition === 'below') {
+ this.$captionsWrapper.addClass('able-captions-below');
+ } else {
+ this.$captionsWrapper.addClass('able-captions-overlay');
+ }
+ this.$captionsWrapper.append(this.$captionsDiv);
+ this.$captionsContainer.append(this.$captionsWrapper);
+ }
+ };
+ AblePlayer.prototype.setupDescriptions = function (track, cues) {
+ // called via setupTracks() only if there is track with kind="descriptions"
+ // prepares for delivery of text description , in case it's needed
+ // whether and how it's delivered is controlled within description.js > initDescription()
+ this.hasClosedDesc = true;
+ this.currentDescription = -1;
+ this.descriptions.push({
+ cues: cues,
+ language: track.language,
+ });
+ };
+ AblePlayer.prototype.setupChapters = function (track, cues) {
+ // NOTE: WebVTT supports nested timestamps (to form an outline)
+ // This is not currently supported.
- var result = [];
+ this.hasChapters = true;
+ this.chapters.push({
+ cues: cues,
+ language: track.language,
+ });
+ };
- var flattenComponent = function (component) {
- var result = [],
- ii;
- if (component.type === "string") {
- result.push(component.value);
- } else if (component.type === "v") {
- result.push("(" + component.value + ")");
- for (ii = 0; ii < component.children.length; ii++) {
- result.push(flattenComponent(component.children[ii]));
- }
- } else if (component.type === "i") {
- result.push("
");
- for (ii = 0; ii < component.children.length; ii++) {
- result.push(flattenComponent(component.children[ii]));
- }
- result.push(" ");
- } else if (component.type === "b") {
- result.push("
");
- for (ii = 0; ii < component.children.length; ii++) {
- result.push(flattenComponent(component.children[ii]));
- }
- result.push(" ");
- } else {
- for (ii = 0; ii < component.children.length; ii++) {
- result.push(flattenComponent(component.children[ii]));
+ AblePlayer.prototype.setupMetadata = function (cues) {
+ if (this.metaType === 'text') {
+ // Metadata is only supported if data-meta-div is provided
+ // The player does not display metadata internally
+ if (this.metaDiv) {
+ if ($('#' + this.metaDiv)) {
+ // container exists
+ this.$metaDiv = $('#' + this.metaDiv);
+ this.hasMeta = true;
+ this.meta = cues;
+ }
}
+ } else if (this.metaType === 'selector') {
+ this.hasMeta = true;
+ this.visibleSelectors = [];
+ this.meta = cues;
}
- return result.join("");
};
- if (typeof cue.components !== "undefined") {
- for (var ii = 0; ii < cue.components.children.length; ii++) {
- result.push(flattenComponent(cue.components.children[ii]));
- }
- }
- return result.join("");
- };
+ AblePlayer.prototype.loadTextObject = function (src) {
+ var deferred, promise, thisObj, $tempDiv;
- AblePlayer.prototype.getCaptionsOptions = function (pref) {
- var options = [];
-
- switch (pref) {
- case "prefCaptionsFont":
- options[0] = ["serif", this.translate( 'serif', 'serif' )];
- options[1] = ["sans-serif", this.translate( 'sans', 'sans-serif' )];
- options[2] = ["cursive", this.translate( 'cursive', 'cursive' )];
- options[3] = ["fantasy", this.translate( 'fantasy', 'fantasy' )];
- options[4] = ["monospace", this.translate( 'monospace', 'monospace' )];
- break;
-
- case "prefCaptionsColor":
- case "prefCaptionsBGColor":
- options[0] = ["white", this.translate( 'white', 'white' )];
- options[1] = ["yellow", this.translate( 'yellow', 'yellow' )];
- options[2] = ["green", this.translate( 'green', 'green' )];
- options[3] = ["cyan", this.translate( 'cyan', 'cyan' )];
- options[4] = ["blue", this.translate( 'blue', 'blue' )];
- options[5] = ["magenta", this.translate( 'magenta', 'magenta' )];
- options[6] = ["red", this.translate( 'red', 'red' )];
- options[7] = ["black", this.translate( 'black', 'black' )];
- break;
-
- case "prefCaptionsSize":
- options[0] = "75%";
- options[1] = "100%";
- options[2] = "125%";
- options[3] = "150%";
- options[4] = "200%";
- break;
-
- case "prefCaptionsOpacity":
- options[0] = "0%";
- options[1] = "25%";
- options[2] = "50%";
- options[3] = "75%";
- options[4] = "100%";
- break;
-
- case "prefCaptionsStyle":
- options[0] = this.translate( 'captionsStylePopOn', 'Pop-on' );
- options[1] = this.translate( 'captionsStyleRollUp', 'Roll-up' );
- break;
-
- case "prefCaptionsPosition":
- options[0] = "overlay";
- options[1] = "below";
- break;
- }
- return options;
- };
+ deferred = new this.defer();
+ promise = deferred.promise();
+ thisObj = this;
- AblePlayer.prototype.translatePrefs = function (pref, value, outputFormat) {
- if (outputFormat == "youtube") {
- if (pref === "size") {
- switch (value) {
- case "75%":
- return -1;
- case "100%":
- return 0;
- case "125%":
- return 1;
- case "150%":
- return 2;
- case "200%":
- return 3;
- }
- }
- }
- return false;
- };
+ // create a temp div for holding data
+ $tempDiv = $('
', {
+ style: 'display:none',
+ });
- AblePlayer.prototype.stylizeCaptions = function ($element, pref) {
- var property, newValue, opacity;
-
- if (typeof $element !== "undefined") {
- if (pref == "prefCaptionsPosition") {
- this.positionCaptions();
- } else if (typeof pref !== "undefined") {
- if (pref === "prefCaptionsFont") {
- property = "font-family";
- } else if (pref === "prefCaptionsSize") {
- property = "font-size";
- } else if (pref === "prefCaptionsColor") {
- property = "color";
- } else if (pref === "prefCaptionsBGColor") {
- property = "background-color";
- } else if (pref === "prefCaptionsOpacity") {
- property = "opacity";
- }
- if (pref === "prefCaptionsOpacity") {
- newValue =
- parseFloat($("#" + this.mediaId + "_" + pref).val()) / 100.0;
- } else {
- newValue = $("#" + this.mediaId + "_" + pref).val();
- }
- $element.css(property, newValue);
+ // Fetch the content manually so it can be sanitized
+ fetch(src)
+ .then( response => {
+
+ return response.text();
+ })
+ .then( vtt => {
+ // Split the input on double line breaks to handle each cue individually.
+ var preParsed = vtt.split(/\r?\n\s*\r?\n/);
+ var lines = '', line;
+
+ preParsed.forEach((l) => {
+ // Sanitize each line.
+ line = validate.sanitizeVttContent(l);
+ lines += line + "\n\n";
+ });
+ // Load the sanitized content into the $tempDiv
+ $tempDiv.html(lines);
+ // Resolve the promise with the sanitized content
+ let data = { 'src': src, 'text': lines };
+ deferred.resolve(data);
+ $tempDiv.remove();
+ })
+ .catch( error => {
+ if (thisObj.debug) ;
+ deferred.reject(src);
+ $tempDiv.remove();
+ });
+
+ return promise;
+ };
+ }
+
+ function addTranscriptFunctions(AblePlayer) {
+ AblePlayer.prototype.setupTranscript = function () {
+ var deferred = new this.defer();
+ var promise = deferred.promise();
+
+ if (this.usingYouTubeCaptions || this.usingVimeoCaptions || this.hideTranscriptButton ) {
+ // a transcript is not possible or is disabled.
+ this.transcriptType = null;
+ deferred.resolve();
} else {
- opacity = parseFloat(this.prefCaptionsOpacity) / 100.0;
- $element.css({
- "font-family": this.prefCaptionsFont,
- color: this.prefCaptionsColor,
- "background-color": this.prefCaptionsBGColor,
- opacity: opacity,
- });
- if ($element === this.$captionsDiv) {
- if (typeof this.$captionsDiv !== "undefined") {
- this.$captionsDiv.css({
- "font-size": this.prefCaptionsSize,
- });
- }
- }
- if (this.prefCaptionsPosition === "below") {
- if (typeof this.$captionsWrapper !== "undefined") {
- this.$captionsWrapper.css({
- "background-color": this.prefCaptionsBGColor,
- opacity: "1",
- });
- }
- } else if (this.prefCaptionsPosition === "overlay") {
- if (typeof this.$captionsWrapper !== "undefined") {
- this.$captionsWrapper.css({
- "background-color": "transparent",
- opacity: "",
- });
+ if (!this.transcriptType) {
+ // previously set transcriptType to null since there are no
elements
+ // check again to see if captions have been collected from other sources (e.g., YouTube)
+
+ if (this.captions.length) {
+ // captions are possible! Use the default type (popup)
+ // if other types ('external' and 'manual') were desired, transcriptType would not be null here
+ this.transcriptType = "popup";
}
}
- this.positionCaptions();
- }
- }
- };
- AblePlayer.prototype.positionCaptions = function (position) {
- if (typeof position === "undefined") {
- position = this.prefCaptionsPosition;
- }
- if (typeof this.$captionsWrapper !== "undefined") {
- if (position == "below") {
- this.$captionsWrapper
- .removeClass("able-captions-overlay")
- .addClass("able-captions-below");
- this.$captionsWrapper.css({
- "background-color": this.prefCaptionsBGColor,
- opacity: "1",
- });
- } else {
- this.$captionsWrapper
- .removeClass("able-captions-below")
- .addClass("able-captions-overlay");
- this.$captionsWrapper.css({
- "background-color": "transparent",
- opacity: "",
- });
- }
- }
- };
-})(jQuery);
-
-(function ($) {
-
- AblePlayer.prototype.populateChaptersDiv = function() {
-
- var headingLevel, headingType, headingId, $chaptersHeading;
- if ( ! this.chaptersDivLocation ) {
- return;
- }
- if ($('#' + this.chaptersDivLocation)) {
-
- this.$chaptersDiv = $('#' + this.chaptersDivLocation);
- this.$chaptersDiv.addClass('able-chapters-div');
-
- this.$chaptersDiv.empty();
-
- if (this.chaptersTitle) {
- headingLevel = this.getNextHeadingLevel(this.$chaptersDiv);
- headingType = 'h' + headingLevel.toString();
- headingId = this.mediaId + '-chapters-heading';
- $chaptersHeading = $('<' + headingType + '>', {
- 'class': 'able-chapters-heading',
- 'id': headingId
- }).text(this.chaptersTitle);
- this.$chaptersDiv.append($chaptersHeading);
- }
-
- this.$chaptersNav = $('');
- if (this.chaptersTitle) {
- this.$chaptersNav.attr( 'aria-labelledby', headingId );
- } else {
- this.$chaptersNav.attr( 'aria-label', this.translate( 'chapters', 'Chapters' ) );
- }
- this.$chaptersDiv.append(this.$chaptersNav);
-
- this.updateChaptersList();
- }
- };
-
- AblePlayer.prototype.updateChaptersList = function() {
-
- var thisObj, cues, $chaptersList, c, thisChapter,
- $chapterItem, $chapterButton, hasDefault,
- getClickFunction, $clickedItem, $chaptersList;
-
- thisObj = this;
-
- if (!this.$chaptersNav) {
- return false;
- }
-
- if (typeof this.useChapterTimes === 'undefined') {
- this.useChapterTimes = (this.seekbarScope === 'chapter' && this.selectedChapters.cues.length) ? true : false;
- }
- if (this.useChapterTimes) {
- cues = this.selectedChapters.cues;
- } else if (this.chapters.length >= 1) {
- cues = this.chapters[0].cues;
- } else {
- cues = [];
- }
- if (cues.length > 0) {
- $chaptersList = $('');
- for (c = 0; c < cues.length; c++) {
- thisChapter = c;
- $chapterItem = $(' ');
- $chapterButton = $('',{
- 'type': 'button',
- 'val': thisChapter
- }).text(this.flattenCueForCaption(cues[thisChapter]));
-
- getClickFunction = function (time) {
- return function () {
- thisObj.seekTrigger = 'chapter';
- $clickedItem = $(this).closest('li');
- $chaptersList = $(this).closest('ul').find('li');
- $chaptersList.removeClass('able-current-chapter')
- .children('button').removeAttr('aria-current');
- $clickedItem.addClass('able-current-chapter')
- .children('button').attr('aria-current','true');
- thisObj.updateChapter(time);
- thisObj.seekTo(time);
- }
- };
- $chapterButton.on('click',getClickFunction(cues[thisChapter].start));
- $chapterButton.on('focus',function() {
- $(this).closest('ul').find('li').removeClass('able-focus');
- $(this).closest('li').addClass('able-focus');
- });
- $chapterItem.on('hover',function() {
- $(this).closest('ul').find('li').removeClass('able-focus');
- $(this).addClass('able-focus');
- });
- $chapterItem.on('mouseleave',function() {
- $(this).removeClass('able-focus');
- });
- $chapterButton.on('blur',function() {
- $(this).closest('li').removeClass('able-focus');
- });
-
- $chapterItem.append($chapterButton);
- $chaptersList.append($chapterItem);
- if (this.defaultChapter === cues[thisChapter].id) {
- $chapterButton.attr('aria-current','true').parent('li').addClass('able-current-chapter');
- this.currentChapter = cues[thisChapter];
- hasDefault = true;
- }
- }
- if (!hasDefault) {
- this.currentChapter = cues[0];
- $chaptersList.find('button').first().attr('aria-current','true')
- .parent('li').addClass('able-current-chapter');
- }
- this.$chaptersNav.html($chaptersList);
- }
- return false;
- };
-
- AblePlayer.prototype.seekToChapter = function(chapterId) {
-
- var i=0;
- while (i < this.selectedChapters.cues.length) {
- if (this.selectedChapters.cues[i].id == chapterId) {
- this.seekTo(this.selectedChapters.cues[i].start);
- this.updateChapter(this.selectedChapters.cues[i].start);
- break;
- }
- i++;
- }
- };
-
- AblePlayer.prototype.updateChapter = function (now) {
-
- if (typeof this.selectedChapters === 'undefined') {
- return;
- }
-
- var chapters, i, thisChapterIndex;
-
- chapters = this.selectedChapters.cues;
- for (i = 0; i < chapters.length; i++) {
- if ((chapters[i].start <= now) && (chapters[i].end > now)) {
- thisChapterIndex = i;
- break;
- }
- }
- if (typeof thisChapterIndex !== 'undefined') {
- if (this.currentChapter !== chapters[thisChapterIndex]) {
- this.currentChapter = chapters[thisChapterIndex];
- if (this.useChapterTimes) {
- this.chapterDuration = this.getChapterDuration();
- this.seekIntervalCalculated = false;
- }
- if (typeof this.$chaptersDiv !== 'undefined') {
- this.$chaptersDiv.find('ul').find('li')
- .removeClass('able-current-chapter')
- .children('button').removeAttr('aria-current');
- this.$chaptersDiv.find('ul').find('li').eq(thisChapterIndex)
- .addClass('able-current-chapter')
- .children('button').attr('aria-current','true');
- }
- }
- }
- };
-
- AblePlayer.prototype.getChapterDuration = function () {
-
-
- var lastChapterIndex, chapterEnd;
-
- if (typeof this.currentChapter === 'undefined') {
- return 0;
- }
- if (typeof this.duration === 'undefined') {
- return 0;
- }
- lastChapterIndex = this.selectedChapters.cues.length-1;
- if (this.selectedChapters.cues[lastChapterIndex] == this.currentChapter) {
- if (this.currentChapter.end !== this.duration) {
- chapterEnd = this.duration;
- this.currentChapter.end = this.duration;
- } else {
- chapterEnd = this.currentChapter.end;
- }
- } else {
- chapterEnd = this.currentChapter.end;
- }
- return chapterEnd - this.currentChapter.start;
- };
-
- AblePlayer.prototype.getChapterElapsed = function () {
-
- if (typeof this.currentChapter === 'undefined') {
- return 0;
- }
-
- if (this.elapsed > this.currentChapter.start) {
- return this.elapsed - this.currentChapter.start;
- } else {
- return 0;
- }
- };
-
- AblePlayer.prototype.convertChapterTimeToVideoTime = function (chapterTime) {
-
- if (typeof this.currentChapter !== 'undefined') {
- var newTime = this.currentChapter.start + chapterTime;
- if (newTime > this.currentChapter.end) {
- return this.currentChapter.end;
- } else {
- return newTime;
- }
- } else {
- return chapterTime;
- }
- };
-
- AblePlayer.prototype.getChapterClickFunction = function (time) {
-
- var thisObj = this;
- return function () {
- thisObj.seekTrigger = 'chapter';
- thisObj.seekTo(time);
- thisObj.hidingPopup = true;
- thisObj.chaptersPopup.hide();
- setTimeout(function() {
- thisObj.hidingPopup = false;
- }, 100);
- thisObj.$chaptersButton.trigger('focus');
- }
- };
-
-})(jQuery);
-
-(function ($) {
- AblePlayer.prototype.updateMeta = function (time) {
- if (this.hasMeta) {
- if (this.metaType === "text") {
- this.$metaDiv.show();
- this.showMeta(time || this.elapsed);
- } else {
- this.showMeta(time || this.elapsed);
- }
- }
- };
-
- AblePlayer.prototype.showMeta = function (now) {
- var tempSelectors,
- m,
- thisMeta,
- cues,
- cueText,
- cueLines,
- i,
- line,
- showDuration,
- focusTarget;
-
- tempSelectors = [];
- if (this.meta.length >= 1) {
- cues = this.meta;
- } else {
- cues = [];
- }
- for (m = 0; m < cues.length; m++) {
- if (cues[m].start <= now && cues[m].end > now) {
- thisMeta = m;
- break;
- }
- }
- if (typeof thisMeta !== "undefined") {
- if (this.currentMeta !== thisMeta) {
- if (this.metaType === "text") {
- this.$metaDiv.html(
- this.flattenCueForMeta(cues[thisMeta]).replace(/\n/g, " ")
- );
- } else if (this.metaType === "selector") {
- cueText = this.flattenCueForMeta(cues[thisMeta]);
- cueLines = cueText.split("\n");
- for (i = 0; i < cueLines.length; i++) {
- line = cueLines[i].trim();
- if (line.toLowerCase().trim() === "pause") {
- this.hideBigPlayButton = true;
- this.pauseMedia();
- } else if (line.toLowerCase().substring(0, 6) == "focus:") {
- focusTarget = line.substring(6).trim();
- if ($(focusTarget).length) {
- $(focusTarget).trigger('focus');
- }
- } else {
- if ($(line).length) {
- this.currentMeta = thisMeta;
- showDuration = parseInt($(line).attr("data-duration"));
- if (
- typeof showDuration !== "undefined" &&
- !isNaN(showDuration)
- ) {
- $(line).show();
- const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
- delay(showDuration).then(() => {
- $(line).hide();
- });
- } else {
- $(line).show();
- }
- this.visibleSelectors.push(line);
- tempSelectors.push(line);
- }
- }
+ if (this.transcriptType) {
+ if ( this.transcriptType === "popup" || this.transcriptType === "external" ) {
+ this.injectTranscriptArea();
+ deferred.resolve();
+ } else if (this.transcriptType === "manual") {
+ this.setupManualTranscript();
+ deferred.resolve();
}
- if (this.visibleSelectors && this.visibleSelectors.length) {
- if (this.visibleSelectors.length !== tempSelectors.length) {
- for (i = this.visibleSelectors.length - 1; i >= 0; i--) {
- if ($.inArray(this.visibleSelectors[i], tempSelectors) == -1) {
- $(this.visibleSelectors[i]).hide();
- this.visibleSelectors.splice(i, 1);
- }
- }
- }
- }
- }
- }
- } else {
- if (typeof this.$metaDiv !== "undefined") {
- this.$metaDiv.html("");
- }
- if (this.visibleSelectors && this.visibleSelectors.length) {
- for (i = 0; i < this.visibleSelectors.length; i++) {
- $(this.visibleSelectors[i]).hide();
- }
- this.visibleSelectors = [];
- }
- this.currentMeta = -1;
- }
- };
-
- AblePlayer.prototype.flattenCueForMeta = function (cue) {
- var result = [];
-
- var flattenComponent = function (component) {
- var result = [],
- ii;
- if (component.type === "string") {
- result.push(component.value);
- } else if (component.type === "v") {
- result.push("[" + component.value + "]");
- for (ii = 0; ii < component.children.length; ii++) {
- result.push(flattenComponent(component.children[ii]));
- }
- } else {
- for (ii = 0; ii < component.children.length; ii++) {
- result.push(flattenComponent(component.children[ii]));
+ } else {
+ // there is no transcript
+ deferred.resolve();
}
}
- return result.join("");
+ return promise;
};
- for (var ii = 0; ii < cue.components.children.length; ii++) {
- result.push(flattenComponent(cue.components.children[ii]));
- }
+ AblePlayer.prototype.injectTranscriptArea = function () {
+ var $autoScrollLabel,
+ $autoScrollContainer,
+ $languageSelectWrapper,
+ $languageSelectLabel,
+ i,
+ $option;
- return result.join("");
- };
-})(jQuery);
+ this.$transcriptArea = $("", {
+ class: "able-transcript-area",
+ role: "dialog",
+ "aria-label": this.translate( 'transcriptTitle', 'Transcript' ),
+ });
-(function ($) {
- AblePlayer.prototype.setupTranscript = function () {
- var deferred = new this.defer();
- var promise = deferred.promise();
+ this.$transcriptToolbar = $("
", {
+ class: "able-window-toolbar able-" + this.toolbarIconColor + "-controls",
+ });
- if (this.usingYouTubeCaptions || this.usingVimeoCaptions || this.hideTranscriptButton ) {
- this.transcriptType = null;
- deferred.resolve();
- } else {
- if (!this.transcriptType) {
+ this.$transcriptDiv = $("
", {
+ class: "able-transcript",
+ });
- if (this.captions.length) {
- this.transcriptType = "popup";
+ // Transcript toolbar content
+
+ // Add auto Scroll checkbox
+ this.$autoScrollTranscriptCheckbox = $("
", {
+ id: "autoscroll-transcript-checkbox-" + this.mediaId,
+ type: "checkbox",
+ });
+ $autoScrollLabel = $("
", {
+ for: "autoscroll-transcript-checkbox-" + this.mediaId,
+ }).text( this.translate( 'autoScroll', 'Auto scroll' ) );
+ $autoScrollContainer = $( '', {
+ 'class': 'autoscroll-transcript'
+ });
+ $autoScrollContainer.append(
+ $autoScrollLabel,
+ this.$autoScrollTranscriptCheckbox
+ );
+ this.$transcriptToolbar.append( $autoScrollContainer );
+
+ // Add field for selecting a transcript language
+ // Only necessary if there is more than one language
+ if (this.captions.length > 1) {
+ $languageSelectWrapper = $("
", {
+ class: "transcript-language-select-wrapper",
+ });
+ $languageSelectLabel = $("
", {
+ for: "transcript-language-select-" + this.mediaId,
+ }).text( this.translate( 'language', 'Language' ) );
+ this.$transcriptLanguageSelect = $("", {
+ id: "transcript-language-select-" + this.mediaId,
+ });
+ for (i = 0; i < this.captions.length; i++) {
+ $option = $(" ", {
+ value: this.captions[i]["language"],
+ lang: this.captions[i]["language"],
+ }).text(this.captions[i]["label"]);
+ if (this.captions[i]["def"]) {
+ $option.prop("selected", true);
+ }
+ this.$transcriptLanguageSelect.append($option);
}
}
- if (this.transcriptType) {
- if ( this.transcriptType === "popup" || this.transcriptType === "external" ) {
- this.injectTranscriptArea();
- deferred.resolve();
- } else if (this.transcriptType === "manual") {
- this.setupManualTranscript();
- deferred.resolve();
- }
+ if ($languageSelectWrapper) {
+ $languageSelectWrapper.append(
+ $languageSelectLabel,
+ this.$transcriptLanguageSelect
+ );
+ this.$transcriptToolbar.append($languageSelectWrapper);
+ }
+ this.$transcriptArea.append(this.$transcriptToolbar, this.$transcriptDiv);
+
+ // If client has provided separate transcript location, put it there.
+ // Otherwise append it to the body
+ if (this.transcriptDivLocation) {
+ this.$transcriptArea.removeAttr( 'role' );
+ this.$transcriptArea.removeAttr( 'aria-label' );
+ $("#" + this.transcriptDivLocation).append(this.$transcriptArea);
} else {
- deferred.resolve();
+ this.$ableWrapper.append(this.$transcriptArea);
}
- }
- return promise;
- };
- AblePlayer.prototype.injectTranscriptArea = function () {
- var thisObj,
- $autoScrollLabel,
- $languageSelectWrapper,
- $languageSelectLabel,
- i,
- $option;
-
- thisObj = this;
- this.$transcriptArea = $("", {
- class: "able-transcript-area",
- role: "dialog",
- "aria-label": this.translate( 'transcriptTitle', 'Transcript' ),
- });
-
- this.$transcriptToolbar = $("
", {
- class: "able-window-toolbar able-" + this.toolbarIconColor + "-controls",
- });
-
- this.$transcriptDiv = $("
", {
- class: "able-transcript",
- });
-
-
- this.$autoScrollTranscriptCheckbox = $("
", {
- id: "autoscroll-transcript-checkbox-" + this.mediaId,
- type: "checkbox",
- });
- $autoScrollLabel = $("
", {
- for: "autoscroll-transcript-checkbox-" + this.mediaId,
- }).text( this.translate( 'autoScroll', 'Auto scroll' ) );
- $autoScrollContainer = $( '', {
- 'class': 'autoscroll-transcript'
- });
- $autoScrollContainer.append(
- $autoScrollLabel,
- this.$autoScrollTranscriptCheckbox
- );
- this.$transcriptToolbar.append( $autoScrollContainer );
-
- if (this.captions.length > 1) {
- $languageSelectWrapper = $("
", {
- class: "transcript-language-select-wrapper",
- });
- $languageSelectLabel = $("
", {
- for: "transcript-language-select-" + this.mediaId,
- }).text( this.translate( 'language', 'Language' ) );
- this.$transcriptLanguageSelect = $("", {
- id: "transcript-language-select-" + this.mediaId,
- });
- for (i = 0; i < this.captions.length; i++) {
- $option = $(" ", {
- value: this.captions[i]["language"],
- lang: this.captions[i]["language"],
- }).text(this.captions[i]["label"]);
- if (this.captions[i]["def"]) {
- $option.prop("selected", true);
+ // make it draggable (popup only; NOT external transcript)
+ if (!this.transcriptDivLocation) {
+ this.initDragDrop("transcript");
+ if (this.prefTranscript === 1) {
+ // transcript is on. Go ahead and position it
+ this.positionDraggableWindow(
+ "transcript",
+ this.getDefaultWidth("transcript")
+ );
}
- this.$transcriptLanguageSelect.append($option);
}
- }
- if ($languageSelectWrapper) {
- $languageSelectWrapper.append(
- $languageSelectLabel,
- this.$transcriptLanguageSelect
- );
- this.$transcriptToolbar.append($languageSelectWrapper);
- }
- this.$transcriptArea.append(this.$transcriptToolbar, this.$transcriptDiv);
-
- if (this.transcriptDivLocation) {
- this.$transcriptArea.removeAttr( 'role' );
- this.$transcriptArea.removeAttr( 'aria-label' );
- $("#" + this.transcriptDivLocation).append(this.$transcriptArea);
- } else {
- this.$ableWrapper.append(this.$transcriptArea);
- }
- if (!this.transcriptDivLocation) {
- this.initDragDrop("transcript");
- if (this.prefTranscript === 1) {
- this.positionDraggableWindow(
- "transcript",
- this.getDefaultWidth("transcript")
- );
+ // If client has provided separate transcript location, override user's preference for hiding transcript
+ if (!this.prefTranscript && !this.transcriptDivLocation) {
+ this.$transcriptArea.hide();
}
- }
+ };
- if (!this.prefTranscript && !this.transcriptDivLocation) {
- this.$transcriptArea.hide();
- }
- };
+ AblePlayer.prototype.addTranscriptAreaEvents = function () {
+ var thisObj = this;
- AblePlayer.prototype.addTranscriptAreaEvents = function () {
- var thisObj = this;
+ this.$autoScrollTranscriptCheckbox.on( 'click', function () {
+ thisObj.handleTranscriptLockToggle(
+ thisObj.$autoScrollTranscriptCheckbox.prop("checked")
+ );
+ });
- this.$autoScrollTranscriptCheckbox.on( 'click', function () {
- thisObj.handleTranscriptLockToggle(
- thisObj.$autoScrollTranscriptCheckbox.prop("checked")
- );
- });
-
- this.$transcriptDiv.on(
- "mousewheel DOMMouseScroll click scroll",
- function (e) {
- if (!thisObj.scrollingTranscript) {
- thisObj.autoScrollTranscript = false;
- thisObj.refreshControls("transcript");
+ this.$transcriptDiv.on(
+ "mousewheel DOMMouseScroll click scroll",
+ function (e) {
+ // Propagation is stopped in transcript click handler, so clicks are on the scrollbar
+ // or outside of a clickable span.
+ if (!thisObj.scrollingTranscript) {
+ thisObj.autoScrollTranscript = false;
+ thisObj.refreshControls("transcript");
+ }
+ thisObj.scrollingTranscript = false;
}
- thisObj.scrollingTranscript = false;
- }
- );
+ );
- if (typeof this.$transcriptLanguageSelect !== "undefined") {
- this.$transcriptLanguageSelect.on('click', function (e) {
- e.stopPropagation();
- });
+ if (typeof this.$transcriptLanguageSelect !== "undefined") {
+ this.$transcriptLanguageSelect.on('click', function (e) {
+ // execute default behavior
+ // prevent propagation of mouse event to toolbar or window
+ e.stopPropagation();
+ });
- this.$transcriptLanguageSelect.on("change", function () {
- var language = thisObj.$transcriptLanguageSelect.val();
+ this.$transcriptLanguageSelect.on("change", function () {
+ var language = thisObj.$transcriptLanguageSelect.val();
- thisObj.syncTrackLanguages("transcript", language);
- });
- }
- };
+ thisObj.syncTrackLanguages("transcript", language);
+ });
+ }
+ };
+
+ AblePlayer.prototype.transcriptSrcHasRequiredParts = function () {
+ // check the external transcript to be sure it has all required components
+ // return true or false
+ // in the process, define all the needed variables and properties
- AblePlayer.prototype.transcriptSrcHasRequiredParts = function () {
-
- if ($("#" + this.transcriptSrc).length) {
- this.$transcriptArea = $("#" + this.transcriptSrc);
- if (this.$transcriptArea.find(".able-window-toolbar").length) {
- this.$transcriptToolbar = this.$transcriptArea
- .find(".able-window-toolbar")
- .eq(0);
- if (this.$transcriptArea.find(".able-transcript").length) {
- this.$transcriptDiv = this.$transcriptArea
- .find(".able-transcript")
+ if ($("#" + this.transcriptSrc).length) {
+ this.$transcriptArea = $("#" + this.transcriptSrc);
+ if (this.$transcriptArea.find(".able-window-toolbar").length) {
+ this.$transcriptToolbar = this.$transcriptArea
+ .find(".able-window-toolbar")
.eq(0);
- if (this.$transcriptArea.find(".able-transcript-seekpoint").length) {
- this.$transcriptSeekpoints = this.$transcriptArea.find(
- ".able-transcript-seekpoint"
- );
- return true;
+ if (this.$transcriptArea.find(".able-transcript").length) {
+ this.$transcriptDiv = this.$transcriptArea
+ .find(".able-transcript")
+ .eq(0);
+ if (this.$transcriptArea.find(".able-transcript-seekpoint").length) {
+ this.$transcriptSeekpoints = this.$transcriptArea.find(
+ ".able-transcript-seekpoint"
+ );
+ return true;
+ }
}
}
}
- }
- return false;
- };
+ return false;
+ };
- AblePlayer.prototype.setupManualTranscript = function () {
- var $autoScrollInput, $autoScrollLabel;
-
- $autoScrollInput = $(" ", {
- id: "autoscroll-transcript-checkbox-" + this.mediaId,
- type: "checkbox",
- });
- $autoScrollLabel = $("", {
- for: "autoscroll-transcript-checkbox-" + this.mediaId,
- }).text( this.translate( 'autoScroll', 'Auto scroll' ) );
-
- this.$autoScrollTranscriptCheckbox = $autoScrollInput;
- this.$transcriptToolbar.append(
- $autoScrollLabel,
- this.$autoScrollTranscriptCheckbox
- );
- };
+ AblePlayer.prototype.setupManualTranscript = function () {
+ var $autoScrollInput, $autoScrollLabel;
- AblePlayer.prototype.updateTranscript = function () {
- if (!this.transcriptType) {
- return;
- }
- if (this.playerCreated && !this.$transcriptArea) {
- return;
- }
- if (this.transcriptType === "external" || this.transcriptType === "popup") {
- var chapters, captions, descriptions;
+ $autoScrollInput = $(" ", {
+ id: "autoscroll-transcript-checkbox-" + this.mediaId,
+ type: "checkbox",
+ });
+ $autoScrollLabel = $("", {
+ for: "autoscroll-transcript-checkbox-" + this.mediaId,
+ }).text( this.translate( 'autoScroll', 'Auto scroll' ) );
+
+ // Add an auto-scroll checkbox to the toolbar.
+ this.$autoScrollTranscriptCheckbox = $autoScrollInput;
+ this.$transcriptToolbar.append(
+ $autoScrollLabel,
+ this.$autoScrollTranscriptCheckbox
+ );
+ };
- if (this.transcriptLang) {
- captions = this.transcriptCaptions.cues;
- } else {
- if (this.transcriptCaptions) {
- this.transcriptLang = this.transcriptCaptions.language;
- captions = this.transcriptCaptions.cues;
- } else if (this.selectedCaptions) {
- this.transcriptLang = this.captionLang;
- captions = this.selectedCaptions.cues;
- }
+ AblePlayer.prototype.updateTranscript = function () {
+ if (!this.transcriptType) {
+ return;
}
+ if (this.playerCreated && !this.$transcriptArea) {
+ return;
+ }
+ if (this.transcriptType === "external" || this.transcriptType === "popup") {
+ var chapters, captions, descriptions;
- if (this.transcriptChapters) {
- chapters = this.transcriptChapters.cues;
- } else if (this.chapters.length > 0) {
+ // Language of transcript might be different than language of captions
+ // But both are in sync by default
if (this.transcriptLang) {
- for (var i = 0; i < this.chapters.length; i++) {
- if (this.chapters[i].language === this.transcriptLang) {
- chapters = this.chapters[i].cues;
+ captions = this.transcriptCaptions.cues;
+ } else {
+ if (this.transcriptCaptions) {
+ this.transcriptLang = this.transcriptCaptions.language;
+ captions = this.transcriptCaptions.cues;
+ } else if (this.selectedCaptions) {
+ this.transcriptLang = this.captionLang;
+ captions = this.selectedCaptions.cues;
+ }
+ }
+
+ // setup chapters
+ if (this.transcriptChapters) {
+ chapters = this.transcriptChapters.cues;
+ } else if (this.chapters.length > 0) {
+ // Try and match the caption language.
+ if (this.transcriptLang) {
+ for (var i = 0; i < this.chapters.length; i++) {
+ if (this.chapters[i].language === this.transcriptLang) {
+ chapters = this.chapters[i].cues;
+ }
+ }
+ }
+ if (typeof chapters === "undefined") {
+ chapters = this.chapters[0].cues || [];
+ }
+ }
+
+ // setup descriptions
+ if (this.transcriptDescriptions) {
+ descriptions = this.transcriptDescriptions.cues;
+ } else if (this.descriptions.length > 0) {
+ // Try and match the caption language.
+ if (this.transcriptLang) {
+ for (i = 0; i < this.descriptions.length; i++) {
+ if (this.descriptions[i].language === this.transcriptLang) {
+ descriptions = this.descriptions[i].cues;
+ }
}
}
+ if (!descriptions) {
+ descriptions = this.descriptions[0].cues || [];
+ }
}
- if (typeof chapters === "undefined") {
- chapters = this.chapters[0].cues || [];
+
+ var div = this.generateTranscript(
+ chapters || [],
+ captions || [],
+ descriptions || []
+ );
+ this.$transcriptDiv.html(div);
+ // reset transcript selected to this.transcriptLang
+ if (this.$transcriptLanguageSelect) {
+ this.$transcriptLanguageSelect
+ .find("option:selected")
+ .prop("selected", false);
+ this.$transcriptLanguageSelect
+ .find("option[lang=" + this.transcriptLang + "]")
+ .prop("selected", true);
}
}
- if (this.transcriptDescriptions) {
- descriptions = this.transcriptDescriptions.cues;
- } else if (this.descriptions.length > 0) {
- if (this.transcriptLang) {
- for (var i = 0; i < this.descriptions.length; i++) {
- if (this.descriptions[i].language === this.transcriptLang) {
- descriptions = this.descriptions[i].cues;
+ var thisObj = this;
+
+ // Make transcript tabbable if preference is turned on.
+ if (this.prefTabbable === 1) {
+ this.$transcriptDiv
+ .find("span.able-transcript-seekpoint")
+ .attr("tabindex", "0");
+ }
+
+ // handle clicks on text within transcript
+ // Note: This event listeners handles clicks only, not keydown events
+ // Pressing Enter on an element that is not natively clickable does NOT trigger click()
+ // Keydown events are handled elsehwere, both globally (ableplayer-base.js) and locally (event.js)
+ if (this.$transcriptArea.length > 0) {
+ this.$transcriptArea
+ .find("span.able-transcript-seekpoint")
+ .on( 'click', function (e) {
+ thisObj.seekTrigger = "transcript";
+ var spanStart = parseFloat($(this).attr("data-start"));
+ // Add a tiny amount so that we're inside the span.
+ spanStart += 0.01;
+ // Each click within the transcript triggers two click events (not sure why)
+ // this.seekingFromTranscript is a stopgab to prevent two calls to SeekTo()
+ if (!thisObj.seekingFromTranscript) {
+ thisObj.seekingFromTranscript = true;
+ thisObj.seekTo(spanStart);
+ } else {
+ // don't seek a second time, but do reset var
+ thisObj.seekingFromTranscript = false;
}
- }
- }
- if (!descriptions) {
- descriptions = this.descriptions[0].cues || [];
- }
+ });
}
+ };
- var div = this.generateTranscript(
- chapters || [],
- captions || [],
- descriptions || []
- );
- this.$transcriptDiv.html(div);
- if (this.$transcriptLanguageSelect) {
- this.$transcriptLanguageSelect
- .find("option:selected")
- .prop("selected", false);
- this.$transcriptLanguageSelect
- .find("option[lang=" + this.transcriptLang + "]")
- .prop("selected", true);
+ AblePlayer.prototype.highlightTranscript = function (currentTime) {
+ // Show highlight in transcript marking current caption.
+
+ if (!this.transcriptType) {
+ return;
}
- }
- var thisObj = this;
+ var start, end, isChapterHeading;
+ var thisObj = this;
- if (this.prefTabbable === 1) {
- this.$transcriptDiv
- .find("span.able-transcript-seekpoint")
- .attr("tabindex", "0");
- }
+ currentTime = parseFloat(currentTime);
- if (this.$transcriptArea.length > 0) {
+ // Highlight the current transcript item.
this.$transcriptArea
.find("span.able-transcript-seekpoint")
- .on( 'click', function (e) {
- thisObj.seekTrigger = "transcript";
- var spanStart = parseFloat($(this).attr("data-start"));
- spanStart += 0.01;
- if (!thisObj.seekingFromTranscript) {
- thisObj.seekingFromTranscript = true;
- thisObj.seekTo(spanStart);
+ .each(function () {
+ start = parseFloat($(this).attr("data-start"));
+ end = parseFloat($(this).attr("data-end"));
+ // be sure this isn't a chapter (don't highlight chapter headings)
+ if ($(this).parent().hasClass("able-transcript-chapter-heading")) {
+ isChapterHeading = true;
} else {
- thisObj.seekingFromTranscript = false;
+ isChapterHeading = false;
}
- });
- }
- };
-
- AblePlayer.prototype.highlightTranscript = function (currentTime) {
-
- if (!this.transcriptType) {
- return;
- }
-
- var start, end, isChapterHeading;
- var thisObj = this;
-
- currentTime = parseFloat(currentTime);
-
- this.$transcriptArea
- .find("span.able-transcript-seekpoint")
- .each(function () {
- start = parseFloat($(this).attr("data-start"));
- end = parseFloat($(this).attr("data-end"));
- if ($(this).parent().hasClass("able-transcript-chapter-heading")) {
- isChapterHeading = true;
- } else {
- isChapterHeading = false;
- }
- if (currentTime >= start && currentTime <= end && !isChapterHeading) {
- if (!$(this).hasClass("able-highlight")) {
- thisObj.$transcriptArea
- .find(".able-highlight")
- .removeClass("able-highlight");
- $(this).addClass("able-highlight");
- thisObj.movingHighlight = true;
+ if (currentTime >= start && currentTime <= end && !isChapterHeading) {
+ // If this item isn't already highlighted, it should be
+ if (!$(this).hasClass("able-highlight")) {
+ // remove all previous highlights before adding one to current span
+ thisObj.$transcriptArea
+ .find(".able-highlight")
+ .removeClass("able-highlight");
+ $(this).addClass("able-highlight");
+ thisObj.movingHighlight = true;
+ }
+ return false;
}
- return false;
- }
- });
- thisObj.currentHighlight = thisObj.$transcriptArea.find(".able-highlight");
- if (thisObj.currentHighlight.length === 0) {
- thisObj.currentHighlight = null;
- }
- };
-
- AblePlayer.prototype.generateTranscript = function (
- chapters,
- captions,
- descriptions
- ) {
- var thisObj = this;
-
- var $main = $('
');
- var transcriptTitle;
+ });
+ thisObj.currentHighlight = thisObj.$transcriptArea.find(".able-highlight");
+ if (thisObj.currentHighlight.length === 0) {
+ // Nothing highlighted.
+ thisObj.currentHighlight = null;
+ }
+ };
- $main.attr("lang", this.transcriptLang);
+ AblePlayer.prototype.generateTranscript = function (
+ chapters,
+ captions,
+ descriptions
+ ) {
+ var thisObj = this;
- if (typeof this.transcriptTitle !== "undefined") {
- transcriptTitle = this.transcriptTitle;
- } else if (this.lyricsMode) {
- transcriptTitle = this.translate( 'lyricsTitle', 'Lyrics' );
- } else {
- transcriptTitle = this.translate( 'transcriptTitle', 'Transcript' );
- }
+ var $main = $('
');
+ var transcriptTitle, firstStart;
- if (!this.transcriptDivLocation) {
- var headingNumber = this.playerHeadingLevel;
- headingNumber += 1;
- var chapterHeadingNumber = headingNumber + 1;
+ // set language for transcript container
+ $main.attr("lang", this.transcriptLang);
- if (headingNumber <= 6) {
- var transcriptHeading = "h" + headingNumber.toString();
+ if (typeof this.transcriptTitle !== "undefined") {
+ transcriptTitle = this.transcriptTitle;
+ } else if (this.lyricsMode) {
+ transcriptTitle = this.translate( 'lyricsTitle', 'Lyrics' );
} else {
- var transcriptHeading = "div";
- }
- var $transcriptHeadingTag = $("<" + transcriptHeading + ">");
- $transcriptHeadingTag.addClass("able-transcript-heading");
- if (headingNumber > 6) {
- $transcriptHeadingTag.attr({
- role: "heading",
- "aria-level": headingNumber,
- });
+ transcriptTitle = this.translate( 'transcriptTitle', 'Transcript' );
}
- $transcriptHeadingTag.text(transcriptTitle);
- $transcriptHeadingTag.attr("lang", this.lang);
+ if (!this.transcriptDivLocation) {
+ // only add an HTML heading to internal transcript
+ // external transcript is expected to have its own heading
+ var headingNumber = this.playerHeadingLevel;
+ headingNumber += 1;
+ var chapterHeadingNumber = headingNumber + 1;
- $main.append($transcriptHeadingTag);
- }
+ let transcriptHeading;
+ if (headingNumber <= 6) {
+ transcriptHeading = "h" + headingNumber.toString();
+ } else {
+ transcriptHeading = "div";
+ }
+ var $transcriptHeadingTag = $("<" + transcriptHeading + ">");
+ $transcriptHeadingTag.addClass("able-transcript-heading");
+ if (headingNumber > 6) {
+ $transcriptHeadingTag.attr({
+ role: "heading",
+ "aria-level": headingNumber,
+ });
+ }
+ $transcriptHeadingTag.text(transcriptTitle);
- var nextChapter = 0;
- var nextCap = 0;
- var nextDesc = 0;
+ // set language of transcript heading to language of player
+ // this is independent of language of transcript
+ $transcriptHeadingTag.attr("lang", this.lang);
- var addChapter = function (div, chap) {
- if (chapterHeadingNumber <= 6) {
- var chapterHeading = "h" + chapterHeadingNumber.toString();
- } else {
- var chapterHeading = "div";
+ $main.append($transcriptHeadingTag);
}
- var $chapterHeadingTag = $("<" + chapterHeading + ">", {
- class: "able-transcript-chapter-heading",
- });
- if (chapterHeadingNumber > 6) {
- $chapterHeadingTag.attr({
- role: "heading",
- "aria-level": chapterHeadingNumber,
- });
- }
+ var nextChapter = 0;
+ var nextCap = 0;
+ var nextDesc = 0;
- var flattenComponentForChapter = function (comp) {
- var result = [];
- if (comp.type === "string") {
- result.push(comp.value);
+ var addChapter = function (div, chap) {
+ let chapterHeading;
+ if (chapterHeadingNumber <= 6) {
+ chapterHeading = "h" + chapterHeadingNumber.toString();
} else {
- for (var i = 0; i < comp.children.length; i++) {
- result = result.concat(
- flattenComponentForChapter(comp.children[i])
- );
- }
+ chapterHeading = "div";
}
- return result;
- };
- var $chapSpan = $("", {
- class: "able-transcript-seekpoint",
- });
- for (var i = 0; i < chap.components.children.length; i++) {
- var results = flattenComponentForChapter(chap.components.children[i]);
- for (var jj = 0; jj < results.length; jj++) {
- $chapSpan.append(results[jj]);
+ var $chapterHeadingTag = $("<" + chapterHeading + ">", {
+ class: "able-transcript-chapter-heading",
+ });
+ if (chapterHeadingNumber > 6) {
+ $chapterHeadingTag.attr({
+ role: "heading",
+ "aria-level": chapterHeadingNumber,
+ });
}
- }
- $chapSpan.attr("data-start", chap.start.toString());
- $chapSpan.attr("data-end", chap.end.toString());
- $chapterHeadingTag.append($chapSpan);
- div.append($chapterHeadingTag);
- };
+ var flattenComponentForChapter = function (comp) {
+ var result = [];
+ if (comp.type === "string") {
+ result.push(comp.value);
+ } else {
+ for (var i = 0; i < comp.children.length; i++) {
+ result = result.concat(
+ flattenComponentForChapter(comp.children[i])
+ );
+ }
+ }
+ return result;
+ };
- var addDescription = function (div, desc) {
- var $descDiv = $("", {
- class: "able-transcript-desc",
- });
- var $descHiddenSpan = $("
", {
- class: "able-hidden",
- });
- $descHiddenSpan.attr("lang", thisObj.lang);
- $descHiddenSpan.text(thisObj.tt.prefHeadingDescription + ": ");
- $descDiv.append($descHiddenSpan);
-
- var flattenComponentForDescription = function (comp) {
- var result = [];
- if (comp.type === "string") {
- result.push(comp.value);
- } else {
- for (var i = 0; i < comp.children.length; i++) {
- result = result.concat(
- flattenComponentForDescription(comp.children[i])
- );
+ var $chapSpan = $("", {
+ class: "able-transcript-seekpoint",
+ });
+ for (var i = 0; i < chap.components.children.length; i++) {
+ var results = flattenComponentForChapter(chap.components.children[i]);
+ for (var jj = 0; jj < results.length; jj++) {
+ $chapSpan.append(results[jj]);
}
}
- return result;
+ $chapSpan.attr("data-start", chap.start.toString());
+ $chapSpan.attr("data-end", chap.end.toString());
+ $chapterHeadingTag.append($chapSpan);
+
+ div.append($chapterHeadingTag);
};
- var $descSpan = $("", {
- class: "able-transcript-seekpoint",
- });
- for (var i = 0; i < desc.components.children.length; i++) {
- var results = flattenComponentForDescription(
- desc.components.children[i]
- );
- for (var jj = 0; jj < results.length; jj++) {
- $descSpan.append(results[jj]);
+ var addDescription = function (div, desc) {
+ var $descDiv = $("", {
+ class: "able-transcript-desc",
+ });
+ var $descHiddenSpan = $("
", {
+ class: "able-hidden",
+ });
+ $descHiddenSpan.attr("lang", thisObj.lang);
+ $descHiddenSpan.text( thisObj.translate( 'prefHeadingDescription', 'Audio description' ) + ": ");
+ $descDiv.append($descHiddenSpan);
+
+ var flattenComponentForDescription = function (comp) {
+ var result = [];
+ if (comp.type === "string") {
+ result.push(comp.value);
+ } else {
+ for (var i = 0; i < comp.children.length; i++) {
+ result = result.concat(
+ flattenComponentForDescription(comp.children[i])
+ );
+ }
+ }
+ return result;
+ };
+
+ var $descSpan = $("", {
+ class: "able-transcript-seekpoint",
+ });
+ for (var i = 0; i < desc.components.children.length; i++) {
+ var results = flattenComponentForDescription(
+ desc.components.children[i]
+ );
+ for (var jj = 0; jj < results.length; jj++) {
+ $descSpan.append(results[jj]);
+ }
}
- }
- $descSpan.attr("data-start", desc.start.toString());
- $descSpan.attr("data-end", desc.end.toString());
- $descDiv.append($descSpan);
+ $descSpan.attr("data-start", desc.start.toString());
+ $descSpan.attr("data-end", desc.end.toString());
+ $descDiv.append($descSpan);
- div.append($descDiv);
- };
+ div.append($descDiv);
+ };
- var addCaption = function (div, cap) {
- var $capSpan = $("", {
- class: "able-transcript-seekpoint able-transcript-caption",
- });
+ var addCaption = function (div, cap) {
+ var $capSpan = $("", {
+ class: "able-transcript-seekpoint able-transcript-caption",
+ });
- var flattenComponentForCaption = function (comp) {
- var result = [];
+ var flattenComponentForCaption = function (comp) {
+ var result = [];
- var parts = 0;
+ var parts = 0;
- var flattenString = function (str) {
- parts++;
+ var flattenString = function (str) {
+ parts++;
- var flatStr;
- var result = [];
- if (str === "") {
- return result;
- }
+ var flatStr;
+ var result = [];
+ if (str === "") {
+ return result;
+ }
- var openBracket = str.indexOf("[");
- var closeBracket = str.indexOf("]");
- var openParen = str.indexOf("(");
- var closeParen = str.indexOf(")");
+ var openBracket = str.indexOf("[");
+ var closeBracket = str.indexOf("]");
+ var openParen = str.indexOf("(");
+ var closeParen = str.indexOf(")");
- var hasBrackets = openBracket !== -1 && closeBracket !== -1;
- var hasParens = openParen !== -1 && closeParen !== -1;
+ var hasBrackets = openBracket !== -1 && closeBracket !== -1;
+ var hasParens = openParen !== -1 && closeParen !== -1;
- if (hasParens || hasBrackets) {
- if (parts > 1) {
- var silentSpanBreak = " ";
+ if (hasParens || hasBrackets) {
+ let silentSpanBreak;
+ if (parts > 1) {
+ // force a line break between sections that contain parens or brackets
+ silentSpanBreak = " ";
+ } else {
+ silentSpanBreak = "";
+ }
+ var silentSpanOpen =
+ silentSpanBreak + '';
+ var silentSpanClose = " ";
+ if (hasParens && hasBrackets) {
+ // string has both!
+ if (openBracket < openParen) {
+ // brackets come first. Parse parens separately
+ hasParens = false;
+ } else {
+ // parens come first. Parse brackets separately
+ hasBrackets = false;
+ }
+ }
+ }
+ if (hasParens) {
+ flatStr = str.substring(0, openParen);
+ flatStr += silentSpanOpen;
+ flatStr += str.substring(openParen, closeParen + 1);
+ flatStr += silentSpanClose;
+ flatStr += flattenString(str.substring(closeParen + 1));
+ result.push(flatStr);
+ } else if (hasBrackets) {
+ flatStr = str.substring(0, openBracket);
+ flatStr += silentSpanOpen;
+ flatStr += str.substring(openBracket, closeBracket + 1);
+ flatStr += silentSpanClose;
+ flatStr += flattenString(str.substring(closeBracket + 1));
+ result.push(flatStr);
} else {
- var silentSpanBreak = "";
+ result.push(str);
}
- var silentSpanOpen =
- silentSpanBreak + '';
- var silentSpanClose = " ";
- if (hasParens && hasBrackets) {
- if (openBracket < openParen) {
- hasParens = false;
- } else {
- hasBrackets = false;
+ return result;
+ };
+
+ if (comp.type === "string") {
+ result = result.concat(flattenString(comp.value));
+ } else if (comp.type === "v") {
+ var $vSpan = $("", {
+ class: "able-unspoken",
+ });
+ // don't display "title=" when rendering the voice tag title in the transcript
+ comp.value = comp.value.replace(/^title="|"$/g, "");
+ $vSpan.text("(" + comp.value + ")");
+ result.push($vSpan);
+ for (var i = 0; i < comp.children.length; i++) {
+ let subResults = flattenComponentForCaption(comp.children[i]);
+ for (let jj = 0; jj < subResults.length; jj++) {
+ result.push(subResults[jj]);
}
}
- }
- if (hasParens) {
- flatStr = str.substring(0, openParen);
- flatStr += silentSpanOpen;
- flatStr += str.substring(openParen, closeParen + 1);
- flatStr += silentSpanClose;
- flatStr += flattenString(str.substring(closeParen + 1));
- result.push(flatStr);
- } else if (hasBrackets) {
- flatStr = str.substring(0, openBracket);
- flatStr += silentSpanOpen;
- flatStr += str.substring(openBracket, closeBracket + 1);
- flatStr += silentSpanClose;
- flatStr += flattenString(str.substring(closeBracket + 1));
- result.push(flatStr);
+ } else if (comp.type === "b" || comp.type === "i") {
+ let $tag;
+ if (comp.type === "b") {
+ $tag = $("");
+ } else if (comp.type === "i") {
+ $tag = $("");
+ }
+ for (i = 0; i < comp.children.length; i++) {
+ let subResults = flattenComponentForCaption(comp.children[i]);
+ for (let jj = 0; jj < subResults.length; jj++) {
+ $tag.append(subResults[jj]);
+ }
+ }
+ if (comp.type === "b" || comp.type == "i") {
+ result.push($tag);
+ }
} else {
- result.push(str);
+ for (i = 0; i < comp.children.length; i++) {
+ result = result.concat(
+ flattenComponentForCaption(comp.children[i])
+ );
+ }
}
return result;
};
- if (comp.type === "string") {
- result = result.concat(flattenString(comp.value));
- } else if (comp.type === "v") {
- var $vSpan = $("", {
- class: "able-unspoken",
- });
- comp.value = comp.value.replace(/^title="|\"$/g, "");
- $vSpan.text("(" + comp.value + ")");
- result.push($vSpan);
- for (var i = 0; i < comp.children.length; i++) {
- var subResults = flattenComponentForCaption(comp.children[i]);
- for (var jj = 0; jj < subResults.length; jj++) {
- result.push(subResults[jj]);
- }
- }
- } else if (comp.type === "b" || comp.type === "i") {
- if (comp.type === "b") {
- var $tag = $("");
- } else if (comp.type === "i") {
- var $tag = $("");
- }
- for (var i = 0; i < comp.children.length; i++) {
- var subResults = flattenComponentForCaption(comp.children[i]);
- for (var jj = 0; jj < subResults.length; jj++) {
- $tag.append(subResults[jj]);
+ for (var i = 0; i < cap.components.children.length; i++) {
+ var next_child_tagname;
+ if ( i < cap.components.children.length - 1 ) {
+ next_child_tagname = cap.components.children[i + 1].tagName;
+ }
+ var results = flattenComponentForCaption(cap.components.children[i]);
+ for (var jj = 0; jj < results.length; jj++) {
+ var result = results[jj];
+ if (typeof result === "string") {
+ if (thisObj.lyricsMode) {
+ // add WITHIN each caption (if payload includes "\n")
+ result = result.replace(/\n/g,' ');
+
+ // add BETWEEN each caption, but do not consider sibling style tags within this caption as the next caption!
+ if ( !next_child_tagname || ( next_child_tagname !== 'i' && next_child_tagname !== 'b' ) ) {
+ result += ' ';
+ }
+ } else {
+ // just add a space between captions
+ result += " ";
+ }
}
- }
- if (comp.type === "b" || comp.type == "i") {
- result.push($tag);
- }
- } else {
- for (var i = 0; i < comp.children.length; i++) {
- result = result.concat(
- flattenComponentForCaption(comp.children[i])
- );
+ $capSpan.append(result);
}
}
- return result;
+ $capSpan.attr("data-start", cap.start.toString());
+ $capSpan.attr("data-end", cap.end.toString());
+ div.append($capSpan);
+ div.append(" \n");
};
- for (var i = 0; i < cap.components.children.length; i++) {
- var next_child_tagname;
- if ( i < cap.components.children.length - 1 ) {
- next_child_tagname = cap.components.children[i + 1].tagName;
- }
- var results = flattenComponentForCaption(cap.components.children[i]);
- for (var jj = 0; jj < results.length; jj++) {
- var result = results[jj];
- if (typeof result === "string") {
- if (thisObj.lyricsMode) {
- result = result.replace(/\n/g,' ');
-
- if ( !next_child_tagname || ( next_child_tagname !== 'i' && next_child_tagname !== 'b' ) ) {
- result += ' ';
- }
- } else {
- result += " ";
- }
- }
- $capSpan.append(result);
- }
- }
- $capSpan.attr("data-start", cap.start.toString());
- $capSpan.attr("data-end", cap.end.toString());
- div.append($capSpan);
- div.append(" \n");
- };
-
- while (
- nextChapter < chapters.length ||
- nextDesc < descriptions.length ||
- nextCap < captions.length
- ) {
- if (
- nextChapter < chapters.length &&
- nextDesc < descriptions.length &&
+ // keep looping as long as any one of the three arrays has content
+ while (
+ nextChapter < chapters.length ||
+ nextDesc < descriptions.length ||
nextCap < captions.length
) {
- var firstStart = Math.min(
- chapters[nextChapter].start,
- descriptions[nextDesc].start,
- captions[nextCap].start
- );
- } else if (
- nextChapter < chapters.length &&
- nextDesc < descriptions.length
- ) {
- var firstStart = Math.min(
- chapters[nextChapter].start,
- descriptions[nextDesc].start
- );
- } else if (nextChapter < chapters.length && nextCap < captions.length) {
- var firstStart = Math.min(
- chapters[nextChapter].start,
- captions[nextCap].start
- );
- } else if (nextDesc < descriptions.length && nextCap < captions.length) {
- var firstStart = Math.min(
- descriptions[nextDesc].start,
- captions[nextCap].start
- );
- } else {
- var firstStart = null;
- }
- if (firstStart !== null) {
if (
- typeof chapters[nextChapter] !== "undefined" &&
- chapters[nextChapter].start === firstStart
+ nextChapter < chapters.length &&
+ nextDesc < descriptions.length &&
+ nextCap < captions.length
) {
- addChapter($main, chapters[nextChapter]);
- nextChapter += 1;
+ // they all three have content
+ firstStart = Math.min(
+ chapters[nextChapter].start,
+ descriptions[nextDesc].start,
+ captions[nextCap].start
+ );
} else if (
- typeof descriptions[nextDesc] !== "undefined" &&
- descriptions[nextDesc].start === firstStart
+ nextChapter < chapters.length &&
+ nextDesc < descriptions.length
) {
- addDescription($main, descriptions[nextDesc]);
- nextDesc += 1;
+ // chapters & descriptions have content
+ firstStart = Math.min(
+ chapters[nextChapter].start,
+ descriptions[nextDesc].start
+ );
+ } else if (nextChapter < chapters.length && nextCap < captions.length) {
+ // chapters & captions have content
+ firstStart = Math.min(
+ chapters[nextChapter].start,
+ captions[nextCap].start
+ );
+ } else if (nextDesc < descriptions.length && nextCap < captions.length) {
+ // descriptions & captions have content
+ firstStart = Math.min(
+ descriptions[nextDesc].start,
+ captions[nextCap].start
+ );
} else {
- addCaption($main, captions[nextCap]);
- nextCap += 1;
+ firstStart = null;
}
- } else {
- if (nextChapter < chapters.length) {
- addChapter($main, chapters[nextChapter]);
- nextChapter += 1;
- } else if (nextDesc < descriptions.length) {
- addDescription($main, descriptions[nextDesc]);
- nextDesc += 1;
- } else if (nextCap < captions.length) {
- addCaption($main, captions[nextCap]);
- nextCap += 1;
+ if (firstStart !== null) {
+ if (
+ typeof chapters[nextChapter] !== "undefined" &&
+ chapters[nextChapter].start === firstStart
+ ) {
+ addChapter($main, chapters[nextChapter]);
+ nextChapter += 1;
+ } else if (
+ typeof descriptions[nextDesc] !== "undefined" &&
+ descriptions[nextDesc].start === firstStart
+ ) {
+ addDescription($main, descriptions[nextDesc]);
+ nextDesc += 1;
+ } else {
+ addCaption($main, captions[nextCap]);
+ nextCap += 1;
+ }
+ } else {
+ if (nextChapter < chapters.length) {
+ addChapter($main, chapters[nextChapter]);
+ nextChapter += 1;
+ } else if (nextDesc < descriptions.length) {
+ addDescription($main, descriptions[nextDesc]);
+ nextDesc += 1;
+ } else if (nextCap < captions.length) {
+ addCaption($main, captions[nextCap]);
+ nextCap += 1;
+ }
}
}
- }
- var $components = $main.children();
- var spanCount = 0;
- $components.each(function () {
- if ($(this).hasClass("able-transcript-caption")) {
- if (
- $(this).text().indexOf("[") !== -1 ||
- $(this).text().indexOf("(") !== -1
- ) {
+ // organize transcript into blocks using [] and () as starting points
+ var $components = $main.children();
+ var spanCount = 0;
+ $components.each(function () {
+ if ($(this).hasClass("able-transcript-caption")) {
+ if (
+ $(this).text().indexOf("[") !== -1 ||
+ $(this).text().indexOf("(") !== -1
+ ) {
+ // this caption includes a bracket or parenth. Start a new block
+ // close the previous block first
+ if (spanCount > 0) {
+ $main = wrapTranscriptBlocks( $main );
+ spanCount = 0;
+ }
+ }
+ $(this).addClass("able-block-temp");
+ spanCount++;
+ } else {
+ // this is not a caption. Close the caption block
if (spanCount > 0) {
$main = wrapTranscriptBlocks( $main );
spanCount = 0;
}
}
- $(this).addClass("able-block-temp");
- spanCount++;
- } else {
- if (spanCount > 0) {
- $main = wrapTranscriptBlocks( $main );
- spanCount = 0;
- }
- }
- });
- $main = wrapTranscriptBlocks( $main );
+ });
+ // Close out remaining temp blocks.
+ $main = wrapTranscriptBlocks( $main );
- return $main;
- };
+ return $main;
+ };
- var wrapTranscriptBlocks = function( $main ) {
- $main.find(".able-block-temp")
- .removeClass("able-block-temp")
- .wrapAll('
');
+ var wrapTranscriptBlocks = function( $main ) {
+ $main.find(".able-block-temp")
+ .removeClass("able-block-temp")
+ .wrapAll('
');
- return $main;
+ return $main;
+ };
}
-})(jQuery);
-
-(function ($) {
- AblePlayer.prototype.showSearchResults = function () {
-
-
- var thisObj = this;
- if (this.searchDiv && this.searchString) {
- var cleanSearchString = DOMPurify.sanitize(this.searchString);
- if ($("#" + this.SearchDiv)) {
- var searchStringHtml = "" + this.translate( 'resultsSummary1', 'You searched for:') + ' ';
- searchStringHtml +=
- '' + cleanSearchString + " ";
- searchStringHtml += "
";
- var resultsArray = this.searchFor(
- cleanSearchString,
- this.searchIgnoreCaps
- );
- if (resultsArray.length > 0) {
- var $resultsSummary = $("", {
- class: "able-search-results-summary",
- });
- var resultsSummaryText = this.translate( 'resultsSummary2', 'Found %1 matching items.', [ '' + resultsArray.length + ' ' ] );
- resultsSummaryText += ' ' + this.translate( 'resultsSummary3', 'Click the time associated with any item to play the video from that point.' );
- $resultsSummary.html( resultsSummaryText );
- var $resultsList = $("
");
- for (var i = 0; i < resultsArray.length; i++) {
- var resultId = "aria-search-result-" + i;
- var $resultsItem = $("", {});
- var itemStartTime = this.secondsToTime(resultsArray[i]["start"]);
- var itemLabel =
- this.translate( 'searchButtonLabel', 'Play at %1', [ itemStartTime["title"] ] );
- var itemStartSpan = $("", {
- class: "able-search-results-time",
- "data-start": resultsArray[i]["start"],
- title: itemLabel,
- "aria-label": itemLabel,
- "aria-describedby": resultId,
- });
- itemStartSpan.text(itemStartTime["value"]);
- itemStartSpan.on("click", function (e) {
- thisObj.seekTrigger = "search";
- var spanStart = parseFloat($(this).attr("data-start"));
- spanStart += 0.01;
- thisObj.seeking = true;
- thisObj.seekTo(spanStart);
- });
- var itemText = $("", {
- class: "able-search-result-text",
- id: resultId,
- });
- itemText.html('...' + resultsArray[i]["caption"] + '...');
- $resultsItem.append(itemStartSpan, itemText);
- $resultsList.append($resultsItem);
- }
- $('#' + this.searchDiv)
- .html(searchStringHtml)
- .append($resultsSummary, $resultsList);
- } else {
- var noResults = $('').text( this.translate( 'noResultsFound', 'No results found.' ) );
- $('#' + this.searchDiv)
- .html(searchStringHtml)
- .append(noResults);
- }
- }
- }
+ var playerHeading$k = "Reproductor";
+ var audioPlayer$k = "Reproductor d'àudio";
+ var videoPlayer$k = "Reproductor de vídeo";
+ var faster$k = "Ràpid";
+ var slower$k = "Lent";
+ var play$k = "Reprodueix";
+ var pause$k = "Pausa";
+ var restart$k = "Reinicia";
+ var prevTrack$k = "Pista anterior";
+ var nextTrack$k = "Pista següent";
+ var rewind$k = "Endarrere";
+ var forward$k = "Endavant";
+ var captions$k = "Subtítols";
+ var showCaptions$k = "Mostra els subtítols";
+ var hideCaptions$k = "Oculta els subtítols";
+ var captionsOff$k = "Desactiva els subtítols";
+ var showTranscript$k = "Mostra la transcripció";
+ var hideTranscript$k = "Oculta la transcripció";
+ var turnOnDescriptions$k = "Activa l'audiodescripció";
+ var turnOffDescriptions$k = "Desactiva l'audiodescripció";
+ var chapters$k = "Capítols";
+ var language$k = "Idioma";
+ var sign$k = "Llengua de signes";
+ var showSign$k = "Mostra la llengua de signes";
+ var hideSign$k = "Oculta la llengua de signes";
+ var seekbarLabel$k = "Línia de temps";
+ var mute$k = "Silencia";
+ var unmute$k = "Activa el so";
+ var volume$k = "Volum";
+ var volumeUpDown$k = "Apuja i abaixa el volum";
+ var preferences$k = "Preferències";
+ var enterFullScreen$k = "Entra en el mode de pantalla completa";
+ var exitFullScreen$k = "Surt del mode de pantalla completa";
+ var speed$k = "Velocitat";
+ var spacebar$k = "Barra espaiadora";
+ var transcriptTitle$k = "Transcripció";
+ var lyricsTitle$k = "Lletra";
+ var autoScroll$k = "Desplaçament automàtic";
+ var statusPlaying$k = "S'està reproduint";
+ var statusPaused$k = "En pausa";
+ var statusStopped$k = "Aturat";
+ var statusBuffering$k = "Emmagatzemant";
+ var statusEnd$k = "Fi de pista";
+ var selectedTrack$j = "Pista seleccionada";
+ var alertDescribedVersion$j = "S'està utilitzant la versió amb audiodescripció del vídeo";
+ var alertNonDescribedVersion$j = "S'està utilitzant la versió sense audiodescripció del vídeo";
+ var prefMenuCaptions$k = "Subtítols";
+ var prefVoicedCaptions$k = "Spoken Captions";
+ var prefMenuDescriptions$k = "Descripcions";
+ var prefMenuKeyboard$k = "Teclat";
+ var prefMenuTranscript$k = "Transcripció";
+ var prefTitleCaptions$k = "Preferències dels subtítols";
+ var prefTitleDescriptions$k = "Preferències de l'audiodescripció";
+ var prefTitleKeyboard$k = "Preferències del teclat";
+ var prefTitleTranscript$j = "Preferències de la transcripció";
+ var prefIntroDescription1$j = "Aquest reproductor suporta l'audiodescripció de dues maneres: ";
+ var prefDescription1$k = "L'actual vídeo té una versió alternativa amb audiodescripció, descripció textual anunciada pel lector de pantalla.";
+ var prefDescription2$k = "L'actual vídeo té una versió alternativa amb audiodescripció.";
+ var prefDescription3$k = "L'actual vídeo té descripció textual.";
+ var prefIntroDescriptionNone$k = "L'actual vídeo no disposa d'audiodescripció en cap format.";
+ var prefIntroDescription3$k = "Utilitzeu el formulari següent per definir les preferències relacionades amb l'audiodescripció textual.";
+ var prefIntroDescription4$k = "Desprès de desar la configuració, podeu commutar l'ús de l'audiodescripció amb el mateix botó.";
+ var prefIntroKeyboard1$k = "Aquest reproductor pot ser utilitzat des de qualsevol lloc de la pàgina utilitzant les dreceres de teclat (vegeu la llista a continuació).";
+ var prefIntroKeyboard2$k = "A continuació, podeu asignar les tecles modificadores (Majúscules, Alt, i la tecla d'inserció).";
+ var prefIntroKeyboard3$k = "NOTA: algunes combinacions de tecles poden entrar en conflicte amb les utilitzades pel navegador o altres aplicacions. Proveu diferents combinacions o tecles modificadores fins a trobar les adequades en cada cas.";
+ var prefHeadingKeyboard1$k = "Tecles modificadores emprades com a dreceres de teclat";
+ var prefHeadingKeyboard2$k = "Dreceres de teclat actuals";
+ var prefHeadingDescription$k = "Audiodescripció";
+ var prefHeadingTextDescription$k = "Audiodescripció textual";
+ var prefAltKey$k = "Alt";
+ var prefCtrlKey$k = "Control";
+ var prefShiftKey$k = "Majúscula";
+ var prefNoKeyShortcuts$k = "Desactiva les dreceres de teclat";
+ var escapeKey$k = "Escapada";
+ var escapeKeyFunction$k = "Tanca el diàleg o finestre emergent actual";
+ var prefDescPause$k = "Pausa automàticament el vídeo en el moment que comenci una audiodescripció";
+ var prefDescVisible$k = "Fes visible la audiodescripció textual si es troba activada";
+ var prefDescVoice$k = "Veu";
+ var prefDescRate$k = "Spoken Description Rate";
+ var prefCaptionRate$k = "Spoken Caption Rate";
+ var prefDescPitch$k = "Tonalitat";
+ var prefDescPitch1$k = "Molt baixa";
+ var prefDescPitch2$k = "Baixa";
+ var prefDescPitch3$k = "Per defecte";
+ var prefDescPitch4$k = "Alta";
+ var prefDescPitch5$k = "Molt alta";
+ var sampleDescriptionText$k = "Ajusta la configuració per escoltar aquest text de mostra.";
+ var prefHighlight$k = "Ressalta la transcripció a mesura que avança el contingut";
+ var prefTabbable$k = "Transcripció operable per teclat";
+ var prefCaptionsFont$k = "Tipus de lletra";
+ var prefCaptionsColor$k = "Color del text";
+ var prefCaptionsBGColor$k = "Fons";
+ var prefCaptionsSize$k = "Mida del text";
+ var prefCaptionsOpacity$k = "Opacitat";
+ var prefCaptionsStyle$k = "Estil";
+ var serif$k = "Serifa";
+ var sans$k = "Sensa serifa";
+ var cursive$k = "Cursiva";
+ var fantasy$k = "fantasia";
+ var monospace$k = "Monoespaiada";
+ var white$k = "Blanc";
+ var yellow$k = "Groc";
+ var green$k = "Verd";
+ var cyan$j = "Cian";
+ var blue$k = "Blau";
+ var magenta$k = "Magenta";
+ var red$k = "Vermell";
+ var black$k = "Negre";
+ var transparent$k = "transparent";
+ var solid$k = "Sòlid";
+ var captionsStylePopOn$k = "Aparició instantània";
+ var captionsStyleRollUp$k = "Desplaçament cap amunt";
+ var prefCaptionsPosition$k = "Posició";
+ var captionsPositionOverlay$k = "Superposició";
+ var captionsPositionBelow$k = "A continuació del vídeo";
+ var sampleCaptionText$k = "Text de mostra dels subtítols";
+ var prefSuccess$k = "S'han desat els canvis.";
+ var prefNoChange$k = "No s'ha fet cap canvi.";
+ var save$k = "Desa";
+ var cancel$k = "Cancel·la";
+ var dismissButton$k = "Ignora";
+ var windowButtonLabel$k = "Opcions de la finestra";
+ var windowMove$k = "Moure";
+ var windowMoveLeft$k = "Finestra desplaçada cap a l'esquerra";
+ var windowMoveRight$k = "Finestra desplaçada cap a la dreta";
+ var windowMoveUp$k = "Finestra desplaçada cap amunt";
+ var windowMoveDown$k = "Finestra desplaçada cap avall";
+ var windowMoveStopped$k = "S'ha aturat el desplaçament de la finestra";
+ var transcriptControls$k = "Controls de la finestra de transcripció";
+ var signControls$k = "Controls de la finestra de llengua de signes";
+ var windowMoveAlert$k = "Arrossegueu o feu servir les tecles de direcció per moure la finestra, polseu retorn per aturar.";
+ var windowResize$k = "Redimensiona";
+ var windowResizeHeading$k = "Redimensiona la finestra amb l'intèrpret";
+ var closeButtonLabel$k = "Tanca";
+ var width$k = "Amplada";
+ var height$k = "Alçada";
+ var resultsSummary1$k = "Heu cercat:";
+ var resultsSummary2$k = "S'han trobat %1 elements coincidents.";
+ var resultsSummary3$k = "Feu clic al moment associat a qualsevol element per reproduir el vídeo des d'aquell punt.";
+ var noResultsFound$k = "No s'han trobat resultats.";
+ var searchButtonLabel$k = "Reprodueix a %1";
+ var hour$k = "hora";
+ var minute$j = "minut";
+ var second$k = "segon";
+ var hours$k = "hores";
+ var minutes$k = "minuts";
+ var seconds$k = "segons";
+ var vtsHeading$k = "Gestor de transcripcions de vídeo";
+ var vtsInstructions1$k = "Utilitzeu el gestor de transcripcions de vídeo per modificar les pistes de text:";
+ var vtsInstructions2$k = "Reordeneu capítols, descripcions, subtítols o subtítols per a persones sordes perquè apareguin en la seqüència correcta a la transcripció generada automàticament per Able Player.";
+ var vtsInstructions3$k = "Modifiqueu el contingut o els temps d'inici i final (tots són editables directament a la taula).";
+ var vtsInstructions4$k = "Afegiu contingut nou, com ara capítols o descripcions.";
+ var vtsInstructions5$k = "Després d'editar, feu clic al botó \"Desa els canvis\" per generar contingut nou per a tots els fitxers de text temporitzat rellevants. El text nou es pot copiar i enganxar en fitxers WebVTT nous.";
+ var vtsSelectLanguage$k = "Seleccioneu una llengua";
+ var vtsSave$k = "Genera contingut .vtt nou";
+ var vtsReturn$k = "Torna a l'editor";
+ var vtsCancel$k = "S'ha cancel·lat el desament. Totes les edicions que heu fet s'han restaurat a la taula del GTV.";
+ var vtsRow$k = "Fila";
+ var vtsKind$k = "Tipus";
+ var vtsStart$k = "Inici";
+ var vtsEnd$k = "Final";
+ var vtsContent$k = "Contingut";
+ var vtsActions$k = "Accions";
+ var vtsNewRow$k = "S'ha inserit una fila nova %1.";
+ var vtsDeletedRow$k = "S'ha suprimit la fila %1.";
+ var vtsMovedRow$k = "La fila %1 s'ha mogut %2 i ara és la fila %3.";
+ var ca = {
+ playerHeading: playerHeading$k,
+ audioPlayer: audioPlayer$k,
+ videoPlayer: videoPlayer$k,
+ faster: faster$k,
+ slower: slower$k,
+ play: play$k,
+ pause: pause$k,
+ restart: restart$k,
+ prevTrack: prevTrack$k,
+ nextTrack: nextTrack$k,
+ rewind: rewind$k,
+ forward: forward$k,
+ captions: captions$k,
+ showCaptions: showCaptions$k,
+ hideCaptions: hideCaptions$k,
+ captionsOff: captionsOff$k,
+ showTranscript: showTranscript$k,
+ hideTranscript: hideTranscript$k,
+ turnOnDescriptions: turnOnDescriptions$k,
+ turnOffDescriptions: turnOffDescriptions$k,
+ chapters: chapters$k,
+ language: language$k,
+ sign: sign$k,
+ showSign: showSign$k,
+ hideSign: hideSign$k,
+ seekbarLabel: seekbarLabel$k,
+ mute: mute$k,
+ unmute: unmute$k,
+ volume: volume$k,
+ volumeUpDown: volumeUpDown$k,
+ preferences: preferences$k,
+ enterFullScreen: enterFullScreen$k,
+ exitFullScreen: exitFullScreen$k,
+ speed: speed$k,
+ spacebar: spacebar$k,
+ transcriptTitle: transcriptTitle$k,
+ lyricsTitle: lyricsTitle$k,
+ autoScroll: autoScroll$k,
+ statusPlaying: statusPlaying$k,
+ statusPaused: statusPaused$k,
+ statusStopped: statusStopped$k,
+ statusBuffering: statusBuffering$k,
+ statusEnd: statusEnd$k,
+ selectedTrack: selectedTrack$j,
+ alertDescribedVersion: alertDescribedVersion$j,
+ alertNonDescribedVersion: alertNonDescribedVersion$j,
+ prefMenuCaptions: prefMenuCaptions$k,
+ prefVoicedCaptions: prefVoicedCaptions$k,
+ prefMenuDescriptions: prefMenuDescriptions$k,
+ prefMenuKeyboard: prefMenuKeyboard$k,
+ prefMenuTranscript: prefMenuTranscript$k,
+ prefTitleCaptions: prefTitleCaptions$k,
+ prefTitleDescriptions: prefTitleDescriptions$k,
+ prefTitleKeyboard: prefTitleKeyboard$k,
+ prefTitleTranscript: prefTitleTranscript$j,
+ prefIntroDescription1: prefIntroDescription1$j,
+ prefDescription1: prefDescription1$k,
+ prefDescription2: prefDescription2$k,
+ prefDescription3: prefDescription3$k,
+ prefIntroDescriptionNone: prefIntroDescriptionNone$k,
+ prefIntroDescription3: prefIntroDescription3$k,
+ prefIntroDescription4: prefIntroDescription4$k,
+ prefIntroKeyboard1: prefIntroKeyboard1$k,
+ prefIntroKeyboard2: prefIntroKeyboard2$k,
+ prefIntroKeyboard3: prefIntroKeyboard3$k,
+ prefHeadingKeyboard1: prefHeadingKeyboard1$k,
+ prefHeadingKeyboard2: prefHeadingKeyboard2$k,
+ prefHeadingDescription: prefHeadingDescription$k,
+ prefHeadingTextDescription: prefHeadingTextDescription$k,
+ prefAltKey: prefAltKey$k,
+ prefCtrlKey: prefCtrlKey$k,
+ prefShiftKey: prefShiftKey$k,
+ prefNoKeyShortcuts: prefNoKeyShortcuts$k,
+ escapeKey: escapeKey$k,
+ escapeKeyFunction: escapeKeyFunction$k,
+ prefDescPause: prefDescPause$k,
+ prefDescVisible: prefDescVisible$k,
+ prefDescVoice: prefDescVoice$k,
+ prefDescRate: prefDescRate$k,
+ prefCaptionRate: prefCaptionRate$k,
+ prefDescPitch: prefDescPitch$k,
+ prefDescPitch1: prefDescPitch1$k,
+ prefDescPitch2: prefDescPitch2$k,
+ prefDescPitch3: prefDescPitch3$k,
+ prefDescPitch4: prefDescPitch4$k,
+ prefDescPitch5: prefDescPitch5$k,
+ sampleDescriptionText: sampleDescriptionText$k,
+ prefHighlight: prefHighlight$k,
+ prefTabbable: prefTabbable$k,
+ prefCaptionsFont: prefCaptionsFont$k,
+ prefCaptionsColor: prefCaptionsColor$k,
+ prefCaptionsBGColor: prefCaptionsBGColor$k,
+ prefCaptionsSize: prefCaptionsSize$k,
+ prefCaptionsOpacity: prefCaptionsOpacity$k,
+ prefCaptionsStyle: prefCaptionsStyle$k,
+ serif: serif$k,
+ sans: sans$k,
+ cursive: cursive$k,
+ fantasy: fantasy$k,
+ monospace: monospace$k,
+ white: white$k,
+ yellow: yellow$k,
+ green: green$k,
+ cyan: cyan$j,
+ blue: blue$k,
+ magenta: magenta$k,
+ red: red$k,
+ black: black$k,
+ transparent: transparent$k,
+ solid: solid$k,
+ captionsStylePopOn: captionsStylePopOn$k,
+ captionsStyleRollUp: captionsStyleRollUp$k,
+ prefCaptionsPosition: prefCaptionsPosition$k,
+ captionsPositionOverlay: captionsPositionOverlay$k,
+ captionsPositionBelow: captionsPositionBelow$k,
+ sampleCaptionText: sampleCaptionText$k,
+ prefSuccess: prefSuccess$k,
+ prefNoChange: prefNoChange$k,
+ save: save$k,
+ cancel: cancel$k,
+ dismissButton: dismissButton$k,
+ windowButtonLabel: windowButtonLabel$k,
+ windowMove: windowMove$k,
+ windowMoveLeft: windowMoveLeft$k,
+ windowMoveRight: windowMoveRight$k,
+ windowMoveUp: windowMoveUp$k,
+ windowMoveDown: windowMoveDown$k,
+ windowMoveStopped: windowMoveStopped$k,
+ transcriptControls: transcriptControls$k,
+ signControls: signControls$k,
+ windowMoveAlert: windowMoveAlert$k,
+ windowResize: windowResize$k,
+ windowResizeHeading: windowResizeHeading$k,
+ closeButtonLabel: closeButtonLabel$k,
+ width: width$k,
+ height: height$k,
+ resultsSummary1: resultsSummary1$k,
+ resultsSummary2: resultsSummary2$k,
+ resultsSummary3: resultsSummary3$k,
+ noResultsFound: noResultsFound$k,
+ searchButtonLabel: searchButtonLabel$k,
+ hour: hour$k,
+ minute: minute$j,
+ second: second$k,
+ hours: hours$k,
+ minutes: minutes$k,
+ seconds: seconds$k,
+ vtsHeading: vtsHeading$k,
+ vtsInstructions1: vtsInstructions1$k,
+ vtsInstructions2: vtsInstructions2$k,
+ vtsInstructions3: vtsInstructions3$k,
+ vtsInstructions4: vtsInstructions4$k,
+ vtsInstructions5: vtsInstructions5$k,
+ vtsSelectLanguage: vtsSelectLanguage$k,
+ vtsSave: vtsSave$k,
+ vtsReturn: vtsReturn$k,
+ vtsCancel: vtsCancel$k,
+ vtsRow: vtsRow$k,
+ vtsKind: vtsKind$k,
+ vtsStart: vtsStart$k,
+ vtsEnd: vtsEnd$k,
+ vtsContent: vtsContent$k,
+ vtsActions: vtsActions$k,
+ vtsNewRow: vtsNewRow$k,
+ vtsDeletedRow: vtsDeletedRow$k,
+ vtsMovedRow: vtsMovedRow$k
};
- AblePlayer.prototype.searchFor = function (searchString, ignoreCaps) {
- var captionLang, captions, results, caption, c, i, j;
- results = [];
- var searchTerms = searchString.split(" ");
- if (this.captions.length > 0) {
- for (i = 0; i < this.captions.length; i++) {
- if (this.captions[i].language === this.searchLang) {
- captionLang = this.searchLang;
- captions = this.captions[i].cues;
- }
- }
- if (captions.length > 0) {
- c = 0;
- for (i = 0; i < captions.length; i++) {
- if (
- $.inArray(captions[i].components.children[0]["type"], [
- "string",
- "i",
- "b",
- "u",
- "v",
- "c",
- ]) !== -1
- ) {
- caption = this.flattenCueForCaption(captions[i]);
- var captionNormalized = ignoreCaps
- ? caption.toLowerCase()
- : caption;
- for (j = 0; j < searchTerms.length; j++) {
- var searchTermNormalized = ignoreCaps
- ? searchTerms[j].toLowerCase()
- : searchTerms[j];
- if (captionNormalized.indexOf(searchTermNormalized) !== -1) {
- results[c] = [];
- results[c]["start"] = captions[i].start;
- results[c]["lang"] = captionLang;
- results[c]["caption"] = this.highlightSearchTerm(
- searchTerms,
- caption
- );
- c++;
- break;
- }
- }
- }
- }
- }
- }
- return results;
+ var playerHeading$j = "Přehrávač médií";
+ var audioPlayer$j = "Audio player";
+ var videoPlayer$j = "Video player";
+ var faster$j = "Rychleji";
+ var slower$j = "Pomaleji";
+ var play$j = "Spustit";
+ var pause$j = "Pauza";
+ var restart$j = "Přehrát od začátku";
+ var prevTrack$j = "Předchozí stopa";
+ var nextTrack$j = "Další stopa";
+ var rewind$j = "Přetočit vzad";
+ var forward$j = "Přetočit vpřed";
+ var captions$j = "Titulky";
+ var showCaptions$j = "Zobrazit titulky";
+ var hideCaptions$j = "Skrýt titulky";
+ var captionsOff$j = "Titulky vypnuty";
+ var showTranscript$j = "Zobrazit přepis";
+ var hideTranscript$j = "Skrýt přepis";
+ var turnOnDescriptions$j = "Zapnout popisy";
+ var turnOffDescriptions$j = "vypnout popisy";
+ var chapters$j = "Kapitoly";
+ var language$j = "Jazyk";
+ var sign$j = "Znaková řeč";
+ var showSign$j = "Zobrazit znakovou řeč";
+ var hideSign$j = "Skrýt znakovou řeč";
+ var seekbarLabel$j = "časová osa";
+ var mute$j = "Vypnout zvuk";
+ var unmute$j = "Zapnout zvuk";
+ var volume$j = "Hlasitost";
+ var volumeUpDown$j = "Hlasitost zvýšit snížit";
+ var preferences$j = "Předvolby";
+ var enterFullScreen$j = "Zobrazit na celou obrazovku";
+ var exitFullScreen$j = "Ukončit celou obrazovku";
+ var speed$j = "Rychlost";
+ var spacebar$j = "mezerník";
+ var transcriptTitle$j = "Přepis";
+ var lyricsTitle$j = "Text";
+ var autoScroll$j = "Automatické posouvání";
+ var statusPlaying$j = "Přehrávání";
+ var statusPaused$j = "Pozastaveno";
+ var statusStopped$j = "Zastaveno";
+ var statusBuffering$j = "Vyrovnávací paměť";
+ var statusEnd$j = "Konec stopy";
+ var selectedTrack$i = "Vybraná stopa";
+ var alertDescribVersion = "Používání zvukově popsané verze tohoto videa";
+ var alertNonDescribVersion = "Použití nepopsané verze tohoto videa";
+ var prefMenuCaptions$j = "Titulky";
+ var prefVoicedCaptions$j = "Spoken Captions";
+ var prefMenuDescriptions$j = "Popisy";
+ var prefMenuKeyboard$j = "Klávesnice";
+ var prefMenuTranscript$j = "Přepis";
+ var prefTitleCaptions$j = "Předvolby titulků";
+ var prefTitleDescriptions$j = "Předvolby zvukového popisu";
+ var prefTitleKeyboard$j = "Předvolby klávesnice";
+ var prefTitleTranscript$i = "Předvolby přepisu";
+ var prefIntroDescription1$i = "Tento přehrávač médií podporuje zvukový popis dvěma způsoby:";
+ var prefDescription1$j = "Aktuální video má alternativně popsaná verze, textový popis.";
+ var prefDescription2$j = "Aktuální video má alternativní popsaná verze videa.";
+ var prefDescription3$j = "Aktuální video má textový popis, oznámený čtečkou obrazovky.";
+ var prefIntroDescriptionNone$j = "Aktuální video nemá žádný zvukový popis v žádném formátu.";
+ var prefIntroDescription3$j = "Pomocí následujícího formuláře můžete nastavit předvolby týkající se textového zvukového popisu.";
+ var prefIntroDescription4$j = "Po uložení nastavení lze zvukový popis zapnout / vypnout pomocí tlačítka Popis.";
+ var prefIntroKeyboard1$j = "Přehrávač médií na této webové stránce lze ovládat odkudkoli na stránce pomocí klávesových zkratek (seznam níže).";
+ var prefIntroKeyboard2$j = "Níže lze přiřadit modifikační klávesy (Shift, Alt a Control).";
+ var prefIntroKeyboard3$j = "POZNÁMKA: Některé kombinace kláves mohou být v konfliktu s klávesami používanými vaším prohlížečem nebo jinými softwarovými aplikacemi. Zkuste najít různé kombinace modifikačních kláves, které vám vyhovují.";
+ var prefHeadingKeyboard1$j = "Modifikační klávesy používané pro zástupce";
+ var prefHeadingKeyboard2$j = "Aktuální klávesové zkratky";
+ var prefHeadingDescription$j = "Zvukový popis";
+ var prefHeadingTextDescription$j = "Textový zvukový popis";
+ var prefAltKey$j = "Alt";
+ var prefCtrlKey$j = "Control";
+ var prefShiftKey$j = "Shift";
+ var prefNoKeyShortcuts$j = "Disable keyboard shortcuts";
+ var escapeKey$j = "Escape";
+ var escapeKeyFunction$j = "Zavřít aktuální dialogové okno nebo vyskakovací nabídku";
+ var prefDescPause$j = "Automaticky pozastavit video při spuštění popisu";
+ var prefDescVisible$j = "Zviditelnit popis";
+ var prefDescVoice$j = "Voice";
+ var prefDescRate$j = "Spoken Description Rate";
+ var prefCaptionRate$j = "Spoken Caption Rate";
+ var prefDescPitch$j = "Pitch";
+ var prefDescPitch1$j = "Very low";
+ var prefDescPitch2$j = "Low";
+ var prefDescPitch3$j = "Default";
+ var prefDescPitch4$j = "High";
+ var prefDescPitch5$j = "Very high";
+ var sampleDescriptionText$j = "Adjust settings to hear this sample text.";
+ var prefHighlight$j = "Zvýraznit přepis při přehrávání médií";
+ var prefTabbable$j = "Přepis umožňující klávesnici";
+ var prefCaptionsFont$j = "Písmo";
+ var prefCaptionsColor$j = "Barva textu";
+ var prefCaptionsBGColor$j = "Pozadí";
+ var prefCaptionsSize$j = "Velikost písma";
+ var prefCaptionsOpacity$j = "Neprůhlednost";
+ var prefCaptionsStyle$j = "Styl";
+ var serif$j = "patkové";
+ var sans$j = "bezpatkové";
+ var cursive$j = "kurzíva";
+ var fantasy$j = "fantasy";
+ var monospace$j = "jednoprostorový";
+ var white$j = "bílá";
+ var yellow$j = "žlutá";
+ var green$j = "zelená";
+ var cyan$i = "azurová";
+ var blue$j = "modrá";
+ var magenta$j = "purpurová";
+ var red$j = "červená";
+ var black$j = "černá";
+ var transparent$j = "transparentní";
+ var solid$j = "jednolitý";
+ var captionsStylePopOn$j = "Vyskakovat";
+ var captionsStyleRollUp$j = "Srolovat";
+ var prefCaptionsPosition$j = "Pozice";
+ var captionsPositionOverlay$j = "Překrytí";
+ var captionsPositionBelow$j = "Níže video";
+ var sampleCaptionText$j = "Ukázkový text titulku";
+ var prefSuccess$j = "Vaše změny byly uloženy.";
+ var prefNoChange$j = "Neprovedli jste žádné změny.";
+ var save$j = "Uložit";
+ var cancel$j = "Zrušit";
+ var dismissButton$j = "Dismiss";
+ var windowButtonLabel$j = "Možnosti okna";
+ var windowMove$j = "Přesunout";
+ var windowMoveLeft$j = "Window moved left";
+ var windowMoveRight$j = "Window moved right";
+ var windowMoveUp$j = "Window moved up";
+ var windowMoveDown$j = "Window moved down";
+ var windowMoveStopped$j = "Window move stopped";
+ var transcriptControls$j = "Transcript Window Controls";
+ var signControls$j = "Sign Language Window Controls";
+ var windowMoveAlert$j = "Přetažením nebo použitím kláves se šipkami přesuňte okno; klávesou Enter zastavíte";
+ var windowResize$j = "Změnit velikost";
+ var windowResizeHeading$j = "Změnit velikost okna";
+ var closeButtonLabel$j = "Zavřít";
+ var width$j = "Šířka";
+ var height$j = "Výška";
+ var resultsSummary1$j = "Hledali jste:";
+ var resultsSummary2$j = "Nalezeno %1 odpovídající položky.";
+ var resultsSummary3$j = "Klepnutím na čas spojený s libovolnou položkou přehrajete video od tohoto bodu.";
+ var noResultsFound$j = "Nebyly nalezeny žádné výsledky.";
+ var searchButtonLabel$j = "Přehrát v %1";
+ var hour$j = "hodina";
+ var minuta = "minuta";
+ var second$j = "sekunda";
+ var hours$j = "hodiny";
+ var minutes$j = "minuty";
+ var seconds$j = "sekundy";
+ var vtsHeading$j = "Video Transcript Sorter";
+ var vtsInstructions1$j = "Use the Video Transcript Sorter to modify text tracks:";
+ var vtsInstructions2$j = "Reorder chapters, descriptions, captions, and/or subtitles so they appear in the proper sequence in Able Player's auto-generated transcript.";
+ var vtsInstructions3$j = "Modify content or start/end times (all are directly editable within the table).";
+ var vtsInstructions4$j = "Add new content, such as chapters or descriptions.";
+ var vtsInstructions5$j = "After editing, click the \"Save Changes\" button to generate new content for all relevant timed text files. The new text can be copied and pasted into new WebVTT files.";
+ var vtsSelectLanguage$j = "Select a language";
+ var vtsSave$j = "Generate new .vtt content";
+ var vtsReturn$j = "Return to Editor";
+ var vtsCancel$j = "Cancelling saving. Any edits you made have been restored in the VTS table.";
+ var vtsRow$j = "Row";
+ var vtsKind$j = "Kind";
+ var vtsStart$j = "Start";
+ var vtsEnd$j = "End";
+ var vtsContent$j = "Content";
+ var vtsActions$j = "Actions";
+ var vtsNewRow$j = "A new row %1 has been inserted.";
+ var vtsDeletedRow$j = "Row %1 has been deleted.";
+ var vtsMovedRow$j = "Row %1 has been moved %2 and is now Row %3.";
+ var cs = {
+ playerHeading: playerHeading$j,
+ audioPlayer: audioPlayer$j,
+ videoPlayer: videoPlayer$j,
+ faster: faster$j,
+ slower: slower$j,
+ play: play$j,
+ pause: pause$j,
+ restart: restart$j,
+ prevTrack: prevTrack$j,
+ nextTrack: nextTrack$j,
+ rewind: rewind$j,
+ forward: forward$j,
+ captions: captions$j,
+ showCaptions: showCaptions$j,
+ hideCaptions: hideCaptions$j,
+ captionsOff: captionsOff$j,
+ showTranscript: showTranscript$j,
+ hideTranscript: hideTranscript$j,
+ turnOnDescriptions: turnOnDescriptions$j,
+ turnOffDescriptions: turnOffDescriptions$j,
+ chapters: chapters$j,
+ language: language$j,
+ sign: sign$j,
+ showSign: showSign$j,
+ hideSign: hideSign$j,
+ seekbarLabel: seekbarLabel$j,
+ mute: mute$j,
+ unmute: unmute$j,
+ volume: volume$j,
+ volumeUpDown: volumeUpDown$j,
+ preferences: preferences$j,
+ enterFullScreen: enterFullScreen$j,
+ exitFullScreen: exitFullScreen$j,
+ speed: speed$j,
+ spacebar: spacebar$j,
+ transcriptTitle: transcriptTitle$j,
+ lyricsTitle: lyricsTitle$j,
+ autoScroll: autoScroll$j,
+ statusPlaying: statusPlaying$j,
+ statusPaused: statusPaused$j,
+ statusStopped: statusStopped$j,
+ statusBuffering: statusBuffering$j,
+ statusEnd: statusEnd$j,
+ selectedTrack: selectedTrack$i,
+ alertDescribVersion: alertDescribVersion,
+ alertNonDescribVersion: alertNonDescribVersion,
+ prefMenuCaptions: prefMenuCaptions$j,
+ prefVoicedCaptions: prefVoicedCaptions$j,
+ prefMenuDescriptions: prefMenuDescriptions$j,
+ prefMenuKeyboard: prefMenuKeyboard$j,
+ prefMenuTranscript: prefMenuTranscript$j,
+ prefTitleCaptions: prefTitleCaptions$j,
+ prefTitleDescriptions: prefTitleDescriptions$j,
+ prefTitleKeyboard: prefTitleKeyboard$j,
+ prefTitleTranscript: prefTitleTranscript$i,
+ prefIntroDescription1: prefIntroDescription1$i,
+ prefDescription1: prefDescription1$j,
+ prefDescription2: prefDescription2$j,
+ prefDescription3: prefDescription3$j,
+ prefIntroDescriptionNone: prefIntroDescriptionNone$j,
+ prefIntroDescription3: prefIntroDescription3$j,
+ prefIntroDescription4: prefIntroDescription4$j,
+ prefIntroKeyboard1: prefIntroKeyboard1$j,
+ prefIntroKeyboard2: prefIntroKeyboard2$j,
+ prefIntroKeyboard3: prefIntroKeyboard3$j,
+ prefHeadingKeyboard1: prefHeadingKeyboard1$j,
+ prefHeadingKeyboard2: prefHeadingKeyboard2$j,
+ prefHeadingDescription: prefHeadingDescription$j,
+ prefHeadingTextDescription: prefHeadingTextDescription$j,
+ prefAltKey: prefAltKey$j,
+ prefCtrlKey: prefCtrlKey$j,
+ prefShiftKey: prefShiftKey$j,
+ prefNoKeyShortcuts: prefNoKeyShortcuts$j,
+ escapeKey: escapeKey$j,
+ escapeKeyFunction: escapeKeyFunction$j,
+ prefDescPause: prefDescPause$j,
+ prefDescVisible: prefDescVisible$j,
+ prefDescVoice: prefDescVoice$j,
+ prefDescRate: prefDescRate$j,
+ prefCaptionRate: prefCaptionRate$j,
+ prefDescPitch: prefDescPitch$j,
+ prefDescPitch1: prefDescPitch1$j,
+ prefDescPitch2: prefDescPitch2$j,
+ prefDescPitch3: prefDescPitch3$j,
+ prefDescPitch4: prefDescPitch4$j,
+ prefDescPitch5: prefDescPitch5$j,
+ sampleDescriptionText: sampleDescriptionText$j,
+ prefHighlight: prefHighlight$j,
+ prefTabbable: prefTabbable$j,
+ prefCaptionsFont: prefCaptionsFont$j,
+ prefCaptionsColor: prefCaptionsColor$j,
+ prefCaptionsBGColor: prefCaptionsBGColor$j,
+ prefCaptionsSize: prefCaptionsSize$j,
+ prefCaptionsOpacity: prefCaptionsOpacity$j,
+ prefCaptionsStyle: prefCaptionsStyle$j,
+ serif: serif$j,
+ sans: sans$j,
+ cursive: cursive$j,
+ fantasy: fantasy$j,
+ monospace: monospace$j,
+ white: white$j,
+ yellow: yellow$j,
+ green: green$j,
+ cyan: cyan$i,
+ blue: blue$j,
+ magenta: magenta$j,
+ red: red$j,
+ black: black$j,
+ transparent: transparent$j,
+ solid: solid$j,
+ captionsStylePopOn: captionsStylePopOn$j,
+ captionsStyleRollUp: captionsStyleRollUp$j,
+ prefCaptionsPosition: prefCaptionsPosition$j,
+ captionsPositionOverlay: captionsPositionOverlay$j,
+ captionsPositionBelow: captionsPositionBelow$j,
+ sampleCaptionText: sampleCaptionText$j,
+ prefSuccess: prefSuccess$j,
+ prefNoChange: prefNoChange$j,
+ save: save$j,
+ cancel: cancel$j,
+ dismissButton: dismissButton$j,
+ windowButtonLabel: windowButtonLabel$j,
+ windowMove: windowMove$j,
+ windowMoveLeft: windowMoveLeft$j,
+ windowMoveRight: windowMoveRight$j,
+ windowMoveUp: windowMoveUp$j,
+ windowMoveDown: windowMoveDown$j,
+ windowMoveStopped: windowMoveStopped$j,
+ transcriptControls: transcriptControls$j,
+ signControls: signControls$j,
+ windowMoveAlert: windowMoveAlert$j,
+ windowResize: windowResize$j,
+ windowResizeHeading: windowResizeHeading$j,
+ closeButtonLabel: closeButtonLabel$j,
+ width: width$j,
+ height: height$j,
+ resultsSummary1: resultsSummary1$j,
+ resultsSummary2: resultsSummary2$j,
+ resultsSummary3: resultsSummary3$j,
+ noResultsFound: noResultsFound$j,
+ searchButtonLabel: searchButtonLabel$j,
+ hour: hour$j,
+ minuta: minuta,
+ second: second$j,
+ hours: hours$j,
+ minutes: minutes$j,
+ seconds: seconds$j,
+ vtsHeading: vtsHeading$j,
+ vtsInstructions1: vtsInstructions1$j,
+ vtsInstructions2: vtsInstructions2$j,
+ vtsInstructions3: vtsInstructions3$j,
+ vtsInstructions4: vtsInstructions4$j,
+ vtsInstructions5: vtsInstructions5$j,
+ vtsSelectLanguage: vtsSelectLanguage$j,
+ vtsSave: vtsSave$j,
+ vtsReturn: vtsReturn$j,
+ vtsCancel: vtsCancel$j,
+ vtsRow: vtsRow$j,
+ vtsKind: vtsKind$j,
+ vtsStart: vtsStart$j,
+ vtsEnd: vtsEnd$j,
+ vtsContent: vtsContent$j,
+ vtsActions: vtsActions$j,
+ vtsNewRow: vtsNewRow$j,
+ vtsDeletedRow: vtsDeletedRow$j,
+ vtsMovedRow: vtsMovedRow$j
};
- AblePlayer.prototype.highlightSearchTerm = function (
- searchTerms,
- resultString
- ) {
- searchTerms.forEach(function (searchTerm) {
- var reg = new RegExp(searchTerm, "gi");
- resultString = resultString.replace(
- reg,
- '$& '
- );
- });
- return resultString;
+ var playerHeading$i = "Medieafspiller";
+ var audioPlayer$i = "Audio player";
+ var videoPlayer$i = "Video player";
+ var faster$i = "Hurtigere";
+ var slower$i = "Langsommere";
+ var play$i = "Afspil";
+ var pause$i = "Pause";
+ var restart$i = "Genstart";
+ var prevTrack$i = "Forrige spor";
+ var nextTrack$i = "Næste spor";
+ var rewind$i = "Spol tilbage";
+ var forward$i = "Spol frem";
+ var captions$i = "Undertekster";
+ var showCaptions$i = "Vis undertekster";
+ var hideCaptions$i = "Gem undertekster";
+ var captionsOff$i = "Slå undertekster fra";
+ var showTranscript$i = "Vis transskription";
+ var hideTranscript$i = "Gem transskription";
+ var turnOnDescriptions$i = "Start synstolkning";
+ var turnOffDescriptions$i = "Stop synstolkning";
+ var chapters$i = "Kapitler";
+ var language$i = "Sprog";
+ var sign$i = "Tegnsprog";
+ var showSign$i = "Vis tegnsprog";
+ var hideSign$i = "Gen tegnsprog";
+ var seekbarLabel$i = "tidslinie";
+ var mute$i = "Stop lyd";
+ var unmute$i = "Start lyd";
+ var volume$i = "Lydstyrke";
+ var volumeUpDown$i = "Lydstyrke op";
+ var preferences$i = "Indstillinger";
+ var enterFullScreen$i = "Vis i fuldskærm";
+ var exitFullScreen$i = "Afslut fuldskærmsvisning";
+ var speed$i = "Hastighed";
+ var spacebar$i = "mellemrumstast";
+ var transcriptTitle$i = "Transskription";
+ var lyricsTitle$i = "Lyrik";
+ var autoScroll$i = "Auto scroll";
+ var statusPlaying$i = "Afspiller";
+ var statusPaused$i = "På pause";
+ var statusStopped$i = "Stoppet";
+ var statusBuffering$i = "Henter data";
+ var statusEnd$i = "Slut på spor";
+ var selectedTrack$h = "Valgt spor";
+ var alertDescribedVersion$i = "Anvender synstolket version af denne video";
+ var alertNonDescribedVersion$i = "Anvende ikke synstolket version af denne video";
+ var prefMenuCaptions$i = "Undertekster";
+ var prefVoicedCaptions$i = "Spoken Captions";
+ var prefMenuDescriptions$i = "Synstolkning";
+ var prefMenuKeyboard$i = "Tastatur";
+ var prefMenuTranscript$i = "Transkript";
+ var prefTitleCaptions$i = "Indstillinger for undertekster";
+ var prefTitleDescriptions$i = "Indstillinger for synstolkning";
+ var prefTitleKeyboard$i = "Indstillinger for tastatur";
+ var prefTitleTranscript$h = "Indstillinger for transskription";
+ var prefIntroDescription1$h = "Denne medieafspiller understøtter audio på to måder: ";
+ var prefDescription1$i = "Nuværende videoer har en alternativ synstolket version, textbaseret synstolkning.";
+ var prefDescription2$i = "Nuværende videoer har alternativ synstolket version af videoen.";
+ var prefDescription3$i = "Nuværende videoer har textbaseret synstolkning.";
+ var prefIntroDescriptionNone$i = "Nuværende video har ingen synstolkning i noget format.";
+ var prefIntroDescription3$i = "Anvende følgende formular for at indstille gældende textbasererede synstolkning.";
+ var prefIntroDescription4$i = "Efter du gemmer dine indstillinger, kan synstolkning slåes til og fra med synstolkningsknappen.";
+ var prefIntroKeyboard1$i = "Medieafspilleren på denne webside kan betjenest med tastuturgenveje (se neden for en liste).";
+ var prefIntroKeyboard2$i = "Meta-taster (Shift, Alt, og Ctrl) kan tildeles nedenfor.";
+ var prefIntroKeyboard3$i = "BEMÆRK: Visse tastekombinationer kan være i konflikt med din webbrowser eller andre programmers indstillinger. Benyt de tastekombinationer der virker for dig.";
+ var prefHeadingKeyboard1$i = "Metataster brugt til genveje";
+ var prefHeadingKeyboard2$i = "Nuværende tastatur genveje";
+ var prefHeadingDescription$i = "Synstolkning";
+ var prefHeadingTextDescription$i = "Tekstbaseret synstolkning";
+ var prefAltKey$i = "Alt";
+ var prefCtrlKey$i = "Ctrl";
+ var prefShiftKey$i = "Shift";
+ var prefNoKeyShortcuts$i = "Disable keyboard shortcuts";
+ var escapeKey$i = "Escape";
+ var escapeKeyFunction$i = "Luk nuværinde dialog eller popup-menu";
+ var prefDescPause$i = "Pause automatisk video når synstolkning starter";
+ var prefDescVisible$i = "Vis synstolkning";
+ var prefDescVoice$i = "Stemme";
+ var prefDescRate$i = "Spoken Description Rate";
+ var prefCaptionRate$i = "Spoken Caption Rate";
+ var prefDescPitch$i = "Tonehøjde";
+ var prefDescPitch1$i = "Meget lavt";
+ var prefDescPitch2$i = "Lavt";
+ var prefDescPitch3$i = "Normal";
+ var prefDescPitch4$i = "Højt";
+ var prefDescPitch5$i = "Meget højt";
+ var sampleDescriptionText$i = "Juster indstillinger for at høre denne eksempel tekst.";
+ var prefHighlight$i = "Marker tekst som læses op i transskriptet";
+ var prefTabbable$i = "Tastaturaktiveret transskription";
+ var prefCaptionsFont$i = "Skrifttype";
+ var prefCaptionsColor$i = "Tekstfarve";
+ var prefCaptionsBGColor$i = "Baggrundsfarve";
+ var prefCaptionsSize$i = "Tekststørrelse";
+ var prefCaptionsOpacity$i = "Gennemsigtighed";
+ var prefCaptionsStyle$i = "Teksttype";
+ var serif$i = "serif";
+ var sans$i = "sans-serif";
+ var cursive$i = "kursiv";
+ var fantasy$i = "fantasi";
+ var monospace$i = "monospace";
+ var white$i = "hvid";
+ var yellow$i = "gul";
+ var green$i = "grøn";
+ var cyan$h = "cyan";
+ var blue$i = "blå";
+ var magenta$i = "lilla";
+ var red$i = "rød";
+ var black$i = "sort";
+ var transparent$i = "gennemsigtig";
+ var solid$i = "massiv";
+ var captionsStylePopOn$i = "Pop op";
+ var captionsStyleRollUp$i = "Pop ned";
+ var prefCaptionsPosition$i = "Position";
+ var captionsPositionOverlay$i = "Vis over video";
+ var captionsPositionBelow$i = "Vis under video";
+ var sampleCaptionText$i = "Eksempel på undertekst";
+ var prefSuccess$i = "Dine ændringer er gemt.";
+ var prefNoChange$i = "Du har ikke lavet nogen ændringer.";
+ var save$i = "Gem";
+ var cancel$i = "Afbryd";
+ var dismissButton$i = "Dismiss";
+ var windowButtonLabel$i = "Vindueindstillinger";
+ var windowMove$i = "Flyt";
+ var windowMoveLeft$i = "Window moved left";
+ var windowMoveRight$i = "Window moved right";
+ var windowMoveUp$i = "Window moved up";
+ var windowMoveDown$i = "Window moved down";
+ var windowMoveStopped$i = "Window move stopped";
+ var transcriptControls$i = "Transcript Window Controls";
+ var signControls$i = "Sign Language Window Controls";
+ var windowMoveAlert$i = "Flyt med mus eller anvende piletasterne for at flytte vinduer; Enter for at slutte";
+ var windowResize$i = "Ændre størrelse";
+ var windowResizeHeading$i = "Ændre vinduestørrelse";
+ var closeButtonLabel$i = "Luk";
+ var width$i = "Bredde";
+ var height$i = "Højde";
+ var resultsSummary1$i = "Du søgte efter:";
+ var resultsSummary2$i = "Fundne %1 matchende indhold.";
+ var resultsSummary3$i = "Klik på tidslinien for at afspille derfra.";
+ var noResultsFound$i = "Ingen resultater.";
+ var searchButtonLabel$i = "Afspil fra %1";
+ var hour$i = "time";
+ var minute$i = "minut";
+ var second$i = "sekund";
+ var hours$i = "timer";
+ var minutes$i = "minutter";
+ var seconds$i = "sekunder";
+ var vtsHeading$i = "Video Transcript Sorter";
+ var vtsInstructions1$i = "Use the Video Transcript Sorter to modify text tracks:";
+ var vtsInstructions2$i = "Reorder chapters, descriptions, captions, and/or subtitles so they appear in the proper sequence in Able Player's auto-generated transcript.";
+ var vtsInstructions3$i = "Modify content or start/end times (all are directly editable within the table).";
+ var vtsInstructions4$i = "Add new content, such as chapters or descriptions.";
+ var vtsInstructions5$i = "After editing, click the \"Save Changes\" button to generate new content for all relevant timed text files. The new text can be copied and pasted into new WebVTT files.";
+ var vtsSelectLanguage$i = "Select a language";
+ var vtsSave$i = "Generate new .vtt content";
+ var vtsReturn$i = "Return to Editor";
+ var vtsCancel$i = "Cancelling saving. Any edits you made have been restored in the VTS table.";
+ var vtsRow$i = "Row";
+ var vtsKind$i = "Kind";
+ var vtsStart$i = "Start";
+ var vtsEnd$i = "End";
+ var vtsContent$i = "Content";
+ var vtsActions$i = "Actions";
+ var vtsNewRow$i = "A new row %1 has been inserted.";
+ var vtsDeletedRow$i = "Row %1 has been deleted.";
+ var vtsMovedRow$i = "Row %1 has been moved %2 and is now Row %3.";
+ var da = {
+ playerHeading: playerHeading$i,
+ audioPlayer: audioPlayer$i,
+ videoPlayer: videoPlayer$i,
+ faster: faster$i,
+ slower: slower$i,
+ play: play$i,
+ pause: pause$i,
+ restart: restart$i,
+ prevTrack: prevTrack$i,
+ nextTrack: nextTrack$i,
+ rewind: rewind$i,
+ forward: forward$i,
+ captions: captions$i,
+ showCaptions: showCaptions$i,
+ hideCaptions: hideCaptions$i,
+ captionsOff: captionsOff$i,
+ showTranscript: showTranscript$i,
+ hideTranscript: hideTranscript$i,
+ turnOnDescriptions: turnOnDescriptions$i,
+ turnOffDescriptions: turnOffDescriptions$i,
+ chapters: chapters$i,
+ language: language$i,
+ sign: sign$i,
+ showSign: showSign$i,
+ hideSign: hideSign$i,
+ seekbarLabel: seekbarLabel$i,
+ mute: mute$i,
+ unmute: unmute$i,
+ volume: volume$i,
+ volumeUpDown: volumeUpDown$i,
+ preferences: preferences$i,
+ enterFullScreen: enterFullScreen$i,
+ exitFullScreen: exitFullScreen$i,
+ speed: speed$i,
+ spacebar: spacebar$i,
+ transcriptTitle: transcriptTitle$i,
+ lyricsTitle: lyricsTitle$i,
+ autoScroll: autoScroll$i,
+ statusPlaying: statusPlaying$i,
+ statusPaused: statusPaused$i,
+ statusStopped: statusStopped$i,
+ statusBuffering: statusBuffering$i,
+ statusEnd: statusEnd$i,
+ selectedTrack: selectedTrack$h,
+ alertDescribedVersion: alertDescribedVersion$i,
+ alertNonDescribedVersion: alertNonDescribedVersion$i,
+ prefMenuCaptions: prefMenuCaptions$i,
+ prefVoicedCaptions: prefVoicedCaptions$i,
+ prefMenuDescriptions: prefMenuDescriptions$i,
+ prefMenuKeyboard: prefMenuKeyboard$i,
+ prefMenuTranscript: prefMenuTranscript$i,
+ prefTitleCaptions: prefTitleCaptions$i,
+ prefTitleDescriptions: prefTitleDescriptions$i,
+ prefTitleKeyboard: prefTitleKeyboard$i,
+ prefTitleTranscript: prefTitleTranscript$h,
+ prefIntroDescription1: prefIntroDescription1$h,
+ prefDescription1: prefDescription1$i,
+ prefDescription2: prefDescription2$i,
+ prefDescription3: prefDescription3$i,
+ prefIntroDescriptionNone: prefIntroDescriptionNone$i,
+ prefIntroDescription3: prefIntroDescription3$i,
+ prefIntroDescription4: prefIntroDescription4$i,
+ prefIntroKeyboard1: prefIntroKeyboard1$i,
+ prefIntroKeyboard2: prefIntroKeyboard2$i,
+ prefIntroKeyboard3: prefIntroKeyboard3$i,
+ prefHeadingKeyboard1: prefHeadingKeyboard1$i,
+ prefHeadingKeyboard2: prefHeadingKeyboard2$i,
+ prefHeadingDescription: prefHeadingDescription$i,
+ prefHeadingTextDescription: prefHeadingTextDescription$i,
+ prefAltKey: prefAltKey$i,
+ prefCtrlKey: prefCtrlKey$i,
+ prefShiftKey: prefShiftKey$i,
+ prefNoKeyShortcuts: prefNoKeyShortcuts$i,
+ escapeKey: escapeKey$i,
+ escapeKeyFunction: escapeKeyFunction$i,
+ prefDescPause: prefDescPause$i,
+ prefDescVisible: prefDescVisible$i,
+ prefDescVoice: prefDescVoice$i,
+ prefDescRate: prefDescRate$i,
+ prefCaptionRate: prefCaptionRate$i,
+ prefDescPitch: prefDescPitch$i,
+ prefDescPitch1: prefDescPitch1$i,
+ prefDescPitch2: prefDescPitch2$i,
+ prefDescPitch3: prefDescPitch3$i,
+ prefDescPitch4: prefDescPitch4$i,
+ prefDescPitch5: prefDescPitch5$i,
+ sampleDescriptionText: sampleDescriptionText$i,
+ prefHighlight: prefHighlight$i,
+ prefTabbable: prefTabbable$i,
+ prefCaptionsFont: prefCaptionsFont$i,
+ prefCaptionsColor: prefCaptionsColor$i,
+ prefCaptionsBGColor: prefCaptionsBGColor$i,
+ prefCaptionsSize: prefCaptionsSize$i,
+ prefCaptionsOpacity: prefCaptionsOpacity$i,
+ prefCaptionsStyle: prefCaptionsStyle$i,
+ serif: serif$i,
+ sans: sans$i,
+ cursive: cursive$i,
+ fantasy: fantasy$i,
+ monospace: monospace$i,
+ white: white$i,
+ yellow: yellow$i,
+ green: green$i,
+ cyan: cyan$h,
+ blue: blue$i,
+ magenta: magenta$i,
+ red: red$i,
+ black: black$i,
+ transparent: transparent$i,
+ solid: solid$i,
+ captionsStylePopOn: captionsStylePopOn$i,
+ captionsStyleRollUp: captionsStyleRollUp$i,
+ prefCaptionsPosition: prefCaptionsPosition$i,
+ captionsPositionOverlay: captionsPositionOverlay$i,
+ captionsPositionBelow: captionsPositionBelow$i,
+ sampleCaptionText: sampleCaptionText$i,
+ prefSuccess: prefSuccess$i,
+ prefNoChange: prefNoChange$i,
+ save: save$i,
+ cancel: cancel$i,
+ dismissButton: dismissButton$i,
+ windowButtonLabel: windowButtonLabel$i,
+ windowMove: windowMove$i,
+ windowMoveLeft: windowMoveLeft$i,
+ windowMoveRight: windowMoveRight$i,
+ windowMoveUp: windowMoveUp$i,
+ windowMoveDown: windowMoveDown$i,
+ windowMoveStopped: windowMoveStopped$i,
+ transcriptControls: transcriptControls$i,
+ signControls: signControls$i,
+ windowMoveAlert: windowMoveAlert$i,
+ windowResize: windowResize$i,
+ windowResizeHeading: windowResizeHeading$i,
+ closeButtonLabel: closeButtonLabel$i,
+ width: width$i,
+ height: height$i,
+ resultsSummary1: resultsSummary1$i,
+ resultsSummary2: resultsSummary2$i,
+ resultsSummary3: resultsSummary3$i,
+ noResultsFound: noResultsFound$i,
+ searchButtonLabel: searchButtonLabel$i,
+ hour: hour$i,
+ minute: minute$i,
+ second: second$i,
+ hours: hours$i,
+ minutes: minutes$i,
+ seconds: seconds$i,
+ vtsHeading: vtsHeading$i,
+ vtsInstructions1: vtsInstructions1$i,
+ vtsInstructions2: vtsInstructions2$i,
+ vtsInstructions3: vtsInstructions3$i,
+ vtsInstructions4: vtsInstructions4$i,
+ vtsInstructions5: vtsInstructions5$i,
+ vtsSelectLanguage: vtsSelectLanguage$i,
+ vtsSave: vtsSave$i,
+ vtsReturn: vtsReturn$i,
+ vtsCancel: vtsCancel$i,
+ vtsRow: vtsRow$i,
+ vtsKind: vtsKind$i,
+ vtsStart: vtsStart$i,
+ vtsEnd: vtsEnd$i,
+ vtsContent: vtsContent$i,
+ vtsActions: vtsActions$i,
+ vtsNewRow: vtsNewRow$i,
+ vtsDeletedRow: vtsDeletedRow$i,
+ vtsMovedRow: vtsMovedRow$i
};
- AblePlayer.prototype.secondsToTime = function (totalSeconds) {
+ var playerHeading$h = "Medienplayer";
+ var audioPlayer$h = "Audioplayer";
+ var videoPlayer$h = "Videoplayer";
+ var faster$h = "Schneller";
+ var slower$h = "Langsamer";
+ var chapters$h = "Kapitel";
+ var play$h = "Abspielen";
+ var pause$h = "Pause";
+ var restart$h = "Neustart";
+ var prevTrack$h = "Vorheriger Titel";
+ var nextTrack$h = "Nächster Titel";
+ var rewind$h = "Zurück";
+ var forward$h = "Vorwärts";
+ var captions$h = "Untertitel";
+ var showCaptions$h = "Untertitel anzeigen";
+ var hideCaptions$h = "Untertitel ausblenden";
+ var captionsOff$h = "Untertitel ausschalten";
+ var showTranscript$h = "Transkription anzeigen";
+ var hideTranscript$h = "Transkription entfernen";
+ var turnOnDescriptions$h = "Audiobeschreibung einschalten";
+ var turnOffDescriptions$h = "Audiobeschreibung ausschalten";
+ var language$h = "Sprache";
+ var sign$h = "Gebärdensprache";
+ var showSign$h = "Gebärdensprache anzeigen";
+ var hideSign$h = "Gebärdensprache ausblenden";
+ var seekbarLabel$h = "Suchleiste";
+ var mute$h = "Ton aus";
+ var unmute$h = "Ton an";
+ var volume$h = "Lautstärke";
+ var volumeUpDown$h = "Lautstärkeregler";
+ var preferences$h = "Einstellungen";
+ var enterFullScreen$h = "Vollbildmodus einschalten";
+ var exitFullScreen$h = "Vollbildmodus verlassen";
+ var speed$h = "Geschwindigkeit";
+ var spacebar$h = "Leertaste";
+ var transcriptTitle$h = "Transkription";
+ var lyricsTitle$h = "Text";
+ var autoScroll$h = "Automatisch scrollen";
+ var statusPlaying$h = "Gestartet";
+ var statusPaused$h = "Pausiert";
+ var statusStopped$h = "Angehalten";
+ var statusBuffering$h = "Daten werden empfangen...";
+ var statusEnd$h = "Ende des Titels";
+ var selectedTrack$g = "Ausgewählter Titel";
+ var alertDescribedVersion$h = "Das Video wird mit Audiobeschreibung abgespielt";
+ var alertNonDescribedVersion$h = "Das Video wird ohne Audiobeschreibung abgespielt";
+ var prefMenuCaptions$h = "Untertitel";
+ var prefVoicedCaptions$h = "Spoken Captions";
+ var prefMenuDescriptions$h = "Audiobeschreibungen";
+ var prefMenuKeyboard$h = "Tastatur";
+ var prefMenuTranscript$h = "Transkription";
+ var prefTitleCaptions$h = "Untertitel Einstellungen";
+ var prefTitleDescriptions$h = "Audiobeschreibung Einstellungen";
+ var prefTitleKeyboard$h = "Tastatur Einstellungen";
+ var prefTitleTranscript$g = "Transkription Einstellungen";
+ var prefIntroDescription1$g = "Dieser Media Player unterstützt zwei Arten von Untertiteln: ";
+ var prefDescription1$h = "Das aktuelle Video hat eine alternative Version der Audiobeschreibung, eine textbasierte Audiobeschreibung.";
+ var prefDescription2$h = "Das aktuelle Video hat Version des Videos, die eine Audiobeschreibung enthält.";
+ var prefDescription3$h = "Das aktuelle Video hat Textbasierte Audiobeschreibung, die vom Screen-Reader vorgelesen wird.";
+ var prefIntroDescriptionNone$h = "Das aktuelle Video hat keine Audiobeschreibung.";
+ var prefIntroDescription3$h = "Mit der folgenden Auswahl steuern Sie das Abspielen der textbasierten Audiobeschreibung.";
+ var prefIntroDescription4$h = "Wenn die Audiobeschreibung aktiviert ist, kann sie per Schaltfläche ein- und ausgeschaltet werden.";
+ var prefIntroKeyboard1$h = "Dieser Media Player lässt sich innerhalb der gesamten Seite per Tastenkürzel bedienen (siehe unten).";
+ var prefIntroKeyboard2$h = "Die Modifikatortasten (Umschalt, Alt, und Strg) können hier zugeordnet werden.";
+ var prefIntroKeyboard3$h = "Achtung: Einige Tastenkombinationen sind je nach Browser und Betriebssystem nicht möglich. Versuchen Sie gegebenenfalls andere Kombinationen.";
+ var prefHeadingKeyboard1$h = "Modifikatortasten für die Tastenkürzel";
+ var prefHeadingKeyboard2$h = "Aktuell eingestellte Tastenkürzel";
+ var prefHeadingDescription$h = "Audiobeschreibung";
+ var prefHeadingTextDescription$h = "Textbasierte Audiobeschreibung";
+ var prefAltKey$h = "Alt";
+ var prefCtrlKey$h = "Strg";
+ var prefShiftKey$h = "Umschalttaste";
+ var prefNoKeyShortcuts$h = "Tastenkombinationen deaktivieren";
+ var escapeKey$h = "ESC Taste";
+ var escapeKeyFunction$h = "Dialogfenster schließen";
+ var prefDescPause$h = "Video automatisch anhalten, wenn Szenenbeschreibungen eingeblendet werden";
+ var prefDescVisible$h = "Textbasierte Szenenbeschreibungen einblenden, wenn diese aktiviert sind";
+ var prefDescVoice$h = "Stimme";
+ var prefDescRate$h = "Spoken Description Rate";
+ var prefCaptionRate$h = "Spoken Caption Rate";
+ var prefDescPitch$h = "Tonlage";
+ var prefDescPitch1$h = "Sehr tief";
+ var prefDescPitch2$h = "Tief";
+ var prefDescPitch3$h = "Mittel";
+ var prefDescPitch4$h = "Hoch";
+ var prefDescPitch5$h = "Sehr hoch";
+ var sampleDescriptionText$h = "Einstellungen bearbeiten um diesen Text vorzulesen.";
+ var prefHighlight$h = "Transkription hervorheben, während das Medium abgespielt wird";
+ var prefTabbable$h = "Transkription per Tastatur ein-/ausschaltbar machen";
+ var prefCaptionsFont$h = "Schriftart";
+ var prefCaptionsColor$h = "Schriftfarbe";
+ var prefCaptionsBGColor$h = "Hintergrund";
+ var prefCaptionsSize$h = "Schriftgöße";
+ var prefCaptionsOpacity$h = "Deckkraft";
+ var prefCaptionsStyle$h = "Stil";
+ var serif$h = "Serifenschrift";
+ var sans$h = "Serifenlose Schrift";
+ var cursive$h = "kursiv";
+ var fantasy$h = "Fantasieschrift";
+ var monospace$h = "nichtproportionale Schrift";
+ var white$h = "weiß";
+ var yellow$h = "gelb";
+ var green$h = "grün";
+ var cyan$g = "cyan";
+ var blue$h = "blau";
+ var magenta$h = "magenta";
+ var red$h = "rot";
+ var black$h = "schwarz";
+ var transparent$h = "transparent";
+ var solid$h = "undurchsichtig";
+ var captionsStylePopOn$h = "Pop-on";
+ var captionsStyleRollUp$h = "Roll-up";
+ var prefCaptionsPosition$h = "Position";
+ var captionsPositionOverlay$h = "Überlagert";
+ var captionsPositionBelow$h = "Unterhalb";
+ var sampleCaptionText$h = "Textbeispiel";
+ var prefSuccess$h = "Ihre Änderungen wurden gespeichert.";
+ var prefNoChange$h = "Es gab keine Änderungen zu speichern.";
+ var save$h = "Speichern";
+ var cancel$h = "Abbrechen";
+ var dismissButton$h = "Dismiss";
+ var windowButtonLabel$h = "Fenstereinstellungen";
+ var windowMove$h = "Verschieben";
+ var windowMoveLeft$h = "Das Fenster verschob sich nach links";
+ var windowMoveRight$h = "Das Fenster verschob sich nach rechts";
+ var windowMoveUp$h = "Das Fenster verschob sich nach oben";
+ var windowMoveDown$h = "Das Fenster verschob sich nach unten";
+ var windowMoveStopped$h = "Das Fenster hörte auf sich zu verschieben";
+ var transcriptControls$h = "Bedienelemente des Transkriptionsfensters";
+ var signControls$h = "Bedienelemente des Gebärdensprache-Fensters";
+ var windowMoveAlert$h = "Fenster mit Pfeiltasten oder Maus verschieben; beenden mit Eingabetaste";
+ var windowResize$h = "Größe verändern";
+ var windowResizeHeading$h = "Größe des Gebärdensprache-Fenster";
+ var closeButtonLabel$h = "Schließen";
+ var width$h = "Breite";
+ var height$h = "Höhe";
+ var resultsSummary1$h = "Suche nach:";
+ var resultsSummary2$h = "Gefunden %1 Treffer.";
+ var resultsSummary3$h = "Auf den Zeitindex klicken, um das Video vom Zeitpunkt des jeweiligen Suchergebnisses abzuspielen.";
+ var noResultsFound$h = "Keine Treffer.";
+ var searchButtonLabel$h = "Abspielen von %1";
+ var hour$h = "Stunde";
+ var minute$h = "Minute";
+ var second$h = "Sekunde";
+ var hours$h = "Stunden";
+ var minutes$h = "Minuten";
+ var seconds$h = "Sekunden";
+ var vtsHeading$h = "Transkriptions-Sortierer für Videos";
+ var vtsInstructions1$h = "Verwenden Sie den Transkription-Sortierer für Videos, um Textspuren zu ändern:";
+ var vtsInstructions2$h = "Ordnen Sie Kapitel, Beschreibungen, Bildunterschriften, und/oder Untertitel so, dass diese in der richtigen Reihenfolge in der selbsterzeugten Transkription des Able Players erscheinen.";
+ var vtsInstructions3$h = "Verändern Sie Inhalt oder Anfangs- bzw. Endzeiten (alle sind direkt innerhalb der Tabelle editierbar).";
+ var vtsInstructions4$h = "Fügen Sie neuen Inhalt, wie Kapitel oder Beschreibungen hinzu.";
+ var vtsInstructions5$h = "Nach dem Editieren klicken Sie auf die Schaltfläche \"Änderungen speichern\" um neuen Inhalt für alle wichtigen zeitgesteuerten Textdateien zu erzeugen. Der neue Text kann in neue WebVTT-Dateien kopiert und eingefügt werden.";
+ var vtsSelectLanguage$h = "Wählen Sie eine Sprache aus";
+ var vtsSave$h = "Erzeugen Sie neuen .vtt-Inhalt";
+ var vtsReturn$h = "Gehen Sie zurück zum Editor";
+ var vtsCancel$h = "Abbruch des Speicherns. Jegliche Bearbeitungen, die Sie vorgenommen haben, wurden in der VTS-Tabelle gesichert.";
+ var vtsRow$h = "Reihe";
+ var vtsKind$h = "Art";
+ var vtsStart$h = "Anfang";
+ var vtsEnd$h = "Ende";
+ var vtsContent$h = "Inhalt";
+ var vtsActions$h = "Aktionen";
+ var vtsNewRow$h = "Eine neue Reihe %1 wurde eingefügt.";
+ var vtsDeletedRow$h = "Reihe %1 wurde gelöscht.";
+ var vtsMovedRow$h = "Reihe %1 wurde verschoben %2 ist nun Reihe %3.";
+ var de = {
+ playerHeading: playerHeading$h,
+ audioPlayer: audioPlayer$h,
+ videoPlayer: videoPlayer$h,
+ faster: faster$h,
+ slower: slower$h,
+ chapters: chapters$h,
+ play: play$h,
+ pause: pause$h,
+ restart: restart$h,
+ prevTrack: prevTrack$h,
+ nextTrack: nextTrack$h,
+ rewind: rewind$h,
+ forward: forward$h,
+ captions: captions$h,
+ showCaptions: showCaptions$h,
+ hideCaptions: hideCaptions$h,
+ captionsOff: captionsOff$h,
+ showTranscript: showTranscript$h,
+ hideTranscript: hideTranscript$h,
+ turnOnDescriptions: turnOnDescriptions$h,
+ turnOffDescriptions: turnOffDescriptions$h,
+ language: language$h,
+ sign: sign$h,
+ showSign: showSign$h,
+ hideSign: hideSign$h,
+ seekbarLabel: seekbarLabel$h,
+ mute: mute$h,
+ unmute: unmute$h,
+ volume: volume$h,
+ volumeUpDown: volumeUpDown$h,
+ preferences: preferences$h,
+ enterFullScreen: enterFullScreen$h,
+ exitFullScreen: exitFullScreen$h,
+ speed: speed$h,
+ spacebar: spacebar$h,
+ transcriptTitle: transcriptTitle$h,
+ lyricsTitle: lyricsTitle$h,
+ autoScroll: autoScroll$h,
+ statusPlaying: statusPlaying$h,
+ statusPaused: statusPaused$h,
+ statusStopped: statusStopped$h,
+ statusBuffering: statusBuffering$h,
+ statusEnd: statusEnd$h,
+ selectedTrack: selectedTrack$g,
+ alertDescribedVersion: alertDescribedVersion$h,
+ alertNonDescribedVersion: alertNonDescribedVersion$h,
+ prefMenuCaptions: prefMenuCaptions$h,
+ prefVoicedCaptions: prefVoicedCaptions$h,
+ prefMenuDescriptions: prefMenuDescriptions$h,
+ prefMenuKeyboard: prefMenuKeyboard$h,
+ prefMenuTranscript: prefMenuTranscript$h,
+ prefTitleCaptions: prefTitleCaptions$h,
+ prefTitleDescriptions: prefTitleDescriptions$h,
+ prefTitleKeyboard: prefTitleKeyboard$h,
+ prefTitleTranscript: prefTitleTranscript$g,
+ prefIntroDescription1: prefIntroDescription1$g,
+ prefDescription1: prefDescription1$h,
+ prefDescription2: prefDescription2$h,
+ prefDescription3: prefDescription3$h,
+ prefIntroDescriptionNone: prefIntroDescriptionNone$h,
+ prefIntroDescription3: prefIntroDescription3$h,
+ prefIntroDescription4: prefIntroDescription4$h,
+ prefIntroKeyboard1: prefIntroKeyboard1$h,
+ prefIntroKeyboard2: prefIntroKeyboard2$h,
+ prefIntroKeyboard3: prefIntroKeyboard3$h,
+ prefHeadingKeyboard1: prefHeadingKeyboard1$h,
+ prefHeadingKeyboard2: prefHeadingKeyboard2$h,
+ prefHeadingDescription: prefHeadingDescription$h,
+ prefHeadingTextDescription: prefHeadingTextDescription$h,
+ prefAltKey: prefAltKey$h,
+ prefCtrlKey: prefCtrlKey$h,
+ prefShiftKey: prefShiftKey$h,
+ prefNoKeyShortcuts: prefNoKeyShortcuts$h,
+ escapeKey: escapeKey$h,
+ escapeKeyFunction: escapeKeyFunction$h,
+ prefDescPause: prefDescPause$h,
+ prefDescVisible: prefDescVisible$h,
+ prefDescVoice: prefDescVoice$h,
+ prefDescRate: prefDescRate$h,
+ prefCaptionRate: prefCaptionRate$h,
+ prefDescPitch: prefDescPitch$h,
+ prefDescPitch1: prefDescPitch1$h,
+ prefDescPitch2: prefDescPitch2$h,
+ prefDescPitch3: prefDescPitch3$h,
+ prefDescPitch4: prefDescPitch4$h,
+ prefDescPitch5: prefDescPitch5$h,
+ sampleDescriptionText: sampleDescriptionText$h,
+ prefHighlight: prefHighlight$h,
+ prefTabbable: prefTabbable$h,
+ prefCaptionsFont: prefCaptionsFont$h,
+ prefCaptionsColor: prefCaptionsColor$h,
+ prefCaptionsBGColor: prefCaptionsBGColor$h,
+ prefCaptionsSize: prefCaptionsSize$h,
+ prefCaptionsOpacity: prefCaptionsOpacity$h,
+ prefCaptionsStyle: prefCaptionsStyle$h,
+ serif: serif$h,
+ sans: sans$h,
+ cursive: cursive$h,
+ fantasy: fantasy$h,
+ monospace: monospace$h,
+ white: white$h,
+ yellow: yellow$h,
+ green: green$h,
+ cyan: cyan$g,
+ blue: blue$h,
+ magenta: magenta$h,
+ red: red$h,
+ black: black$h,
+ transparent: transparent$h,
+ solid: solid$h,
+ captionsStylePopOn: captionsStylePopOn$h,
+ captionsStyleRollUp: captionsStyleRollUp$h,
+ prefCaptionsPosition: prefCaptionsPosition$h,
+ captionsPositionOverlay: captionsPositionOverlay$h,
+ captionsPositionBelow: captionsPositionBelow$h,
+ sampleCaptionText: sampleCaptionText$h,
+ prefSuccess: prefSuccess$h,
+ prefNoChange: prefNoChange$h,
+ save: save$h,
+ cancel: cancel$h,
+ dismissButton: dismissButton$h,
+ windowButtonLabel: windowButtonLabel$h,
+ windowMove: windowMove$h,
+ windowMoveLeft: windowMoveLeft$h,
+ windowMoveRight: windowMoveRight$h,
+ windowMoveUp: windowMoveUp$h,
+ windowMoveDown: windowMoveDown$h,
+ windowMoveStopped: windowMoveStopped$h,
+ transcriptControls: transcriptControls$h,
+ signControls: signControls$h,
+ windowMoveAlert: windowMoveAlert$h,
+ windowResize: windowResize$h,
+ windowResizeHeading: windowResizeHeading$h,
+ closeButtonLabel: closeButtonLabel$h,
+ width: width$h,
+ height: height$h,
+ resultsSummary1: resultsSummary1$h,
+ resultsSummary2: resultsSummary2$h,
+ resultsSummary3: resultsSummary3$h,
+ noResultsFound: noResultsFound$h,
+ searchButtonLabel: searchButtonLabel$h,
+ hour: hour$h,
+ minute: minute$h,
+ second: second$h,
+ hours: hours$h,
+ minutes: minutes$h,
+ seconds: seconds$h,
+ vtsHeading: vtsHeading$h,
+ vtsInstructions1: vtsInstructions1$h,
+ vtsInstructions2: vtsInstructions2$h,
+ vtsInstructions3: vtsInstructions3$h,
+ vtsInstructions4: vtsInstructions4$h,
+ vtsInstructions5: vtsInstructions5$h,
+ vtsSelectLanguage: vtsSelectLanguage$h,
+ vtsSave: vtsSave$h,
+ vtsReturn: vtsReturn$h,
+ vtsCancel: vtsCancel$h,
+ vtsRow: vtsRow$h,
+ vtsKind: vtsKind$h,
+ vtsStart: vtsStart$h,
+ vtsEnd: vtsEnd$h,
+ vtsContent: vtsContent$h,
+ vtsActions: vtsActions$h,
+ vtsNewRow: vtsNewRow$h,
+ vtsDeletedRow: vtsDeletedRow$h,
+ vtsMovedRow: vtsMovedRow$h
+ };
- var totalSeconds = Math.floor(totalSeconds);
+ var playerHeading$g = "Media player";
+ var audioPlayer$g = "Audio player";
+ var videoPlayer$g = "Video player";
+ var faster$g = "Faster";
+ var slower$g = "Slower";
+ var play$g = "Play";
+ var pause$g = "Pause";
+ var restart$g = "Restart";
+ var prevTrack$g = "Previous track";
+ var nextTrack$g = "Next track";
+ var rewind$g = "Rewind";
+ var forward$g = "Forward";
+ var captions$g = "Captions";
+ var showCaptions$g = "Show captions";
+ var hideCaptions$g = "Hide captions";
+ var captionsOff$g = "Captions off";
+ var showTranscript$g = "Show transcript";
+ var hideTranscript$g = "Hide transcript";
+ var turnOnDescriptions$g = "Turn on descriptions";
+ var turnOffDescriptions$g = "Turn off descriptions";
+ var chapters$g = "Chapters";
+ var language$g = "Language";
+ var sign$g = "Sign language";
+ var showSign$g = "Show sign language";
+ var hideSign$g = "Hide sign language";
+ var seekbarLabel$g = "timeline";
+ var mute$g = "Mute";
+ var unmute$g = "Unmute";
+ var volume$g = "Volume";
+ var volumeUpDown$g = "Volume up down";
+ var preferences$g = "Preferences";
+ var enterFullScreen$g = "Enter full screen";
+ var exitFullScreen$g = "Exit full screen";
+ var speed$g = "Speed";
+ var spacebar$g = "spacebar";
+ var transcriptTitle$g = "Transcript";
+ var lyricsTitle$g = "Lyrics";
+ var autoScroll$g = "Auto scroll";
+ var statusPlaying$g = "Playing";
+ var statusPaused$g = "Paused";
+ var statusStopped$g = "Stopped";
+ var statusBuffering$g = "Buffering";
+ var statusEnd$g = "End of track";
+ var selectedTrack$f = "Selected Track";
+ var alertDescribedVersion$g = "Using the audio described version of this video";
+ var alertNonDescribedVersion$g = "Using the non-described version of this video";
+ var prefMenuCaptions$g = "Captions";
+ var prefVoicedCaptions$g = "Spoken Captions";
+ var prefMenuDescriptions$g = "Descriptions";
+ var prefMenuKeyboard$g = "Keyboard";
+ var prefMenuTranscript$g = "Transcript";
+ var prefTitleCaptions$g = "Captions Preferences";
+ var prefTitleDescriptions$g = "Audio Description Preferences";
+ var prefTitleKeyboard$g = "Keyboard Preferences";
+ var prefTitleTranscript$f = "Transcript Preferences";
+ var prefIntroDescription1$f = "This media player supports audio description in two ways: ";
+ var prefDescription1$g = "The current video has an alternative described version and text-based description, announced by screen reader.";
+ var prefDescription2$g = "The current video has text-based description.";
+ var prefDescription3$g = "The current video has an alternative described version.";
+ var prefIntroDescriptionNone$g = "The current video has no audio description in either format.";
+ var prefIntroDescription3$g = "Use the following form to set your preferences related to text-based audio description.";
+ var prefIntroDescription4$g = "After you save your settings, audio description can be toggled on/off using the Description button.";
+ var prefIntroKeyboard1$g = "The media player on this web page can be operated from anywhere on the page using keyboard shortcuts (see below for a list).";
+ var prefIntroKeyboard2$g = "Modifier keys (Shift, Alt, and Control) can be assigned below.";
+ var prefIntroKeyboard3$g = "NOTE: Some key combinations might conflict with keys used by your browser and/or other software applications. Try various combinations of modifier keys to find one that works for you.";
+ var prefHeadingKeyboard1$g = "Modifier keys used for shortcuts";
+ var prefHeadingKeyboard2$g = "Current keyboard shortcuts";
+ var prefHeadingDescription$g = "Audio description";
+ var prefHeadingTextDescription$g = "Text-based audio description";
+ var prefAltKey$g = "Alt";
+ var prefCtrlKey$g = "Control";
+ var prefShiftKey$g = "Shift";
+ var prefNoKeyShortcuts$g = "Disable keyboard shortcuts";
+ var escapeKey$g = "Escape";
+ var escapeKeyFunction$g = "Close current dialog or popup menu";
+ var prefDescPause$g = "Automatically pause video when description starts";
+ var prefDescVisible$g = "Make description visible";
+ var prefDescVoice$g = "Voice";
+ var prefDescRate$g = "Spoken Description Rate";
+ var prefCaptionRate$g = "Spoken Caption Rate";
+ var prefDescPitch$g = "Pitch";
+ var prefDescPitch1$g = "Very low";
+ var prefDescPitch2$g = "Low";
+ var prefDescPitch3$g = "Default";
+ var prefDescPitch4$g = "High";
+ var prefDescPitch5$g = "Very high";
+ var sampleDescriptionText$g = "Adjust settings to hear this sample text.";
+ var prefHighlight$g = "Highlight transcript as media plays";
+ var prefTabbable$g = "Keyboard-enable transcript";
+ var prefCaptionsFont$g = "Font";
+ var prefCaptionsColor$g = "Text Color";
+ var prefCaptionsBGColor$g = "Background";
+ var prefCaptionsSize$g = "Font Size";
+ var prefCaptionsOpacity$g = "Opacity";
+ var prefCaptionsStyle$g = "Style";
+ var serif$g = "serif";
+ var sans$g = "sans-serif";
+ var cursive$g = "cursive";
+ var fantasy$g = "fantasy";
+ var monospace$g = "monospace";
+ var white$g = "white";
+ var yellow$g = "yellow";
+ var green$g = "green";
+ var cyan$f = "cyan";
+ var blue$g = "blue";
+ var magenta$g = "magenta";
+ var red$g = "red";
+ var black$g = "black";
+ var transparent$g = "transparent";
+ var solid$g = "solid";
+ var captionsStylePopOn$g = "Pop-on";
+ var captionsStyleRollUp$g = "Roll-up";
+ var prefCaptionsPosition$g = "Position";
+ var captionsPositionOverlay$g = "Overlay";
+ var captionsPositionBelow$g = "Below video";
+ var sampleCaptionText$g = "Sample caption text";
+ var prefSuccess$g = "Your changes have been saved.";
+ var prefNoChange$g = "You didn't make any changes.";
+ var save$g = "Save";
+ var cancel$g = "Cancel";
+ var dismissButton$g = "Dismiss";
+ var windowButtonLabel$g = "Window options";
+ var windowMove$g = "Move";
+ var windowMoveLeft$g = "Window moved left";
+ var windowMoveRight$g = "Window moved right";
+ var windowMoveUp$g = "Window moved up";
+ var windowMoveDown$g = "Window moved down";
+ var windowMoveStopped$g = "Window move stopped";
+ var transcriptControls$g = "Transcript Window Controls";
+ var signControls$g = "Sign Language Window Controls";
+ var windowMoveAlert$g = "Drag or use arrow keys to move the window; Enter to stop";
+ var windowResize$g = "Resize";
+ var windowResizeHeading$g = "Resize Window";
+ var closeButtonLabel$g = "Close";
+ var width$g = "Width";
+ var height$g = "Height";
+ var resultsSummary1$g = "You searched for:";
+ var resultsSummary2$g = "Found %1 matching items.";
+ var resultsSummary3$g = "Click the time associated with any item to play the video from that point.";
+ var noResultsFound$g = "No results found.";
+ var searchButtonLabel$g = "Play at %1";
+ var hour$g = "hour";
+ var minute$g = "minute";
+ var second$g = "second";
+ var hours$g = "hours";
+ var minutes$g = "minutes";
+ var seconds$g = "seconds";
+ var vtsHeading$g = "Video Transcript Sorter";
+ var vtsInstructions1$g = "Use the Video Transcript Sorter to modify text tracks:";
+ var vtsInstructions2$g = "Reorder chapters, descriptions, captions, and/or subtitles so they appear in the proper sequence in Able Player's auto-generated transcript.";
+ var vtsInstructions3$g = "Modify content or start/end times (all are directly editable within the table).";
+ var vtsInstructions4$g = "Add new content, such as chapters or descriptions.";
+ var vtsInstructions5$g = "After editing, click the \"Save Changes\" button to generate new content for all relevant timed text files. The new text can be copied and pasted into new WebVTT files.";
+ var vtsSelectLanguage$g = "Select a language";
+ var vtsSave$g = "Generate new .vtt content";
+ var vtsReturn$g = "Return to Editor";
+ var vtsCancel$g = "Cancelling saving. Any edits you made have been restored in the VTS table.";
+ var vtsRow$g = "Row";
+ var vtsKind$g = "Kind";
+ var vtsStart$g = "Start";
+ var vtsEnd$g = "End";
+ var vtsContent$g = "Content";
+ var vtsActions$g = "Actions";
+ var vtsNewRow$g = "A new row %1 has been inserted.";
+ var vtsDeletedRow$g = "Row %1 has been deleted.";
+ var vtsMovedRow$g = "Row %1 has been moved %2 and is now Row %3.";
+ var en = {
+ playerHeading: playerHeading$g,
+ audioPlayer: audioPlayer$g,
+ videoPlayer: videoPlayer$g,
+ faster: faster$g,
+ slower: slower$g,
+ play: play$g,
+ pause: pause$g,
+ restart: restart$g,
+ prevTrack: prevTrack$g,
+ nextTrack: nextTrack$g,
+ rewind: rewind$g,
+ forward: forward$g,
+ captions: captions$g,
+ showCaptions: showCaptions$g,
+ hideCaptions: hideCaptions$g,
+ captionsOff: captionsOff$g,
+ showTranscript: showTranscript$g,
+ hideTranscript: hideTranscript$g,
+ turnOnDescriptions: turnOnDescriptions$g,
+ turnOffDescriptions: turnOffDescriptions$g,
+ chapters: chapters$g,
+ language: language$g,
+ sign: sign$g,
+ showSign: showSign$g,
+ hideSign: hideSign$g,
+ seekbarLabel: seekbarLabel$g,
+ mute: mute$g,
+ unmute: unmute$g,
+ volume: volume$g,
+ volumeUpDown: volumeUpDown$g,
+ preferences: preferences$g,
+ enterFullScreen: enterFullScreen$g,
+ exitFullScreen: exitFullScreen$g,
+ speed: speed$g,
+ spacebar: spacebar$g,
+ transcriptTitle: transcriptTitle$g,
+ lyricsTitle: lyricsTitle$g,
+ autoScroll: autoScroll$g,
+ statusPlaying: statusPlaying$g,
+ statusPaused: statusPaused$g,
+ statusStopped: statusStopped$g,
+ statusBuffering: statusBuffering$g,
+ statusEnd: statusEnd$g,
+ selectedTrack: selectedTrack$f,
+ alertDescribedVersion: alertDescribedVersion$g,
+ alertNonDescribedVersion: alertNonDescribedVersion$g,
+ prefMenuCaptions: prefMenuCaptions$g,
+ prefVoicedCaptions: prefVoicedCaptions$g,
+ prefMenuDescriptions: prefMenuDescriptions$g,
+ prefMenuKeyboard: prefMenuKeyboard$g,
+ prefMenuTranscript: prefMenuTranscript$g,
+ prefTitleCaptions: prefTitleCaptions$g,
+ prefTitleDescriptions: prefTitleDescriptions$g,
+ prefTitleKeyboard: prefTitleKeyboard$g,
+ prefTitleTranscript: prefTitleTranscript$f,
+ prefIntroDescription1: prefIntroDescription1$f,
+ prefDescription1: prefDescription1$g,
+ prefDescription2: prefDescription2$g,
+ prefDescription3: prefDescription3$g,
+ prefIntroDescriptionNone: prefIntroDescriptionNone$g,
+ prefIntroDescription3: prefIntroDescription3$g,
+ prefIntroDescription4: prefIntroDescription4$g,
+ prefIntroKeyboard1: prefIntroKeyboard1$g,
+ prefIntroKeyboard2: prefIntroKeyboard2$g,
+ prefIntroKeyboard3: prefIntroKeyboard3$g,
+ prefHeadingKeyboard1: prefHeadingKeyboard1$g,
+ prefHeadingKeyboard2: prefHeadingKeyboard2$g,
+ prefHeadingDescription: prefHeadingDescription$g,
+ prefHeadingTextDescription: prefHeadingTextDescription$g,
+ prefAltKey: prefAltKey$g,
+ prefCtrlKey: prefCtrlKey$g,
+ prefShiftKey: prefShiftKey$g,
+ prefNoKeyShortcuts: prefNoKeyShortcuts$g,
+ escapeKey: escapeKey$g,
+ escapeKeyFunction: escapeKeyFunction$g,
+ prefDescPause: prefDescPause$g,
+ prefDescVisible: prefDescVisible$g,
+ prefDescVoice: prefDescVoice$g,
+ prefDescRate: prefDescRate$g,
+ prefCaptionRate: prefCaptionRate$g,
+ prefDescPitch: prefDescPitch$g,
+ prefDescPitch1: prefDescPitch1$g,
+ prefDescPitch2: prefDescPitch2$g,
+ prefDescPitch3: prefDescPitch3$g,
+ prefDescPitch4: prefDescPitch4$g,
+ prefDescPitch5: prefDescPitch5$g,
+ sampleDescriptionText: sampleDescriptionText$g,
+ prefHighlight: prefHighlight$g,
+ prefTabbable: prefTabbable$g,
+ prefCaptionsFont: prefCaptionsFont$g,
+ prefCaptionsColor: prefCaptionsColor$g,
+ prefCaptionsBGColor: prefCaptionsBGColor$g,
+ prefCaptionsSize: prefCaptionsSize$g,
+ prefCaptionsOpacity: prefCaptionsOpacity$g,
+ prefCaptionsStyle: prefCaptionsStyle$g,
+ serif: serif$g,
+ sans: sans$g,
+ cursive: cursive$g,
+ fantasy: fantasy$g,
+ monospace: monospace$g,
+ white: white$g,
+ yellow: yellow$g,
+ green: green$g,
+ cyan: cyan$f,
+ blue: blue$g,
+ magenta: magenta$g,
+ red: red$g,
+ black: black$g,
+ transparent: transparent$g,
+ solid: solid$g,
+ captionsStylePopOn: captionsStylePopOn$g,
+ captionsStyleRollUp: captionsStyleRollUp$g,
+ prefCaptionsPosition: prefCaptionsPosition$g,
+ captionsPositionOverlay: captionsPositionOverlay$g,
+ captionsPositionBelow: captionsPositionBelow$g,
+ sampleCaptionText: sampleCaptionText$g,
+ prefSuccess: prefSuccess$g,
+ prefNoChange: prefNoChange$g,
+ save: save$g,
+ cancel: cancel$g,
+ dismissButton: dismissButton$g,
+ windowButtonLabel: windowButtonLabel$g,
+ windowMove: windowMove$g,
+ windowMoveLeft: windowMoveLeft$g,
+ windowMoveRight: windowMoveRight$g,
+ windowMoveUp: windowMoveUp$g,
+ windowMoveDown: windowMoveDown$g,
+ windowMoveStopped: windowMoveStopped$g,
+ transcriptControls: transcriptControls$g,
+ signControls: signControls$g,
+ windowMoveAlert: windowMoveAlert$g,
+ windowResize: windowResize$g,
+ windowResizeHeading: windowResizeHeading$g,
+ closeButtonLabel: closeButtonLabel$g,
+ width: width$g,
+ height: height$g,
+ resultsSummary1: resultsSummary1$g,
+ resultsSummary2: resultsSummary2$g,
+ resultsSummary3: resultsSummary3$g,
+ noResultsFound: noResultsFound$g,
+ searchButtonLabel: searchButtonLabel$g,
+ hour: hour$g,
+ minute: minute$g,
+ second: second$g,
+ hours: hours$g,
+ minutes: minutes$g,
+ seconds: seconds$g,
+ vtsHeading: vtsHeading$g,
+ vtsInstructions1: vtsInstructions1$g,
+ vtsInstructions2: vtsInstructions2$g,
+ vtsInstructions3: vtsInstructions3$g,
+ vtsInstructions4: vtsInstructions4$g,
+ vtsInstructions5: vtsInstructions5$g,
+ vtsSelectLanguage: vtsSelectLanguage$g,
+ vtsSave: vtsSave$g,
+ vtsReturn: vtsReturn$g,
+ vtsCancel: vtsCancel$g,
+ vtsRow: vtsRow$g,
+ vtsKind: vtsKind$g,
+ vtsStart: vtsStart$g,
+ vtsEnd: vtsEnd$g,
+ vtsContent: vtsContent$g,
+ vtsActions: vtsActions$g,
+ vtsNewRow: vtsNewRow$g,
+ vtsDeletedRow: vtsDeletedRow$g,
+ vtsMovedRow: vtsMovedRow$g
+ };
- var hours = parseInt(totalSeconds / 3600, 10) % 24;
- var minutes = parseInt(totalSeconds / 60, 10) % 60;
- var seconds = totalSeconds % 60;
- var value = "";
- var title = "";
- if (hours > 0) {
- value += hours + ":";
- if (hours == 1) {
- title += "1 " + this.translate( 'hour', 'hour' ) + " ";
- } else {
- title += hours + " " + this.translate( 'hours', 'hours' ) + " ";
- }
- }
- if (minutes < 10) {
- value += "0" + minutes + ":";
- if (minutes > 0) {
- if (minutes == 1) {
- title += "1 " + this.translate( 'minute', 'minute' ) + " ";
- } else {
- title += minutes + " " + this.translate( 'minutes', 'minutes' ) + " ";
- }
- }
- } else {
- value += minutes + ":";
- title += minutes + " " + this.translate( 'minutes', 'minutes' ) + " ";
- }
- if (seconds < 10) {
- value += "0" + seconds;
- if (seconds > 0) {
- if (seconds == 1) {
- title += "1 " + this.translate( 'second', 'second' ) + " ";
- } else {
- title += seconds + " " + this.translate( 'seconds', 'seconds' ) + " ";
- }
- }
- } else {
- value += seconds;
- title += seconds + " " + this.translate( 'seconds', 'seconds' ) + " ";
- }
- var time = [];
- time["value"] = value;
- time["title"] = title;
- return time;
+ var playerHeading$f = "Media player";
+ var audioPlayer$f = "Audio player";
+ var videoPlayer$f = "Video player";
+ var faster$f = "Rápido";
+ var slower$f = "Lento";
+ var play$f = "Play";
+ var pause$f = "Pausa";
+ var restart$f = "Reiniciar";
+ var prevTrack$f = "Pista Anterior";
+ var nextTrack$f = "Siguiente Pista";
+ var rewind$f = "Rebobinar";
+ var forward$f = "Adelantar";
+ var captions$f = "Subtítulos";
+ var showCaptions$f = "Mostrar subtítulos";
+ var hideCaptions$f = "Ocultar subtítulos";
+ var captionsOff$f = "Sin subtítulos";
+ var showTranscript$f = "Mostrar transcripción";
+ var hideTranscript$f = "Ocultar transcripción";
+ var turnOnDescriptions$f = "Habilitar descripciones";
+ var turnOffDescriptions$f = "Deshabilitar descripciones";
+ var chapters$f = "Capítulos";
+ var language$f = "Idioma";
+ var sign$f = "Lengua de señas";
+ var showSign$f = "Mostrar lengua de señas";
+ var hideSign$f = "Ocultar lengua de señas";
+ var seekbarLabel$f = "timeline";
+ var mute$f = "Silenciar";
+ var unmute$f = "Habilitar sonido";
+ var volume$f = "Volumen";
+ var volumeUpDown$f = "Bajar sonido";
+ var preferences$f = "Preferencias";
+ var enterFullScreen$f = "Ver a pantalla completa";
+ var exitFullScreen$f = "Salir de pantalla completa";
+ var speed$f = "Velocidad";
+ var spacebar$f = "Barra espaciadora";
+ var transcriptTitle$f = "Transcript";
+ var lyricsTitle$f = "Letra";
+ var autoScroll$f = "Desplazamiento automático";
+ var statusPlaying$f = "Reproduciendo";
+ var statusPaused$f = "Pausado";
+ var statusStopped$f = "Detenido";
+ var statusBuffering$f = "Almacenando";
+ var statusEnd$f = "Fin de pista";
+ var selectedTrack$e = "Pista seleccionada";
+ var alertDescribedVersion$f = "Utilizando la versión audiodescrita del vídeo";
+ var alertNonDescribedVersion$f = "Utilizando la versión no descrita de este vídeo";
+ var prefMenuCaptions$f = "Subtítulos";
+ var prefVoicedCaptions$f = "Spoken Captions";
+ var prefMenuDescriptions$f = "Descripciones";
+ var prefMenuKeyboard$f = "Teclado";
+ var prefMenuTranscript$f = "Transcripción";
+ var prefTitleCaptions$f = "Preferencias de subtítulos";
+ var prefTitleDescriptions$f = "Preferencias de audiodescripción";
+ var prefTitleKeyboard$f = "Preferencias de teclado";
+ var prefTitleTranscript$e = "Preferencias de transcripción";
+ var prefIntroDescription1$e = "Este reproductor soporta la audiodescripción de dos maneras: ";
+ var prefDescription1$f = "El vídeo actual tiene una versión alternativa con descripción, descripción en texto.";
+ var prefDescription2$f = "El vídeo actual tiene versión alternativa del vídeo, descrito.";
+ var prefDescription3$f = "El vídeo actual tiene descripción en texto, leída por el lector de pantalla.";
+ var prefIntroDescriptionNone$f = "El vídeo actual no tiene audiodescripción de ninguna manera.";
+ var prefIntroDescription3$f = "Utilice el siguiente formulario para establecer sus preferencias en cuanto a la audiodescripción en texto.";
+ var prefIntroDescription4$f = "Una vez guardadas sus preferencias, la audiodescripción puede habilitarse o deshabilitarse mediante el botón Descripción.";
+ var prefIntroKeyboard1$f = "El reproductor en esta página puede manejarse desde cualquier parte de la página utilizando los atajos de teclado (vea la lista más abajo).";
+ var prefIntroKeyboard2$f = "Las teclas modificadoras (Mayúsculas, Alt, Control) pueden definirse más abajo.";
+ var prefIntroKeyboard3$f = "NOTA: Algunas combinaciones de teclas pueden entrar en conflicto con teclas utilizadas por su navegador y/o otras aplicaciones. Intente varias combinaciones de teclas modificadoras para encontrar la que funciona bien en su caso.";
+ var prefHeadingKeyboard1$f = "Teclas modificadoras utilizadas para atajos de teclado";
+ var prefHeadingKeyboard2$f = "Atajos de teclado definidos actualmente";
+ var prefHeadingDescription$f = "Audiodescrita";
+ var prefHeadingTextDescription$f = "Audiodescrita en texto";
+ var prefAltKey$f = "Alt";
+ var prefCtrlKey$f = "Control";
+ var prefShiftKey$f = "Mayúsculas";
+ var prefNoKeyShortcuts$f = "Disable keyboard shortcuts";
+ var escapeKey$f = "Escape";
+ var escapeKeyFunction$f = "Cerrar el cuadro de diálogo o menú contextual";
+ var prefDescPause$f = "Pausar automáticamente el video cuando arranque una descripción";
+ var prefDescVisible$f = "Hacer visibles las descripciones en texto si se están usando";
+ var prefDescVoice$f = "Voz";
+ var prefDescRate$f = "Spoken Description Rate";
+ var prefCaptionRate$f = "Spoken Caption Rate";
+ var prefDescPitch$f = "Tono";
+ var prefDescPitch1$f = "Muy grave";
+ var prefDescPitch2$f = "Grave";
+ var prefDescPitch3$f = "Normal";
+ var prefDescPitch4$f = "Aguda";
+ var prefDescPitch5$f = "Muy aguda";
+ var sampleDescriptionText$f = "Ajuste la configuración para escuchar este texto de muestra";
+ var prefHighlight$f = "Resalte la transcripción a medida que avance el contenido";
+ var prefTabbable$f = "Transcripción manejable por teclado";
+ var prefCaptionsFont$f = "Fuente";
+ var prefCaptionsColor$f = "Color del texto";
+ var prefCaptionsBGColor$f = "Fondo";
+ var prefCaptionsSize$f = "Tamaño de Fuente";
+ var prefCaptionsOpacity$f = "Opacidad";
+ var prefCaptionsStyle$f = "Estilo";
+ var serif$f = "serif";
+ var sans$f = "sans-serif";
+ var cursive$f = "cursiva";
+ var fantasy$f = "fantasía";
+ var monospace$f = "mono espaciada";
+ var white$f = "blanco";
+ var yellow$f = "amarillo";
+ var green$f = "verde";
+ var cyan$e = "cyan";
+ var blue$f = "azul";
+ var magenta$f = "magenta";
+ var red$f = "rojo";
+ var black$f = "negro";
+ var transparent$f = "transparente";
+ var solid$f = "sólido";
+ var captionsStylePopOn$f = "Pop-on";
+ var captionsStyleRollUp$f = "Roll-up";
+ var prefCaptionsPosition$f = "Posición";
+ var captionsPositionOverlay$f = "Cubrir";
+ var captionsPositionBelow$f = "Debajo del vídeo";
+ var sampleCaptionText$f = "Texto de ejemplo de subtítulo";
+ var prefSuccess$f = "Los cambios han sido guardados.";
+ var prefNoChange$f = "No se ha hecho ningún cambio.";
+ var save$f = "Guardar";
+ var cancel$f = "Cancelar";
+ var dismissButton$f = "Dismiss";
+ var windowButtonLabel$f = "Opciones en Windows";
+ var windowMove$f = "Mover";
+ var windowMoveLeft$f = "Window moved left";
+ var windowMoveRight$f = "Window moved right";
+ var windowMoveUp$f = "Window moved up";
+ var windowMoveDown$f = "Window moved down";
+ var windowMoveStopped$f = "Window move stopped";
+ var transcriptControls$f = "Transcript Window Controls";
+ var signControls$f = "Sign Language Window Controls";
+ var windowMoveAlert$f = "Arrastre o use las teclas de flecha para mover la ventana, pulse Enter para parar.";
+ var windowResize$f = "Redimensionar";
+ var windowResizeHeading$f = "Redimensionar la ventana con el intérprete";
+ var closeButtonLabel$f = "Cerrar";
+ var width$f = "Ancho";
+ var height$f = "Alto";
+ var resultsSummary1$f = "You searched for:";
+ var resultsSummary2$f = "Found %1 matching items.";
+ var resultsSummary3$f = "Click the time associated with any item to play the video from that point.";
+ var noResultsFound$f = "No results found.";
+ var searchButtonLabel$f = "Play at %1";
+ var hour$f = "hour";
+ var minute$f = "minute";
+ var second$f = "second";
+ var hours$f = "hours";
+ var minutes$f = "minutes";
+ var seconds$f = "seconds";
+ var vtsHeading$f = "Video Transcript Sorter";
+ var vtsInstructions1$f = "Use the Video Transcript Sorter to modify text tracks:";
+ var vtsInstructions2$f = "Reorder chapters, descriptions, captions, and/or subtitles so they appear in the proper sequence in Able Player's auto-generated transcript.";
+ var vtsInstructions3$f = "Modify content or start/end times (all are directly editable within the table).";
+ var vtsInstructions4$f = "Add new content, such as chapters or descriptions.";
+ var vtsInstructions5$f = "After editing, click the \"Save Changes\" button to generate new content for all relevant timed text files. The new text can be copied and pasted into new WebVTT files.";
+ var vtsSelectLanguage$f = "Select a language";
+ var vtsSave$f = "Generate new .vtt content";
+ var vtsReturn$f = "Return to Editor";
+ var vtsCancel$f = "Cancelling saving. Any edits you made have been restored in the VTS table.";
+ var vtsRow$f = "Row";
+ var vtsKind$f = "Kind";
+ var vtsStart$f = "Start";
+ var vtsEnd$f = "End";
+ var vtsContent$f = "Content";
+ var vtsActions$f = "Actions";
+ var vtsNewRow$f = "A new row %1 has been inserted.";
+ var vtsDeletedRow$f = "Row %1 has been deleted.";
+ var vtsMovedRow$f = "Row %1 has been moved %2 and is now Row %3.";
+ var es = {
+ playerHeading: playerHeading$f,
+ audioPlayer: audioPlayer$f,
+ videoPlayer: videoPlayer$f,
+ faster: faster$f,
+ slower: slower$f,
+ play: play$f,
+ pause: pause$f,
+ restart: restart$f,
+ prevTrack: prevTrack$f,
+ nextTrack: nextTrack$f,
+ rewind: rewind$f,
+ forward: forward$f,
+ captions: captions$f,
+ showCaptions: showCaptions$f,
+ hideCaptions: hideCaptions$f,
+ captionsOff: captionsOff$f,
+ showTranscript: showTranscript$f,
+ hideTranscript: hideTranscript$f,
+ turnOnDescriptions: turnOnDescriptions$f,
+ turnOffDescriptions: turnOffDescriptions$f,
+ chapters: chapters$f,
+ language: language$f,
+ sign: sign$f,
+ showSign: showSign$f,
+ hideSign: hideSign$f,
+ seekbarLabel: seekbarLabel$f,
+ mute: mute$f,
+ unmute: unmute$f,
+ volume: volume$f,
+ volumeUpDown: volumeUpDown$f,
+ preferences: preferences$f,
+ enterFullScreen: enterFullScreen$f,
+ exitFullScreen: exitFullScreen$f,
+ speed: speed$f,
+ spacebar: spacebar$f,
+ transcriptTitle: transcriptTitle$f,
+ lyricsTitle: lyricsTitle$f,
+ autoScroll: autoScroll$f,
+ statusPlaying: statusPlaying$f,
+ statusPaused: statusPaused$f,
+ statusStopped: statusStopped$f,
+ statusBuffering: statusBuffering$f,
+ statusEnd: statusEnd$f,
+ selectedTrack: selectedTrack$e,
+ alertDescribedVersion: alertDescribedVersion$f,
+ alertNonDescribedVersion: alertNonDescribedVersion$f,
+ prefMenuCaptions: prefMenuCaptions$f,
+ prefVoicedCaptions: prefVoicedCaptions$f,
+ prefMenuDescriptions: prefMenuDescriptions$f,
+ prefMenuKeyboard: prefMenuKeyboard$f,
+ prefMenuTranscript: prefMenuTranscript$f,
+ prefTitleCaptions: prefTitleCaptions$f,
+ prefTitleDescriptions: prefTitleDescriptions$f,
+ prefTitleKeyboard: prefTitleKeyboard$f,
+ prefTitleTranscript: prefTitleTranscript$e,
+ prefIntroDescription1: prefIntroDescription1$e,
+ prefDescription1: prefDescription1$f,
+ prefDescription2: prefDescription2$f,
+ prefDescription3: prefDescription3$f,
+ prefIntroDescriptionNone: prefIntroDescriptionNone$f,
+ prefIntroDescription3: prefIntroDescription3$f,
+ prefIntroDescription4: prefIntroDescription4$f,
+ prefIntroKeyboard1: prefIntroKeyboard1$f,
+ prefIntroKeyboard2: prefIntroKeyboard2$f,
+ prefIntroKeyboard3: prefIntroKeyboard3$f,
+ prefHeadingKeyboard1: prefHeadingKeyboard1$f,
+ prefHeadingKeyboard2: prefHeadingKeyboard2$f,
+ prefHeadingDescription: prefHeadingDescription$f,
+ prefHeadingTextDescription: prefHeadingTextDescription$f,
+ prefAltKey: prefAltKey$f,
+ prefCtrlKey: prefCtrlKey$f,
+ prefShiftKey: prefShiftKey$f,
+ prefNoKeyShortcuts: prefNoKeyShortcuts$f,
+ escapeKey: escapeKey$f,
+ escapeKeyFunction: escapeKeyFunction$f,
+ prefDescPause: prefDescPause$f,
+ prefDescVisible: prefDescVisible$f,
+ prefDescVoice: prefDescVoice$f,
+ prefDescRate: prefDescRate$f,
+ prefCaptionRate: prefCaptionRate$f,
+ prefDescPitch: prefDescPitch$f,
+ prefDescPitch1: prefDescPitch1$f,
+ prefDescPitch2: prefDescPitch2$f,
+ prefDescPitch3: prefDescPitch3$f,
+ prefDescPitch4: prefDescPitch4$f,
+ prefDescPitch5: prefDescPitch5$f,
+ sampleDescriptionText: sampleDescriptionText$f,
+ prefHighlight: prefHighlight$f,
+ prefTabbable: prefTabbable$f,
+ prefCaptionsFont: prefCaptionsFont$f,
+ prefCaptionsColor: prefCaptionsColor$f,
+ prefCaptionsBGColor: prefCaptionsBGColor$f,
+ prefCaptionsSize: prefCaptionsSize$f,
+ prefCaptionsOpacity: prefCaptionsOpacity$f,
+ prefCaptionsStyle: prefCaptionsStyle$f,
+ serif: serif$f,
+ sans: sans$f,
+ cursive: cursive$f,
+ fantasy: fantasy$f,
+ monospace: monospace$f,
+ white: white$f,
+ yellow: yellow$f,
+ green: green$f,
+ cyan: cyan$e,
+ blue: blue$f,
+ magenta: magenta$f,
+ red: red$f,
+ black: black$f,
+ transparent: transparent$f,
+ solid: solid$f,
+ captionsStylePopOn: captionsStylePopOn$f,
+ captionsStyleRollUp: captionsStyleRollUp$f,
+ prefCaptionsPosition: prefCaptionsPosition$f,
+ captionsPositionOverlay: captionsPositionOverlay$f,
+ captionsPositionBelow: captionsPositionBelow$f,
+ sampleCaptionText: sampleCaptionText$f,
+ prefSuccess: prefSuccess$f,
+ prefNoChange: prefNoChange$f,
+ save: save$f,
+ cancel: cancel$f,
+ dismissButton: dismissButton$f,
+ windowButtonLabel: windowButtonLabel$f,
+ windowMove: windowMove$f,
+ windowMoveLeft: windowMoveLeft$f,
+ windowMoveRight: windowMoveRight$f,
+ windowMoveUp: windowMoveUp$f,
+ windowMoveDown: windowMoveDown$f,
+ windowMoveStopped: windowMoveStopped$f,
+ transcriptControls: transcriptControls$f,
+ signControls: signControls$f,
+ windowMoveAlert: windowMoveAlert$f,
+ windowResize: windowResize$f,
+ windowResizeHeading: windowResizeHeading$f,
+ closeButtonLabel: closeButtonLabel$f,
+ width: width$f,
+ height: height$f,
+ resultsSummary1: resultsSummary1$f,
+ resultsSummary2: resultsSummary2$f,
+ resultsSummary3: resultsSummary3$f,
+ noResultsFound: noResultsFound$f,
+ searchButtonLabel: searchButtonLabel$f,
+ hour: hour$f,
+ minute: minute$f,
+ second: second$f,
+ hours: hours$f,
+ minutes: minutes$f,
+ seconds: seconds$f,
+ vtsHeading: vtsHeading$f,
+ vtsInstructions1: vtsInstructions1$f,
+ vtsInstructions2: vtsInstructions2$f,
+ vtsInstructions3: vtsInstructions3$f,
+ vtsInstructions4: vtsInstructions4$f,
+ vtsInstructions5: vtsInstructions5$f,
+ vtsSelectLanguage: vtsSelectLanguage$f,
+ vtsSave: vtsSave$f,
+ vtsReturn: vtsReturn$f,
+ vtsCancel: vtsCancel$f,
+ vtsRow: vtsRow$f,
+ vtsKind: vtsKind$f,
+ vtsStart: vtsStart$f,
+ vtsEnd: vtsEnd$f,
+ vtsContent: vtsContent$f,
+ vtsActions: vtsActions$f,
+ vtsNewRow: vtsNewRow$f,
+ vtsDeletedRow: vtsDeletedRow$f,
+ vtsMovedRow: vtsMovedRow$f
+ };
+
+ var playerHeading$e = "Lecteur multimédia";
+ var audioPlayer$e = "Audio player";
+ var videoPlayer$e = "Video player";
+ var faster$e = "Plus rapidement";
+ var slower$e = "Plus lentement";
+ var play$e = "Lecture";
+ var pause$e = "Pause";
+ var restart$e = "Redémarrer";
+ var prevTrack$e = "Piste Précédente";
+ var nextTrack$e = "Piste Suivante";
+ var rewind$e = "Reculer";
+ var forward$e = "Avancer";
+ var captions$e = "Sous-titres";
+ var showCaptions$e = "Afficher les sous-titres";
+ var hideCaptions$e = "Masquer les sous-titres";
+ var captionsOff$e = "Sous-titres désactivés";
+ var showTranscript$e = "Afficher la transcription";
+ var hideTranscript$e = "Masquer la transcription";
+ var turnOnDescriptions$e = "Activer les descriptions";
+ var turnOffDescriptions$e = "Désactiver les descriptions";
+ var chapters$e = "Chapitres";
+ var language$e = "Langue";
+ var sign$e = "Langage gestuel";
+ var showSign$e = "Afficher le langage gestuel";
+ var hideSign$e = "Masque le langage gestuel";
+ var seekbarLabel$e = "timeline";
+ var mute$e = "Son désactivé";
+ var unmute$e = "Son activé";
+ var volume$e = "Volume";
+ var volumeUpDown$e = "Monter baisser le volume";
+ var preferences$e = "Préférences";
+ var enterFullScreen$e = "Activer le mode plein écran";
+ var exitFullScreen$e = "Quitter le mode plein écran";
+ var speed$e = "Vitesse";
+ var spacebar$e = "barre d’espacement";
+ var transcriptTitle$e = "Transcription";
+ var lyricsTitle$e = "Paroles";
+ var autoScroll$e = "Défilement automatique";
+ var statusPlaying$e = "Lecture en cours";
+ var statusPaused$e = "Lecture sur pause";
+ var statusStopped$e = "Lecture interrompue";
+ var statusBuffering$e = "Tamponnage";
+ var statusEnd$e = "Fin de la piste";
+ var selectedTrack$d = "Piste choisie";
+ var alertDescribedVersion$e = "Utilisation de la version avec description sonore de cette vidéo";
+ var alertNonDescribedVersion$e = "Utilisation de la version non décrite de cette vidéo";
+ var prefMenuCaptions$e = "Sous-titres";
+ var prefVoicedCaptions$e = "Spoken Captions";
+ var prefMenuDescriptions$e = "Descriptions";
+ var prefMenuKeyboard$e = "Clavier";
+ var prefMenuTranscript$e = "Transcription";
+ var prefTitleCaptions$e = "Préférences liées au sous-titrage";
+ var prefTitleDescriptions$e = "Préférences liées aux descriptions sonores";
+ var prefTitleKeyboard$e = "Préférences liées au clavier";
+ var prefTitleTranscript$d = "Préférence liées à la transcription";
+ var prefIntroDescription1$d = "Ce lecteur multimédia permet d’entendre les descriptions sonores de deux façons:";
+ var prefDescription1$e = "Il y a une version autre version avec description, description textuelle.";
+ var prefDescription2$e = "Il y a une version autre version de la vidéo avec description.";
+ var prefDescription3$e = "Il y a une version description textuelle, lue à l’aide d’un lecteur d’écran.";
+ var prefIntroDescriptionNone$e = "Il n’y a pas de version avec description sonore (dans ni l’un ni l’autre des formats) de la présente vidéo.";
+ var prefIntroDescription3$e = "Utilisez le formulaire suivant pour établir vos préférences liées aux descriptions sonores textuelle.";
+ var prefIntroDescription4$e = "Après avoir enregistré vos préférences, vous pouvez activer ou désactiver la description sonore avec le bouton Description.";
+ var prefIntroKeyboard1$e = "Le lecteur multimédia de cette page Web peut être utilisé à partir de n’importe quel endroit sur la page avec des raccourcis du clavier (voir la liste ci-dessous).";
+ var prefIntroKeyboard2$e = "Des rôles peuvent être assignés aux touches de modification (Shift, Alt, Ctrl) ci-dessous.";
+ var prefIntroKeyboard3$e = "Certaines combinaisons de touches pourraient entrer en conflit avec les touches utilisées par votre navigateur ou autres applications logicielles. Essayez diverses combinaisons de touches de modification pour en trouver qui fonctionnent pour vous.";
+ var prefHeadingKeyboard1$e = "Touches de modification utilisées pour des raccourcis";
+ var prefHeadingKeyboard2$e = "Raccourcis du clavier assignés actuellement";
+ var prefHeadingDescription$e = "Description sonore";
+ var prefHeadingTextDescription$e = "Description sonore textuelle";
+ var prefAltKey$e = "Alt";
+ var prefCtrlKey$e = "Ctrl";
+ var prefShiftKey$e = "Shift";
+ var prefNoKeyShortcuts$e = "Disable keyboard shortcuts";
+ var escapeKey$e = "Esc";
+ var escapeKeyFunction$e = "Fermer la fenêtre de dialogue ou le menu contextuel";
+ var prefDescPause$e = "Mettre la vidéo en pause automatiquement quand la description commence";
+ var prefDescVisible$e = "Affichez la description";
+ var prefDescVoice$e = "Voix";
+ var prefDescRate$e = "Spoken Description Rate";
+ var prefCaptionRate$e = "Spoken Caption Rate";
+ var prefDescPitch$e = "Volume";
+ var prefDescPitch1$e = "Très faible";
+ var prefDescPitch2$e = "Faible";
+ var prefDescPitch3$e = "Par défaut";
+ var prefDescPitch4$e = "Fort";
+ var prefDescPitch5$e = "Très fort";
+ var sampleDescriptionText$e = "Régler les paramètres afin d'entendre cet extrait de texte";
+ var prefHighlight$e = "Surligner la transcription pendant la lecture";
+ var prefTabbable$e = "Transcription activée par clavier";
+ var prefCaptionsFont$e = "Police de caractères";
+ var prefCaptionsColor$e = "Couleur du texte";
+ var prefCaptionsBGColor$e = "Arrière-plan";
+ var prefCaptionsSize$e = "Taille de la police";
+ var prefCaptionsOpacity$e = "Opacité";
+ var prefCaptionsStyle$e = "Style";
+ var serif$e = "avec empattement";
+ var sans$e = "sans empattement";
+ var cursive$e = "écriture cursive";
+ var fantasy$e = "écriture de fantaisie";
+ var monospace$e = "à taille fixe";
+ var white$e = "blanc";
+ var yellow$e = "jaune";
+ var green$e = "vert";
+ var cyan$d = "cyan";
+ var blue$e = "bleu";
+ var magenta$e = "magenta";
+ var red$e = "rouge";
+ var black$e = "noir";
+ var transparent$e = "transparent";
+ var solid$e = "solide";
+ var captionsStylePopOn$e = "Pop-on";
+ var captionsStyleRollUp$e = "Roll-up";
+ var prefCaptionsPosition$e = "Position";
+ var captionsPositionOverlay$e = "Superposés";
+ var captionsPositionBelow$e = "Sous la vidéo";
+ var sampleCaptionText$e = "Échantillon de sous-titre";
+ var prefSuccess$e = "Vos changements ont été enregistrés.";
+ var prefNoChange$e = "Vous n’avez pas fait de changements.";
+ var save$e = "Enregistrer";
+ var cancel$e = "Annuler";
+ var dismissButton$e = "Dismiss";
+ var windowButtonLabel$e = "Options de fenêtre";
+ var windowMove$e = "Déplacer";
+ var windowMoveLeft$e = "Window moved left";
+ var windowMoveRight$e = "Window moved right";
+ var windowMoveUp$e = "Window moved up";
+ var windowMoveDown$e = "Window moved down";
+ var windowMoveStopped$e = "Window move stopped";
+ var transcriptControls$e = "Transcript Window Controls";
+ var signControls$e = "Sign Language Window Controls";
+ var windowMoveAlert$e = "Faites glisser avec la souris ou utilisez les touches fléchées pour déplacer la fenêtre; appuyez sur « Enter » pour arrêter.";
+ var windowResize$e = "Redimensionner";
+ var windowResizeHeading$e = "Redimensionner la fenêtre de l’interprète";
+ var closeButtonLabel$e = "Fermer";
+ var width$e = "Largeur";
+ var height$e = "Hauteur";
+ var resultsSummary1$e = "Vos résultats de recherche";
+ var resultsSummary2$e = "Trouvé %1 éléments correspondants.";
+ var resultsSummary3$e = "Cliquez sur le temps associé à n'importe quel élément pour lire la vidéo à partir de ce point.";
+ var noResultsFound$e = "Aucun résultat trouvé.";
+ var searchButtonLabel$e = "Lecture à %1";
+ var hour$e = "heure";
+ var minute$e = "minute";
+ var second$e = "seconde";
+ var hours$e = "heures";
+ var minutes$e = "minutes";
+ var seconds$e = "seconds";
+ var vtsHeading$e = "Video Transcript Sorter";
+ var vtsInstructions1$e = "Use the Video Transcript Sorter to modify text tracks:";
+ var vtsInstructions2$e = "Reorder chapters, descriptions, captions, and/or subtitles so they appear in the proper sequence in Able Player's auto-generated transcript.";
+ var vtsInstructions3$e = "Modify content or start/end times (all are directly editable within the table).";
+ var vtsInstructions4$e = "Add new content, such as chapters or descriptions.";
+ var vtsInstructions5$e = "After editing, click the \"Save Changes\" button to generate new content for all relevant timed text files. The new text can be copied and pasted into new WebVTT files.";
+ var vtsSelectLanguage$e = "Select a language";
+ var vtsSave$e = "Generate new .vtt content";
+ var vtsReturn$e = "Return to Editor";
+ var vtsCancel$e = "Cancelling saving. Any edits you made have been restored in the VTS table.";
+ var vtsRow$e = "Row";
+ var vtsKind$e = "Kind";
+ var vtsStart$e = "Start";
+ var vtsEnd$e = "End";
+ var vtsContent$e = "Content";
+ var vtsActions$e = "Actions";
+ var vtsNewRow$e = "A new row %1 has been inserted.";
+ var vtsDeletedRow$e = "Row %1 has been deleted.";
+ var vtsMovedRow$e = "Row %1 has been moved %2 and is now Row %3.";
+ var fr = {
+ playerHeading: playerHeading$e,
+ audioPlayer: audioPlayer$e,
+ videoPlayer: videoPlayer$e,
+ faster: faster$e,
+ slower: slower$e,
+ play: play$e,
+ pause: pause$e,
+ restart: restart$e,
+ prevTrack: prevTrack$e,
+ nextTrack: nextTrack$e,
+ rewind: rewind$e,
+ forward: forward$e,
+ captions: captions$e,
+ showCaptions: showCaptions$e,
+ hideCaptions: hideCaptions$e,
+ captionsOff: captionsOff$e,
+ showTranscript: showTranscript$e,
+ hideTranscript: hideTranscript$e,
+ turnOnDescriptions: turnOnDescriptions$e,
+ turnOffDescriptions: turnOffDescriptions$e,
+ chapters: chapters$e,
+ language: language$e,
+ sign: sign$e,
+ showSign: showSign$e,
+ hideSign: hideSign$e,
+ seekbarLabel: seekbarLabel$e,
+ mute: mute$e,
+ unmute: unmute$e,
+ volume: volume$e,
+ volumeUpDown: volumeUpDown$e,
+ preferences: preferences$e,
+ enterFullScreen: enterFullScreen$e,
+ exitFullScreen: exitFullScreen$e,
+ speed: speed$e,
+ spacebar: spacebar$e,
+ transcriptTitle: transcriptTitle$e,
+ lyricsTitle: lyricsTitle$e,
+ autoScroll: autoScroll$e,
+ statusPlaying: statusPlaying$e,
+ statusPaused: statusPaused$e,
+ statusStopped: statusStopped$e,
+ statusBuffering: statusBuffering$e,
+ statusEnd: statusEnd$e,
+ selectedTrack: selectedTrack$d,
+ alertDescribedVersion: alertDescribedVersion$e,
+ alertNonDescribedVersion: alertNonDescribedVersion$e,
+ prefMenuCaptions: prefMenuCaptions$e,
+ prefVoicedCaptions: prefVoicedCaptions$e,
+ prefMenuDescriptions: prefMenuDescriptions$e,
+ prefMenuKeyboard: prefMenuKeyboard$e,
+ prefMenuTranscript: prefMenuTranscript$e,
+ prefTitleCaptions: prefTitleCaptions$e,
+ prefTitleDescriptions: prefTitleDescriptions$e,
+ prefTitleKeyboard: prefTitleKeyboard$e,
+ prefTitleTranscript: prefTitleTranscript$d,
+ prefIntroDescription1: prefIntroDescription1$d,
+ prefDescription1: prefDescription1$e,
+ prefDescription2: prefDescription2$e,
+ prefDescription3: prefDescription3$e,
+ prefIntroDescriptionNone: prefIntroDescriptionNone$e,
+ prefIntroDescription3: prefIntroDescription3$e,
+ prefIntroDescription4: prefIntroDescription4$e,
+ prefIntroKeyboard1: prefIntroKeyboard1$e,
+ prefIntroKeyboard2: prefIntroKeyboard2$e,
+ prefIntroKeyboard3: prefIntroKeyboard3$e,
+ prefHeadingKeyboard1: prefHeadingKeyboard1$e,
+ prefHeadingKeyboard2: prefHeadingKeyboard2$e,
+ prefHeadingDescription: prefHeadingDescription$e,
+ prefHeadingTextDescription: prefHeadingTextDescription$e,
+ prefAltKey: prefAltKey$e,
+ prefCtrlKey: prefCtrlKey$e,
+ prefShiftKey: prefShiftKey$e,
+ prefNoKeyShortcuts: prefNoKeyShortcuts$e,
+ escapeKey: escapeKey$e,
+ escapeKeyFunction: escapeKeyFunction$e,
+ prefDescPause: prefDescPause$e,
+ prefDescVisible: prefDescVisible$e,
+ prefDescVoice: prefDescVoice$e,
+ prefDescRate: prefDescRate$e,
+ prefCaptionRate: prefCaptionRate$e,
+ prefDescPitch: prefDescPitch$e,
+ prefDescPitch1: prefDescPitch1$e,
+ prefDescPitch2: prefDescPitch2$e,
+ prefDescPitch3: prefDescPitch3$e,
+ prefDescPitch4: prefDescPitch4$e,
+ prefDescPitch5: prefDescPitch5$e,
+ sampleDescriptionText: sampleDescriptionText$e,
+ prefHighlight: prefHighlight$e,
+ prefTabbable: prefTabbable$e,
+ prefCaptionsFont: prefCaptionsFont$e,
+ prefCaptionsColor: prefCaptionsColor$e,
+ prefCaptionsBGColor: prefCaptionsBGColor$e,
+ prefCaptionsSize: prefCaptionsSize$e,
+ prefCaptionsOpacity: prefCaptionsOpacity$e,
+ prefCaptionsStyle: prefCaptionsStyle$e,
+ serif: serif$e,
+ sans: sans$e,
+ cursive: cursive$e,
+ fantasy: fantasy$e,
+ monospace: monospace$e,
+ white: white$e,
+ yellow: yellow$e,
+ green: green$e,
+ cyan: cyan$d,
+ blue: blue$e,
+ magenta: magenta$e,
+ red: red$e,
+ black: black$e,
+ transparent: transparent$e,
+ solid: solid$e,
+ captionsStylePopOn: captionsStylePopOn$e,
+ captionsStyleRollUp: captionsStyleRollUp$e,
+ prefCaptionsPosition: prefCaptionsPosition$e,
+ captionsPositionOverlay: captionsPositionOverlay$e,
+ captionsPositionBelow: captionsPositionBelow$e,
+ sampleCaptionText: sampleCaptionText$e,
+ prefSuccess: prefSuccess$e,
+ prefNoChange: prefNoChange$e,
+ save: save$e,
+ cancel: cancel$e,
+ dismissButton: dismissButton$e,
+ windowButtonLabel: windowButtonLabel$e,
+ windowMove: windowMove$e,
+ windowMoveLeft: windowMoveLeft$e,
+ windowMoveRight: windowMoveRight$e,
+ windowMoveUp: windowMoveUp$e,
+ windowMoveDown: windowMoveDown$e,
+ windowMoveStopped: windowMoveStopped$e,
+ transcriptControls: transcriptControls$e,
+ signControls: signControls$e,
+ windowMoveAlert: windowMoveAlert$e,
+ windowResize: windowResize$e,
+ windowResizeHeading: windowResizeHeading$e,
+ closeButtonLabel: closeButtonLabel$e,
+ width: width$e,
+ height: height$e,
+ resultsSummary1: resultsSummary1$e,
+ resultsSummary2: resultsSummary2$e,
+ resultsSummary3: resultsSummary3$e,
+ noResultsFound: noResultsFound$e,
+ searchButtonLabel: searchButtonLabel$e,
+ hour: hour$e,
+ minute: minute$e,
+ second: second$e,
+ hours: hours$e,
+ minutes: minutes$e,
+ seconds: seconds$e,
+ vtsHeading: vtsHeading$e,
+ vtsInstructions1: vtsInstructions1$e,
+ vtsInstructions2: vtsInstructions2$e,
+ vtsInstructions3: vtsInstructions3$e,
+ vtsInstructions4: vtsInstructions4$e,
+ vtsInstructions5: vtsInstructions5$e,
+ vtsSelectLanguage: vtsSelectLanguage$e,
+ vtsSave: vtsSave$e,
+ vtsReturn: vtsReturn$e,
+ vtsCancel: vtsCancel$e,
+ vtsRow: vtsRow$e,
+ vtsKind: vtsKind$e,
+ vtsStart: vtsStart$e,
+ vtsEnd: vtsEnd$e,
+ vtsContent: vtsContent$e,
+ vtsActions: vtsActions$e,
+ vtsNewRow: vtsNewRow$e,
+ vtsDeletedRow: vtsDeletedRow$e,
+ vtsMovedRow: vtsMovedRow$e
+ };
+
+ var playerHeading$d = "נגן מדיה";
+ var audioPlayer$d = "Audio player";
+ var videoPlayer$d = "Video player";
+ var faster$d = "מהר יותר";
+ var slower$d = "לאט יותר";
+ var play$d = "נגן";
+ var pause$d = "הפסקה";
+ var restart$d = "התחלה מחדש";
+ var prevTrack$d = "המסלול הקודם";
+ var nextTrack$d = "המסלול הבא";
+ var rewind$d = "חזרה";
+ var forward$d = "קדימה";
+ var captions$d = "כיתובים";
+ var showCaptions$d = "הצגת כיתובים";
+ var hideCaptions$d = "הסתרת כיתובים";
+ var captionsOff$d = "ללא כיתובים";
+ var showTranscript$d = "הצג תמליל";
+ var hideTranscript$d = "הסתר תמליל";
+ var turnOnDescriptions$d = "הפעל תמליל";
+ var turnOffDescriptions$d = "סגור תמליל";
+ var chapters$d = "פרקים";
+ var language$d = "שפה";
+ var sign$d = "שפת סימנים";
+ var showSign$d = "הצג שפת סימנים";
+ var hideSign$d = "הסתר שפת סימנים";
+ var seekbarLabel$d = "ציר זמן";
+ var mute$d = "השתקה";
+ var unmute$d = "הפסקת השתקה";
+ var volume$d = "עצמה";
+ var volumeUpDown$d = "Volume up down";
+ var preferences$d = "העדפות";
+ var enterFullScreen$d = "מעבר למסך מלא";
+ var exitFullScreen$d = "יציאה ממסך מלא";
+ var speed$d = "מהירות";
+ var spacebar$d = "מקש הרווח";
+ var transcriptTitle$d = "תמליל";
+ var lyricsTitle$d = "מילים";
+ var autoScroll$d = "גלילה אוטומטית";
+ var statusPlaying$d = "מנגן";
+ var statusPaused$d = "מופסק";
+ var statusStopped$d = "נעצר";
+ var statusBuffering$d = "חציצה";
+ var statusEnd$d = "סוף המסלול";
+ var selectTrack = "מסלול נבחר";
+ var alertDescribedVersion$d = "שימוש בגירסת אודיו המתוארת של סרטון זה";
+ var alertNonDescribedVersion$d = "שימוש בגרסה הלא מתוארת של סרטון זה";
+ var prefMenuCaptions$d = "כיתובים";
+ var prefVoicedCaptions$d = "Spoken Captions";
+ var prefMenuDescriptions$d = "תיאורים";
+ var prefMenuKeyboard$d = "מקלדת";
+ var prefMenuTranscript$d = "תמליל";
+ var prefTitleCaptions$d = "העדפות כיתובים";
+ var prefTitleDescriptions$d = "העדפות תיאור שמע";
+ var prefTitleKeyboard$d = "העדפות מקלדת";
+ var PrefTitleTranscript = "העדפות תמליל";
+ var prefIntrodescription1 = "נגן המדיה תומך בתיאור השמע בשתי דרכים:";
+ var prefDescription1$d = "הווידאו הנוכחי יש גרסה חלופית המתוארתתיאור מבוסס טקסט";
+ var prefDescription2$d = "הווידאו הנוכחי ישגרסה חלופית המתוארת של וידאו";
+ var prefDescription3$d = "הווידאו הנוכחי יש תיאור מבוסס טקסט, הודיעה על ידי קורא מסך";
+ var prefIntroDescriptionNone$d = "לסרטון הנוכחי אין תיאור שמע בתבנית.";
+ var prefIntroDescription3$d = "השתמש בטופס הבא כדי לקבוע את ההעדפות שלך הקשורות לתיאור שמע.";
+ var prefIntroDescription4$d = "לאחר שתשמור את ההגדרות שלך, תיאור השמע יכול להיות מוחל על / כיבוי באמצעות לחצן תיאור.";
+ var prefIntroKeyboard1$d = "נגן המדיה בדף אינטרנט זה יכול להיות מופעל מכל מקום בדף באמצעות קיצורי מקשים (ראה להלן רשימה).";
+ var prefIntroKeyboard2$d = "ניתן לשנות את מקשי השינוי (Shift, Alt ו- Control).";
+ var prefIntroKeyboard3$d = "הערה: ייתכן שחלק מצירופי המקשים מתנגשים עם המקשים המשמשים את הדפדפן ו / או יישומי תוכנה אחרים, נסה שילובים שונים של מפתחות שינוי כדי למצוא אחד המתאים לך.";
+ var prefHeadingKeyboard1$d = "מקשי משנה המשמשים לקיצורי דרך";
+ var prefHeadingKeyboard2$d = "קיצורי מקשים נוכחיים";
+ var prefHeadingDescription$d = "תיאור שמע";
+ var prefHeadingTextDescription$d = "תיאור מבוסס טקסט מבוסס טקסט";
+ var prefAltKey$d = "Alt";
+ var prefCtrlKey$d = "Control";
+ var prefShiftKey$d = "Shift";
+ var prefNoKeyShortcuts$d = "Disable keyboard shortcuts";
+ var escapeKey$d = "Escape";
+ var escapeKeyFunction$d = "סגור את תיבת הדו שיח הנוכחית או תפריט קופץ";
+ var prefDescPause$d = "השהה את הווידאו באופן אוטומטי כאשר התיאור מתחיל";
+ var prefDescVisible$d = "הפוך תיאור גלוי";
+ var prefDescVoice$d = "Voice";
+ var prefDescRate$d = "Spoken Description Rate";
+ var prefCaptionRate$d = "Spoken Caption Rate";
+ var prefDescPitch$d = "Pitch";
+ var prefDescPitch1$d = "Very low";
+ var prefDescPitch2$d = "Low";
+ var prefDescPitch3$d = "Default";
+ var prefDescPitch4$d = "High";
+ var prefDescPitch5$d = "Very high";
+ var sampleDescriptionText$d = "Adjust settings to hear this sample text.";
+ var prefHighlight$d = "הדגש תמליל כמו משחק מדיה";
+ var prefTabbable$d = "הפעל תמליל";
+ var prefCaptionsFont$d = "גופן";
+ var prefCaptionsColor$d = "צבע טקסט";
+ var prefCaptionsBGColor$d = "רקע";
+ var prefCaptionsSize$d = "גודל גופן";
+ var prefCaptionsOpacity$d = "אטימות";
+ var prefCaptionsStyle$d = "סגנון";
+ var serif$d = "serif";
+ var sans$d = "sans-serif";
+ var cursive$d = "cursive";
+ var fantasy$d = "fantasy";
+ var monospace$d = "monospace";
+ var white$d = "לבן";
+ var yellow$d = "צהוב";
+ var green$d = "ירוק";
+ var cyan$c = "טורקיז";
+ var blue$d = "כחול";
+ var magenta$d = "מגנטה";
+ var red$d = "אדום";
+ var black$d = "שחור";
+ var transparent$d = "שקוף";
+ var solid$d = "מלא";
+ var captionsStylePopOn$d = "Pop-on";
+ var captionsStyleRollUp$d = "Roll-up";
+ var prefCaptionsPosition$d = "מיקום";
+ var captionsPositionOverlay$d = "Overlay";
+ var captionsPositionBelow$d = "מתחת לוידאו";
+ var sampleCaptionText$d = "דוגמת טקסט כיתוביות";
+ var prefSuccess$d = "השינויים שלכם נשמרו.";
+ var prefNoChange$d = "לא בצעתם כל שינוי.";
+ var save$d = "שמירה";
+ var cancel$d = "ביטול";
+ var dismissButton$d = "Dismiss";
+ var windowButtonLabel$d = "אפשרויות חלון";
+ var windowMove$d = "הזזה";
+ var windowMoveLeft$d = "Window moved left";
+ var windowMoveRight$d = "Window moved right";
+ var windowMoveUp$d = "Window moved up";
+ var windowMoveDown$d = "Window moved down";
+ var windowMoveStopped$d = "Window move stopped";
+ var transcriptControls$d = "Transcript Window Controls";
+ var signControls$d = "Sign Language Window Controls";
+ var windowMoveAlert$d = "גרור או השתמשו מקשי החצים להזזת החלון; כפתור Enter להפסקה";
+ var windowResize$d = "שיוי גודל";
+ var windowResizeHeading$d = "שינוי גודל חלון";
+ var closeButtonLabel$d = "סגירת";
+ var width$d = "רוחב";
+ var height$d = "גובה";
+ var resultsSummary1$d = "You searched for:";
+ var resultsSummary2$d = "Found %1 matching items.";
+ var resultsSummary3$d = "Click the time associated with any item to play the video from that point.";
+ var noResultsFound$d = "No results found.";
+ var searchButtonLabel$d = "Play at %1";
+ var hour$d = "hour";
+ var minute$d = "minute";
+ var second$d = "second";
+ var hours$d = "hours";
+ var minutes$d = "minutes";
+ var seconds$d = "seconds";
+ var vtsHeading$d = "Video Transcript Sorter";
+ var vtsInstructions1$d = "Use the Video Transcript Sorter to modify text tracks:";
+ var vtsInstructions2$d = "Reorder chapters, descriptions, captions, and/or subtitles so they appear in the proper sequence in Able Player's auto-generated transcript.";
+ var vtsInstructions3$d = "Modify content or start/end times (all are directly editable within the table).";
+ var vtsInstructions4$d = "Add new content, such as chapters or descriptions.";
+ var vtsInstructions5$d = "After editing, click the \"Save Changes\" button to generate new content for all relevant timed text files. The new text can be copied and pasted into new WebVTT files.";
+ var vtsSelectLanguage$d = "Select a language";
+ var vtsSave$d = "Generate new .vtt content";
+ var vtsReturn$d = "Return to Editor";
+ var vtsCancel$d = "Cancelling saving. Any edits you made have been restored in the VTS table.";
+ var vtsRow$d = "Row";
+ var vtsKind$d = "Kind";
+ var vtsStart$d = "Start";
+ var vtsEnd$d = "End";
+ var vtsContent$d = "Content";
+ var vtsActions$d = "Actions";
+ var vtsNewRow$d = "A new row %1 has been inserted.";
+ var vtsDeletedRow$d = "Row %1 has been deleted.";
+ var vtsMovedRow$d = "Row %1 has been moved %2 and is now Row %3.";
+ var he = {
+ playerHeading: playerHeading$d,
+ audioPlayer: audioPlayer$d,
+ videoPlayer: videoPlayer$d,
+ faster: faster$d,
+ slower: slower$d,
+ play: play$d,
+ pause: pause$d,
+ restart: restart$d,
+ prevTrack: prevTrack$d,
+ nextTrack: nextTrack$d,
+ rewind: rewind$d,
+ forward: forward$d,
+ captions: captions$d,
+ showCaptions: showCaptions$d,
+ hideCaptions: hideCaptions$d,
+ captionsOff: captionsOff$d,
+ showTranscript: showTranscript$d,
+ hideTranscript: hideTranscript$d,
+ turnOnDescriptions: turnOnDescriptions$d,
+ turnOffDescriptions: turnOffDescriptions$d,
+ chapters: chapters$d,
+ language: language$d,
+ sign: sign$d,
+ showSign: showSign$d,
+ hideSign: hideSign$d,
+ seekbarLabel: seekbarLabel$d,
+ mute: mute$d,
+ unmute: unmute$d,
+ volume: volume$d,
+ volumeUpDown: volumeUpDown$d,
+ preferences: preferences$d,
+ enterFullScreen: enterFullScreen$d,
+ exitFullScreen: exitFullScreen$d,
+ speed: speed$d,
+ spacebar: spacebar$d,
+ transcriptTitle: transcriptTitle$d,
+ lyricsTitle: lyricsTitle$d,
+ autoScroll: autoScroll$d,
+ statusPlaying: statusPlaying$d,
+ statusPaused: statusPaused$d,
+ statusStopped: statusStopped$d,
+ statusBuffering: statusBuffering$d,
+ statusEnd: statusEnd$d,
+ selectTrack: selectTrack,
+ alertDescribedVersion: alertDescribedVersion$d,
+ alertNonDescribedVersion: alertNonDescribedVersion$d,
+ prefMenuCaptions: prefMenuCaptions$d,
+ prefVoicedCaptions: prefVoicedCaptions$d,
+ prefMenuDescriptions: prefMenuDescriptions$d,
+ prefMenuKeyboard: prefMenuKeyboard$d,
+ prefMenuTranscript: prefMenuTranscript$d,
+ prefTitleCaptions: prefTitleCaptions$d,
+ prefTitleDescriptions: prefTitleDescriptions$d,
+ prefTitleKeyboard: prefTitleKeyboard$d,
+ PrefTitleTranscript: PrefTitleTranscript,
+ prefIntrodescription1: prefIntrodescription1,
+ prefDescription1: prefDescription1$d,
+ prefDescription2: prefDescription2$d,
+ prefDescription3: prefDescription3$d,
+ prefIntroDescriptionNone: prefIntroDescriptionNone$d,
+ prefIntroDescription3: prefIntroDescription3$d,
+ prefIntroDescription4: prefIntroDescription4$d,
+ prefIntroKeyboard1: prefIntroKeyboard1$d,
+ prefIntroKeyboard2: prefIntroKeyboard2$d,
+ prefIntroKeyboard3: prefIntroKeyboard3$d,
+ prefHeadingKeyboard1: prefHeadingKeyboard1$d,
+ prefHeadingKeyboard2: prefHeadingKeyboard2$d,
+ prefHeadingDescription: prefHeadingDescription$d,
+ prefHeadingTextDescription: prefHeadingTextDescription$d,
+ prefAltKey: prefAltKey$d,
+ prefCtrlKey: prefCtrlKey$d,
+ prefShiftKey: prefShiftKey$d,
+ prefNoKeyShortcuts: prefNoKeyShortcuts$d,
+ escapeKey: escapeKey$d,
+ escapeKeyFunction: escapeKeyFunction$d,
+ prefDescPause: prefDescPause$d,
+ prefDescVisible: prefDescVisible$d,
+ prefDescVoice: prefDescVoice$d,
+ prefDescRate: prefDescRate$d,
+ prefCaptionRate: prefCaptionRate$d,
+ prefDescPitch: prefDescPitch$d,
+ prefDescPitch1: prefDescPitch1$d,
+ prefDescPitch2: prefDescPitch2$d,
+ prefDescPitch3: prefDescPitch3$d,
+ prefDescPitch4: prefDescPitch4$d,
+ prefDescPitch5: prefDescPitch5$d,
+ sampleDescriptionText: sampleDescriptionText$d,
+ prefHighlight: prefHighlight$d,
+ prefTabbable: prefTabbable$d,
+ prefCaptionsFont: prefCaptionsFont$d,
+ prefCaptionsColor: prefCaptionsColor$d,
+ prefCaptionsBGColor: prefCaptionsBGColor$d,
+ prefCaptionsSize: prefCaptionsSize$d,
+ prefCaptionsOpacity: prefCaptionsOpacity$d,
+ prefCaptionsStyle: prefCaptionsStyle$d,
+ serif: serif$d,
+ sans: sans$d,
+ cursive: cursive$d,
+ fantasy: fantasy$d,
+ monospace: monospace$d,
+ white: white$d,
+ yellow: yellow$d,
+ green: green$d,
+ cyan: cyan$c,
+ blue: blue$d,
+ magenta: magenta$d,
+ red: red$d,
+ black: black$d,
+ transparent: transparent$d,
+ solid: solid$d,
+ captionsStylePopOn: captionsStylePopOn$d,
+ captionsStyleRollUp: captionsStyleRollUp$d,
+ prefCaptionsPosition: prefCaptionsPosition$d,
+ captionsPositionOverlay: captionsPositionOverlay$d,
+ captionsPositionBelow: captionsPositionBelow$d,
+ sampleCaptionText: sampleCaptionText$d,
+ prefSuccess: prefSuccess$d,
+ prefNoChange: prefNoChange$d,
+ save: save$d,
+ cancel: cancel$d,
+ dismissButton: dismissButton$d,
+ windowButtonLabel: windowButtonLabel$d,
+ windowMove: windowMove$d,
+ windowMoveLeft: windowMoveLeft$d,
+ windowMoveRight: windowMoveRight$d,
+ windowMoveUp: windowMoveUp$d,
+ windowMoveDown: windowMoveDown$d,
+ windowMoveStopped: windowMoveStopped$d,
+ transcriptControls: transcriptControls$d,
+ signControls: signControls$d,
+ windowMoveAlert: windowMoveAlert$d,
+ windowResize: windowResize$d,
+ windowResizeHeading: windowResizeHeading$d,
+ closeButtonLabel: closeButtonLabel$d,
+ width: width$d,
+ height: height$d,
+ resultsSummary1: resultsSummary1$d,
+ resultsSummary2: resultsSummary2$d,
+ resultsSummary3: resultsSummary3$d,
+ noResultsFound: noResultsFound$d,
+ searchButtonLabel: searchButtonLabel$d,
+ hour: hour$d,
+ minute: minute$d,
+ second: second$d,
+ hours: hours$d,
+ minutes: minutes$d,
+ seconds: seconds$d,
+ vtsHeading: vtsHeading$d,
+ vtsInstructions1: vtsInstructions1$d,
+ vtsInstructions2: vtsInstructions2$d,
+ vtsInstructions3: vtsInstructions3$d,
+ vtsInstructions4: vtsInstructions4$d,
+ vtsInstructions5: vtsInstructions5$d,
+ vtsSelectLanguage: vtsSelectLanguage$d,
+ vtsSave: vtsSave$d,
+ vtsReturn: vtsReturn$d,
+ vtsCancel: vtsCancel$d,
+ vtsRow: vtsRow$d,
+ vtsKind: vtsKind$d,
+ vtsStart: vtsStart$d,
+ vtsEnd: vtsEnd$d,
+ vtsContent: vtsContent$d,
+ vtsActions: vtsActions$d,
+ vtsNewRow: vtsNewRow$d,
+ vtsDeletedRow: vtsDeletedRow$d,
+ vtsMovedRow: vtsMovedRow$d
+ };
+
+ var playerHeading$c = "Pemutar media";
+ var audioPlayer$c = "Audio player";
+ var videoPlayer$c = "Video player";
+ var faster$c = "Percepat";
+ var slower$c = "Perlambat";
+ var play$c = "Mulai";
+ var pause$c = "Jeda";
+ var restart$c = "Ulangi";
+ var prevTrack$c = "Trek sebelumnya";
+ var nextTrack$c = "Trek berikutnya";
+ var rewind$c = "Mundur";
+ var forward$c = "Maju";
+ var captions$c = "Takarir";
+ var showCaptions$c = "Tampilkan takarir";
+ var hideCaptions$c = "Sembunyikan takarir";
+ var captionsOff$c = "Tanpa takarir";
+ var showTranscript$c = "Tampilkan transkripsi";
+ var hideTranscript$c = "Sembunyikan transkripsi";
+ var turnOnDescriptions$c = "Nyalakan deskripsi";
+ var turnOffDescriptions$c = "Matikan deskripsi";
+ var chapters$c = "Bagian";
+ var language$c = "Bahasa";
+ var sign$c = "Bahasa isyarat";
+ var showSign$c = "Tampilkan bahasa isyarat";
+ var hideSign$c = "Sembunyikan bahasa isyarat";
+ var seekbarLabel$c = "lini masa";
+ var mute$c = "Matikan Suara";
+ var unmute$c = "Nyalakan Suara";
+ var volume$c = "Volume";
+ var volumeUpDown$c = "Naik turun volume";
+ var preferences$c = "Preferensi";
+ var enterFullScreen$c = "Masuk ke mode layar penuh";
+ var exitFullScreen$c = "Keluar dari mode layar penuh";
+ var speed$c = "Kecepatan";
+ var spacebar$c = "tombol spasi";
+ var transcriptTitle$c = "Transkripsi";
+ var lyricsTitle$c = "Lirik";
+ var autoScroll$c = "Gulir otomatis";
+ var statusPlaying$c = "Memutar";
+ var statusPaused$c = "Dijedakan";
+ var statusStopped$c = "Dihentikan";
+ var statusBuffering$c = "Sedang Bufer";
+ var statusEnd$c = "Akhir dari trek";
+ var selectedTrack$c = "Trek Pilihan";
+ var alertDescribedVersion$c = "Menggunakan versi dengan deskripsi audio pada video ini";
+ var alertNonDescribedVersion$c = "Menggunakan versi tanpa deskripsi pada video ini";
+ var prefMenuCaptions$c = "Takarir";
+ var prefVoicedCaptions$c = "Spoken Captions";
+ var prefMenuDescriptions$c = "Deskripsi";
+ var prefMenuKeyboard$c = "Kibor";
+ var prefMenuTranscript$c = "Transkripsi";
+ var prefTitleCaptions$c = "Preferensi Takarir";
+ var prefTitleDescriptions$c = "Preferensi Deskripsi Audio";
+ var prefTitleKeyboard$c = "Preferensi Kibor";
+ var prefTitleTranscript$c = "Preferensi Transkripsi";
+ var prefIntroDescription1$c = "Pemutar media ini mendukung deskripsi audio dengan dua cara: ";
+ var prefDescription1$c = "Video ini memiliki versi alternatif berdeskripsi, deskripsi berbasis teks.";
+ var prefDescription2$c = "Video ini memiliki versi alternatif video dengan deskripsi.";
+ var prefDescription3$c = "Video ini memiliki deskripsi berbasis teks, dibacakan oleh pembaca layar.";
+ var prefIntroDescriptionNone$c = "Video ini tidak memiliki deskripsi audio dalam format mana pun.";
+ var prefIntroDescription3$c = "Gunakan isian berikut untuk memasang preferensi terkait deskripsi audio berbasis teks.";
+ var prefIntroDescription4$c = "Setelah Anda menyimpan pengaturan, deskripsi audio dapat dinyala/matikan melalui tombol Deskripsi.";
+ var prefIntroKeyboard1$c = "Pemutar media dalam halaman ini dapat dioperasikan dari bagian mana pun pada halaman dengan menggunakan pintasan kibor (lihat daftar di bawah).";
+ var prefIntroKeyboard2$c = "Fungsi tombol kombinasi (Shift, Alt, Control) dapat dipasangkan di bawah ini.";
+ var prefIntroKeyboard3$c = "CATATAN: Beberapa kombinasi tombol mungkin akan bersinggungan dengan yang digunakan oleh browser dan/atau aplikasi perangkat lunak lainnya. Cobalah berbagai kombinasi untuk menemukan kombinasi yang bekerja untuk Anda.";
+ var prefHeadingKeyboard1$c = "Tombol kombinasi yang digunakan untuk pintasan";
+ var prefHeadingKeyboard2$c = "Pintasan kibor saat ini";
+ var prefHeadingDescription$c = "Deskripsi audio";
+ var prefHeadingTextDescription$c = "Deskripsi audio berbasis teks";
+ var prefAltKey$c = "Alt";
+ var prefCtrlKey$c = "Control";
+ var prefShiftKey$c = "Shift";
+ var prefNoKeyShortcuts$c = "Disable keyboard shortcuts";
+ var escapeKey$c = "Escape";
+ var escapeKeyFunction$c = "Tutup dialog atau menu sembulan yang tampil";
+ var prefDescPause$c = "Otomatis jedakan video ketika deskripsi dimulai";
+ var prefDescVisible$c = "Tampilkan deskripsi";
+ var prefDescVoice$c = "Suara";
+ var prefDescRate$c = "Spoken Description Rate";
+ var prefCaptionRate$c = "Spoken Caption Rate";
+ var prefDescPitch$c = "Titinada";
+ var prefDescPitch1$c = "Sangat rendah";
+ var prefDescPitch2$c = "Rendah";
+ var prefDescPitch3$c = "Bawaan";
+ var prefDescPitch4$c = "Tinggi";
+ var prefDescPitch5$c = "Sangat tinggi";
+ var sampleDescriptionText$c = "Sesuaikan pengaturan untuk mendengarkan teks ini.";
+ var prefHighlight$c = "Soroti transkripsi yang sesuai saat media diputar";
+ var prefTabbable$c = "Transkripsi dengan kontrol kibor";
+ var prefCaptionsFont$c = "Jenis Huruf";
+ var prefCaptionsColor$c = "Warna Teks";
+ var prefCaptionsBGColor$c = "Warna Latar";
+ var prefCaptionsSize$c = "Ukuran Huruf";
+ var prefCaptionsOpacity$c = "Opasitas";
+ var prefCaptionsStyle$c = "Gaya";
+ var serif$c = "serif";
+ var sans$c = "sans-serif";
+ var cursive$c = "kursif";
+ var fantasy$c = "fantasi";
+ var monospace$c = "monospasi";
+ var white$c = "putih";
+ var yellow$c = "kuning";
+ var green$c = "hijau";
+ var cyan$b = "sian";
+ var blue$c = "biru";
+ var magenta$c = "magenta";
+ var red$c = "merah";
+ var black$c = "hitam";
+ var transparent$c = "transparan";
+ var solid$c = "solid";
+ var captionsStylePopOn$c = "Muncul";
+ var captionsStyleRollUp$c = "Bergulir naik";
+ var prefCaptionsPosition$c = "Posisi";
+ var captionsPositionOverlay$c = "Di atas video";
+ var captionsPositionBelow$c = "Di bawah video";
+ var sampleCaptionText$c = "Contoh teks takarir";
+ var prefSuccess$c = "Perubahan telah disimpan.";
+ var prefNoChange$c = "Anda tidak melakukan perubahan apa pun.";
+ var save$c = "Simpan";
+ var cancel$c = "Batal";
+ var dismissButton$c = "Dismiss";
+ var windowButtonLabel$c = "Opsi jendela";
+ var windowMove$c = "Geser";
+ var windowMoveLeft$c = "Window moved left";
+ var windowMoveRight$c = "Window moved right";
+ var windowMoveUp$c = "Window moved up";
+ var windowMoveDown$c = "Window moved down";
+ var windowMoveStopped$c = "Window move stopped";
+ var transcriptControls$c = "Transcript Window Controls";
+ var signControls$c = "Sign Language Window Controls";
+ var windowMoveAlert$c = "Seret atau gunakan tombol panah untuk menggeser jendela; Tekan Enter untuk berhenti";
+ var windowResize$c = "Ubah ukuran";
+ var windowResizeHeading$c = "Ubah Ukuran Jendela";
+ var closeButtonLabel$c = "Tutup";
+ var width$c = "Lebar";
+ var height$c = "Tinggi";
+ var resultsSummary1$c = "Anda mencari:";
+ var resultsSummary2$c = "Ditemukan %1 hal yang sesuai.";
+ var resultsSummary3$c = "Klik waktu yang terkait dengan suatu hal untuk memutar video dari titik tersebut.";
+ var noResultsFound$c = "Tidak ada hasil yang ditemukan.";
+ var searchButtonLabel$c = "Diputar pada %1";
+ var hour$c = "jam";
+ var minute$c = "menit";
+ var second$c = "detik";
+ var hours$c = "jam";
+ var minutes$c = "menit";
+ var seconds$c = "detik";
+ var vtsHeading$c = "Video Transcript Sorter";
+ var vtsInstructions1$c = "Use the Video Transcript Sorter to modify text tracks:";
+ var vtsInstructions2$c = "Reorder chapters, descriptions, captions, and/or subtitles so they appear in the proper sequence in Able Player's auto-generated transcript.";
+ var vtsInstructions3$c = "Modify content or start/end times (all are directly editable within the table).";
+ var vtsInstructions4$c = "Add new content, such as chapters or descriptions.";
+ var vtsInstructions5$c = "After editing, click the \"Save Changes\" button to generate new content for all relevant timed text files. The new text can be copied and pasted into new WebVTT files.";
+ var vtsSelectLanguage$c = "Select a language";
+ var vtsSave$c = "Generate new .vtt content";
+ var vtsReturn$c = "Return to Editor";
+ var vtsCancel$c = "Cancelling saving. Any edits you made have been restored in the VTS table.";
+ var vtsRow$c = "Row";
+ var vtsKind$c = "Kind";
+ var vtsStart$c = "Start";
+ var vtsEnd$c = "End";
+ var vtsContent$c = "Content";
+ var vtsActions$c = "Actions";
+ var vtsNewRow$c = "A new row %1 has been inserted.";
+ var vtsDeletedRow$c = "Row %1 has been deleted.";
+ var vtsMovedRow$c = "Row %1 has been moved %2 and is now Row %3.";
+ var id = {
+ playerHeading: playerHeading$c,
+ audioPlayer: audioPlayer$c,
+ videoPlayer: videoPlayer$c,
+ faster: faster$c,
+ slower: slower$c,
+ play: play$c,
+ pause: pause$c,
+ restart: restart$c,
+ prevTrack: prevTrack$c,
+ nextTrack: nextTrack$c,
+ rewind: rewind$c,
+ forward: forward$c,
+ captions: captions$c,
+ showCaptions: showCaptions$c,
+ hideCaptions: hideCaptions$c,
+ captionsOff: captionsOff$c,
+ showTranscript: showTranscript$c,
+ hideTranscript: hideTranscript$c,
+ turnOnDescriptions: turnOnDescriptions$c,
+ turnOffDescriptions: turnOffDescriptions$c,
+ chapters: chapters$c,
+ language: language$c,
+ sign: sign$c,
+ showSign: showSign$c,
+ hideSign: hideSign$c,
+ seekbarLabel: seekbarLabel$c,
+ mute: mute$c,
+ unmute: unmute$c,
+ volume: volume$c,
+ volumeUpDown: volumeUpDown$c,
+ preferences: preferences$c,
+ enterFullScreen: enterFullScreen$c,
+ exitFullScreen: exitFullScreen$c,
+ speed: speed$c,
+ spacebar: spacebar$c,
+ transcriptTitle: transcriptTitle$c,
+ lyricsTitle: lyricsTitle$c,
+ autoScroll: autoScroll$c,
+ statusPlaying: statusPlaying$c,
+ statusPaused: statusPaused$c,
+ statusStopped: statusStopped$c,
+ statusBuffering: statusBuffering$c,
+ statusEnd: statusEnd$c,
+ selectedTrack: selectedTrack$c,
+ alertDescribedVersion: alertDescribedVersion$c,
+ alertNonDescribedVersion: alertNonDescribedVersion$c,
+ prefMenuCaptions: prefMenuCaptions$c,
+ prefVoicedCaptions: prefVoicedCaptions$c,
+ prefMenuDescriptions: prefMenuDescriptions$c,
+ prefMenuKeyboard: prefMenuKeyboard$c,
+ prefMenuTranscript: prefMenuTranscript$c,
+ prefTitleCaptions: prefTitleCaptions$c,
+ prefTitleDescriptions: prefTitleDescriptions$c,
+ prefTitleKeyboard: prefTitleKeyboard$c,
+ prefTitleTranscript: prefTitleTranscript$c,
+ prefIntroDescription1: prefIntroDescription1$c,
+ prefDescription1: prefDescription1$c,
+ prefDescription2: prefDescription2$c,
+ prefDescription3: prefDescription3$c,
+ prefIntroDescriptionNone: prefIntroDescriptionNone$c,
+ prefIntroDescription3: prefIntroDescription3$c,
+ prefIntroDescription4: prefIntroDescription4$c,
+ prefIntroKeyboard1: prefIntroKeyboard1$c,
+ prefIntroKeyboard2: prefIntroKeyboard2$c,
+ prefIntroKeyboard3: prefIntroKeyboard3$c,
+ prefHeadingKeyboard1: prefHeadingKeyboard1$c,
+ prefHeadingKeyboard2: prefHeadingKeyboard2$c,
+ prefHeadingDescription: prefHeadingDescription$c,
+ prefHeadingTextDescription: prefHeadingTextDescription$c,
+ prefAltKey: prefAltKey$c,
+ prefCtrlKey: prefCtrlKey$c,
+ prefShiftKey: prefShiftKey$c,
+ prefNoKeyShortcuts: prefNoKeyShortcuts$c,
+ escapeKey: escapeKey$c,
+ escapeKeyFunction: escapeKeyFunction$c,
+ prefDescPause: prefDescPause$c,
+ prefDescVisible: prefDescVisible$c,
+ prefDescVoice: prefDescVoice$c,
+ prefDescRate: prefDescRate$c,
+ prefCaptionRate: prefCaptionRate$c,
+ prefDescPitch: prefDescPitch$c,
+ prefDescPitch1: prefDescPitch1$c,
+ prefDescPitch2: prefDescPitch2$c,
+ prefDescPitch3: prefDescPitch3$c,
+ prefDescPitch4: prefDescPitch4$c,
+ prefDescPitch5: prefDescPitch5$c,
+ sampleDescriptionText: sampleDescriptionText$c,
+ prefHighlight: prefHighlight$c,
+ prefTabbable: prefTabbable$c,
+ prefCaptionsFont: prefCaptionsFont$c,
+ prefCaptionsColor: prefCaptionsColor$c,
+ prefCaptionsBGColor: prefCaptionsBGColor$c,
+ prefCaptionsSize: prefCaptionsSize$c,
+ prefCaptionsOpacity: prefCaptionsOpacity$c,
+ prefCaptionsStyle: prefCaptionsStyle$c,
+ serif: serif$c,
+ sans: sans$c,
+ cursive: cursive$c,
+ fantasy: fantasy$c,
+ monospace: monospace$c,
+ white: white$c,
+ yellow: yellow$c,
+ green: green$c,
+ cyan: cyan$b,
+ blue: blue$c,
+ magenta: magenta$c,
+ red: red$c,
+ black: black$c,
+ transparent: transparent$c,
+ solid: solid$c,
+ captionsStylePopOn: captionsStylePopOn$c,
+ captionsStyleRollUp: captionsStyleRollUp$c,
+ prefCaptionsPosition: prefCaptionsPosition$c,
+ captionsPositionOverlay: captionsPositionOverlay$c,
+ captionsPositionBelow: captionsPositionBelow$c,
+ sampleCaptionText: sampleCaptionText$c,
+ prefSuccess: prefSuccess$c,
+ prefNoChange: prefNoChange$c,
+ save: save$c,
+ cancel: cancel$c,
+ dismissButton: dismissButton$c,
+ windowButtonLabel: windowButtonLabel$c,
+ windowMove: windowMove$c,
+ windowMoveLeft: windowMoveLeft$c,
+ windowMoveRight: windowMoveRight$c,
+ windowMoveUp: windowMoveUp$c,
+ windowMoveDown: windowMoveDown$c,
+ windowMoveStopped: windowMoveStopped$c,
+ transcriptControls: transcriptControls$c,
+ signControls: signControls$c,
+ windowMoveAlert: windowMoveAlert$c,
+ windowResize: windowResize$c,
+ windowResizeHeading: windowResizeHeading$c,
+ closeButtonLabel: closeButtonLabel$c,
+ width: width$c,
+ height: height$c,
+ resultsSummary1: resultsSummary1$c,
+ resultsSummary2: resultsSummary2$c,
+ resultsSummary3: resultsSummary3$c,
+ noResultsFound: noResultsFound$c,
+ searchButtonLabel: searchButtonLabel$c,
+ hour: hour$c,
+ minute: minute$c,
+ second: second$c,
+ hours: hours$c,
+ minutes: minutes$c,
+ seconds: seconds$c,
+ vtsHeading: vtsHeading$c,
+ vtsInstructions1: vtsInstructions1$c,
+ vtsInstructions2: vtsInstructions2$c,
+ vtsInstructions3: vtsInstructions3$c,
+ vtsInstructions4: vtsInstructions4$c,
+ vtsInstructions5: vtsInstructions5$c,
+ vtsSelectLanguage: vtsSelectLanguage$c,
+ vtsSave: vtsSave$c,
+ vtsReturn: vtsReturn$c,
+ vtsCancel: vtsCancel$c,
+ vtsRow: vtsRow$c,
+ vtsKind: vtsKind$c,
+ vtsStart: vtsStart$c,
+ vtsEnd: vtsEnd$c,
+ vtsContent: vtsContent$c,
+ vtsActions: vtsActions$c,
+ vtsNewRow: vtsNewRow$c,
+ vtsDeletedRow: vtsDeletedRow$c,
+ vtsMovedRow: vtsMovedRow$c
+ };
+
+ var playerHeading$b = "Lettore multimediale";
+ var audioPlayer$b = "Audio player";
+ var videoPlayer$b = "Video player";
+ var faster$b = "Più veloce";
+ var slower$b = "Più lento";
+ var play$b = "Riproduci";
+ var pause$b = "Pausa";
+ var restart$b = "Torna all'inizio";
+ var prevTrack$b = "Traccia precedente";
+ var nextTrack$b = "Traccia successiva";
+ var rewind$b = "Indietro";
+ var forward$b = "Avanti";
+ var captions$b = "Sottotitoli";
+ var showCaptions$b = "Mostra sottotitoli";
+ var hideCaptions$b = "Nascondi sottotitoli";
+ var captionsOff$b = "Disattiva sottotitoli";
+ var showTranscript$b = "Mostra trascrizione";
+ var hideTranscript$b = "Nascondi trascrizione";
+ var turnOnDescriptions$b = "Attiva audiodescrizioni";
+ var turnOffDescriptions$b = "Disattiva audiodescrizioni";
+ var chapters$b = "Capitoli";
+ var language$b = "Lingua";
+ var sign$b = "Lingua dei segni";
+ var showSign$b = "Mostra lingua dei segni";
+ var hideSign$b = "Nascondi lingua dei segni";
+ var seekbarLabel$b = "Tempo trascorso";
+ var mute$b = "Muto";
+ var unmute$b = "Riattiva l'audio";
+ var volume$b = "Volume";
+ var volumeUpDown$b = "Incremento e diminuzione volume";
+ var preferences$b = "Preferenze";
+ var enterFullScreen$b = "Attiva schermo intero";
+ var exitFullScreen$b = "Disattiva schermo intero";
+ var speed$b = "Velocità";
+ var spacebar$b = "barra spaziatrice";
+ var transcriptTitle$b = "Trascrizione";
+ var lyricsTitle$b = "Testi";
+ var autoScroll$b = "Auto scorrimento";
+ var statusPlaying$b = "In riproduzione";
+ var statusPaused$b = "In pausa";
+ var statusStopped$b = "Fermato";
+ var statusBuffering$b = "Buffering";
+ var statusEnd$b = "Fine traccia";
+ var selectedTrack$b = "Traccia selezionata";
+ var alertDescribedVersion$b = "Sto usando la versione audiodescritta di questo video";
+ var alertNonDescribedVersion$b = "Sto usando la versione non audiodescritta di questo video";
+ var prefMenuCaptions$b = "Sottotitoli";
+ var prefVoicedCaptions$b = "Spoken Captions";
+ var prefMenuDescriptions$b = "Audioescrizioni";
+ var prefMenuKeyboard$b = "Tastiera";
+ var prefMenuTranscript$b = "Trascrizione";
+ var prefTitleCaptions$b = "Preferenze sottotitoli";
+ var prefTitleDescriptions$b = "Preferenze audiodescrizione";
+ var prefTitleKeyboard$b = "Preferenze tastiera";
+ var prefTitleTranscript$b = "Preferenze trascrizione";
+ var prefIntroDescription1$b = "Questo lettore multimediale supporta le audiodescrizioni in due modi:";
+ var prefDescription1$b = "il video corrente ha Una versione di descrizione alternativa, Descrizione testuale.";
+ var prefDescription2$b = "il video corrente ha Versione di descrizione alternativa per il video.";
+ var prefDescription3$b = "il video corrente ha Descrizione testuale, letta dal lettore di schermo.";
+ var prefIntroDescriptionNone$b = "Il video corrente non ha audiodescrizioni.";
+ var prefIntroDescription3$b = "Usa il seguente modulo per impostare le tue preferenze relative all'audiodescrizione testuale.";
+ var prefIntroDescription4$b = "Dopo aver salvato le tue impostazioni, le audiodescrizioni possono essere attivate o disattivate usando i pulsanti descrizione.";
+ var prefIntroKeyboard1$b = "Il lettore multimediale può essere usato dovunque in questa pagina, attraverso la tastiera. Vedi sotto per un elenco di tasti di scelta rapida.";
+ var prefIntroKeyboard2$b = "I tasti di scelta rapida, (Shift, Alt, e Control) possono essere assegnati di seguito.";
+ var prefIntroKeyboard3$b = "NOTA: Alcune combinazioni di tasti possono essere in conflitto con i tasti utilizzati dal tuo browser od altro software. Prova varie combinazioni di tasti per trovarne una che funzioni correttamente.";
+ var prefHeadingKeyboard1$b = "Tasti di scelta rapida";
+ var prefHeadingKeyboard2$b = "Tasti di scelta rapida correnti";
+ var prefHeadingDescription$b = "Audiodescrizione";
+ var prefHeadingTextDescription$b = "audiodescrizione testuale";
+ var prefAltKey$b = "Alt";
+ var prefCtrlKey$b = "Control";
+ var prefShiftKey$b = "Shift";
+ var prefNoKeyShortcuts$b = "Disable keyboard shortcuts";
+ var escapeKey$b = "Escape";
+ var escapeKeyFunction$b = "Chiude il menu o la finestra corrente";
+ var prefDescPause$b = "Mette automaticamente il video in pausa, quando inizia la descrizione";
+ var prefDescVisible$b = "Rende la descrizione visibile";
+ var prefDescVoice$b = "Voice";
+ var prefDescRate$b = "Spoken Description Rate";
+ var prefCaptionRate$b = "Spoken Caption Rate";
+ var prefDescPitch$b = "Pitch";
+ var prefDescPitch1$b = "Very low";
+ var prefDescPitch2$b = "Low";
+ var prefDescPitch3$b = "Default";
+ var prefDescPitch4$b = "High";
+ var prefDescPitch5$b = "Very high";
+ var sampleDescriptionText$b = "Adjust settings to hear this sample text.";
+ var prefHighlight$b = "Evidenzia la descrizione";
+ var prefTabbable$b = "Abilita la descrizione";
+ var prefCaptionsFont$b = "Carattere";
+ var prefCaptionsColor$b = "Colore del testo";
+ var prefCaptionsBGColor$b = "Colore di sfondo";
+ var prefCaptionsSize$b = "Dimensione del carattere";
+ var prefCaptionsOpacity$b = "Opacità";
+ var prefCaptionsStyle$b = "Stile";
+ var serif$b = "serif";
+ var sans$b = "sans-serif";
+ var cursive$b = "corsivo";
+ var fantasy$b = "fantasy";
+ var monospace$b = "monospace";
+ var white$b = "bianco";
+ var yellow$b = "giallo";
+ var green$b = "verde";
+ var ciano = "ciano";
+ var blue$b = "blue";
+ var magenta$b = "magenta";
+ var red$b = "rosso";
+ var black$b = "nero";
+ var transparent$b = "trasparente";
+ var solid$b = "solido";
+ var captionsStylePopOn$b = "A comparsa";
+ var captionsStyleRollUp$b = "A scorrimento";
+ var prefCaptionsPosition$b = "Posizione";
+ var captionsPositionOverlay$b = "Copre";
+ var captionsPositionBelow$b = "Sotto al video";
+ var sampleCaptionText$b = "Testo di esempio sottotitoli";
+ var prefSuccess$b = "I cambiamenti sono stati salvati.";
+ var prefNoChange$b = "Non è stato effettuato alcun cambiamento.";
+ var save$b = "Salva";
+ var cancel$b = "Annulla";
+ var dismissButton$b = "Dismiss";
+ var windowButtonLabel$b = "Opzioni finestra";
+ var windowMove$b = "Sposta";
+ var windowMoveLeft$b = "Window moved left";
+ var windowMoveRight$b = "Window moved right";
+ var windowMoveUp$b = "Window moved up";
+ var windowMoveDown$b = "Window moved down";
+ var windowMoveStopped$b = "Window move stopped";
+ var transcriptControls$b = "Transcript Window Controls";
+ var signControls$b = "Sign Language Window Controls";
+ var windowMoveAlert$b = "Trascina o usa le frecce per spostare la finestra. Invio per fermare.";
+ var windowResize$b = "Ridimensiona";
+ var windowResizeHeading$b = "Ridimensiona finestra";
+ var closeButtonLabel$b = "Chiudi";
+ var width$b = "Larghezza";
+ var height$b = "Altezza";
+ var resultsSummary1$b = "You searched for:";
+ var resultsSummary2$b = "Found %1 matching items.";
+ var resultsSummary3$b = "Click the time associated with any item to play the video from that point.";
+ var noResultsFound$b = "No results found.";
+ var searchButtonLabel$b = "Play at %1";
+ var hour$b = "hour";
+ var minute$b = "minute";
+ var second$b = "second";
+ var hours$b = "hours";
+ var minutes$b = "minutes";
+ var seconds$b = "seconds";
+ var vtsHeading$b = "Video Transcript Sorter";
+ var vtsInstructions1$b = "Use the Video Transcript Sorter to modify text tracks:";
+ var vtsInstructions2$b = "Reorder chapters, descriptions, captions, and/or subtitles so they appear in the proper sequence in Able Player's auto-generated transcript.";
+ var vtsInstructions3$b = "Modify content or start/end times (all are directly editable within the table).";
+ var vtsInstructions4$b = "Add new content, such as chapters or descriptions.";
+ var vtsInstructions5$b = "After editing, click the \"Save Changes\" button to generate new content for all relevant timed text files. The new text can be copied and pasted into new WebVTT files.";
+ var vtsSelectLanguage$b = "Select a language";
+ var vtsSave$b = "Generate new .vtt content";
+ var vtsReturn$b = "Return to Editor";
+ var vtsCancel$b = "Cancelling saving. Any edits you made have been restored in the VTS table.";
+ var vtsRow$b = "Row";
+ var vtsKind$b = "Kind";
+ var vtsStart$b = "Start";
+ var vtsEnd$b = "End";
+ var vtsContent$b = "Content";
+ var vtsActions$b = "Actions";
+ var vtsNewRow$b = "A new row %1 has been inserted.";
+ var vtsDeletedRow$b = "Row %1 has been deleted.";
+ var vtsMovedRow$b = "Row %1 has been moved %2 and is now Row %3.";
+ var it = {
+ playerHeading: playerHeading$b,
+ audioPlayer: audioPlayer$b,
+ videoPlayer: videoPlayer$b,
+ faster: faster$b,
+ slower: slower$b,
+ play: play$b,
+ pause: pause$b,
+ restart: restart$b,
+ prevTrack: prevTrack$b,
+ nextTrack: nextTrack$b,
+ rewind: rewind$b,
+ forward: forward$b,
+ captions: captions$b,
+ showCaptions: showCaptions$b,
+ hideCaptions: hideCaptions$b,
+ captionsOff: captionsOff$b,
+ showTranscript: showTranscript$b,
+ hideTranscript: hideTranscript$b,
+ turnOnDescriptions: turnOnDescriptions$b,
+ turnOffDescriptions: turnOffDescriptions$b,
+ chapters: chapters$b,
+ language: language$b,
+ sign: sign$b,
+ showSign: showSign$b,
+ hideSign: hideSign$b,
+ seekbarLabel: seekbarLabel$b,
+ mute: mute$b,
+ unmute: unmute$b,
+ volume: volume$b,
+ volumeUpDown: volumeUpDown$b,
+ preferences: preferences$b,
+ enterFullScreen: enterFullScreen$b,
+ exitFullScreen: exitFullScreen$b,
+ speed: speed$b,
+ spacebar: spacebar$b,
+ transcriptTitle: transcriptTitle$b,
+ lyricsTitle: lyricsTitle$b,
+ autoScroll: autoScroll$b,
+ statusPlaying: statusPlaying$b,
+ statusPaused: statusPaused$b,
+ statusStopped: statusStopped$b,
+ statusBuffering: statusBuffering$b,
+ statusEnd: statusEnd$b,
+ selectedTrack: selectedTrack$b,
+ alertDescribedVersion: alertDescribedVersion$b,
+ alertNonDescribedVersion: alertNonDescribedVersion$b,
+ prefMenuCaptions: prefMenuCaptions$b,
+ prefVoicedCaptions: prefVoicedCaptions$b,
+ prefMenuDescriptions: prefMenuDescriptions$b,
+ prefMenuKeyboard: prefMenuKeyboard$b,
+ prefMenuTranscript: prefMenuTranscript$b,
+ prefTitleCaptions: prefTitleCaptions$b,
+ prefTitleDescriptions: prefTitleDescriptions$b,
+ prefTitleKeyboard: prefTitleKeyboard$b,
+ prefTitleTranscript: prefTitleTranscript$b,
+ prefIntroDescription1: prefIntroDescription1$b,
+ prefDescription1: prefDescription1$b,
+ prefDescription2: prefDescription2$b,
+ prefDescription3: prefDescription3$b,
+ prefIntroDescriptionNone: prefIntroDescriptionNone$b,
+ prefIntroDescription3: prefIntroDescription3$b,
+ prefIntroDescription4: prefIntroDescription4$b,
+ prefIntroKeyboard1: prefIntroKeyboard1$b,
+ prefIntroKeyboard2: prefIntroKeyboard2$b,
+ prefIntroKeyboard3: prefIntroKeyboard3$b,
+ prefHeadingKeyboard1: prefHeadingKeyboard1$b,
+ prefHeadingKeyboard2: prefHeadingKeyboard2$b,
+ prefHeadingDescription: prefHeadingDescription$b,
+ prefHeadingTextDescription: prefHeadingTextDescription$b,
+ prefAltKey: prefAltKey$b,
+ prefCtrlKey: prefCtrlKey$b,
+ prefShiftKey: prefShiftKey$b,
+ prefNoKeyShortcuts: prefNoKeyShortcuts$b,
+ escapeKey: escapeKey$b,
+ escapeKeyFunction: escapeKeyFunction$b,
+ prefDescPause: prefDescPause$b,
+ prefDescVisible: prefDescVisible$b,
+ prefDescVoice: prefDescVoice$b,
+ prefDescRate: prefDescRate$b,
+ prefCaptionRate: prefCaptionRate$b,
+ prefDescPitch: prefDescPitch$b,
+ prefDescPitch1: prefDescPitch1$b,
+ prefDescPitch2: prefDescPitch2$b,
+ prefDescPitch3: prefDescPitch3$b,
+ prefDescPitch4: prefDescPitch4$b,
+ prefDescPitch5: prefDescPitch5$b,
+ sampleDescriptionText: sampleDescriptionText$b,
+ prefHighlight: prefHighlight$b,
+ prefTabbable: prefTabbable$b,
+ prefCaptionsFont: prefCaptionsFont$b,
+ prefCaptionsColor: prefCaptionsColor$b,
+ prefCaptionsBGColor: prefCaptionsBGColor$b,
+ prefCaptionsSize: prefCaptionsSize$b,
+ prefCaptionsOpacity: prefCaptionsOpacity$b,
+ prefCaptionsStyle: prefCaptionsStyle$b,
+ serif: serif$b,
+ sans: sans$b,
+ cursive: cursive$b,
+ fantasy: fantasy$b,
+ monospace: monospace$b,
+ white: white$b,
+ yellow: yellow$b,
+ green: green$b,
+ ciano: ciano,
+ blue: blue$b,
+ magenta: magenta$b,
+ red: red$b,
+ black: black$b,
+ transparent: transparent$b,
+ solid: solid$b,
+ captionsStylePopOn: captionsStylePopOn$b,
+ captionsStyleRollUp: captionsStyleRollUp$b,
+ prefCaptionsPosition: prefCaptionsPosition$b,
+ captionsPositionOverlay: captionsPositionOverlay$b,
+ captionsPositionBelow: captionsPositionBelow$b,
+ sampleCaptionText: sampleCaptionText$b,
+ prefSuccess: prefSuccess$b,
+ prefNoChange: prefNoChange$b,
+ save: save$b,
+ cancel: cancel$b,
+ dismissButton: dismissButton$b,
+ windowButtonLabel: windowButtonLabel$b,
+ windowMove: windowMove$b,
+ windowMoveLeft: windowMoveLeft$b,
+ windowMoveRight: windowMoveRight$b,
+ windowMoveUp: windowMoveUp$b,
+ windowMoveDown: windowMoveDown$b,
+ windowMoveStopped: windowMoveStopped$b,
+ transcriptControls: transcriptControls$b,
+ signControls: signControls$b,
+ windowMoveAlert: windowMoveAlert$b,
+ windowResize: windowResize$b,
+ windowResizeHeading: windowResizeHeading$b,
+ closeButtonLabel: closeButtonLabel$b,
+ width: width$b,
+ height: height$b,
+ resultsSummary1: resultsSummary1$b,
+ resultsSummary2: resultsSummary2$b,
+ resultsSummary3: resultsSummary3$b,
+ noResultsFound: noResultsFound$b,
+ searchButtonLabel: searchButtonLabel$b,
+ hour: hour$b,
+ minute: minute$b,
+ second: second$b,
+ hours: hours$b,
+ minutes: minutes$b,
+ seconds: seconds$b,
+ vtsHeading: vtsHeading$b,
+ vtsInstructions1: vtsInstructions1$b,
+ vtsInstructions2: vtsInstructions2$b,
+ vtsInstructions3: vtsInstructions3$b,
+ vtsInstructions4: vtsInstructions4$b,
+ vtsInstructions5: vtsInstructions5$b,
+ vtsSelectLanguage: vtsSelectLanguage$b,
+ vtsSave: vtsSave$b,
+ vtsReturn: vtsReturn$b,
+ vtsCancel: vtsCancel$b,
+ vtsRow: vtsRow$b,
+ vtsKind: vtsKind$b,
+ vtsStart: vtsStart$b,
+ vtsEnd: vtsEnd$b,
+ vtsContent: vtsContent$b,
+ vtsActions: vtsActions$b,
+ vtsNewRow: vtsNewRow$b,
+ vtsDeletedRow: vtsDeletedRow$b,
+ vtsMovedRow: vtsMovedRow$b
+ };
+
+ var playerHeading$a = "メディアプレイヤー";
+ var audioPlayer$a = "Audio player";
+ var videoPlayer$a = "Video player";
+ var faster$a = "はやく";
+ var slower$a = "おそく";
+ var play$a = "再生";
+ var pause$a = "一時停止";
+ var restart$a = "再開";
+ var prevTrack$a = "前のトラック";
+ var nextTrack$a = "次のトラック";
+ var rewind$a = "巻き戻し";
+ var forward$a = "早送り";
+ var captions$a = "キャプション";
+ var showCaptions$a = "キャプションを表示する";
+ var hideCaptions$a = "キャプションを非表示にする";
+ var captionsOff$a = "キャプションを消す";
+ var showTranscript$a = "書き起こしの表示";
+ var hideTranscript$a = "書き起こしを非表示にする";
+ var turnOnDescriptions$a = "音声解説を出す";
+ var turnOffDescriptions$a = "音声解説を出さない";
+ var chapters$a = "チャプター";
+ var language$a = "言語";
+ var sign$a = "手話";
+ var showSign$a = "手話を表示";
+ var hideSign$a = "手話を非表示";
+ var seekbarLabel$a = "タイムライン";
+ var mute$a = "消音";
+ var unmute$a = "消音解除";
+ var volume$a = "音量";
+ var volumeUpDown$a = "音量の上下";
+ var preferences$a = "設定";
+ var enterFullScreen$a = "全画面表示";
+ var exitFullScreen$a = "全画面表示の終了";
+ var speed$a = "再生速度";
+ var spacebar$a = "スペースキー";
+ var transcriptTitle$a = "書き起こし";
+ var lyricsTitle$a = "歌詞";
+ var autoScroll$a = "自動スクロール";
+ var statusPlaying$a = "再生中";
+ var statusPaused$a = "一時停止中";
+ var statusStopped$a = "停止";
+ var statusBuffering$a = "バッファリング中";
+ var statusEnd$a = "トラックの終わり";
+ var selectedTrack$a = "選択されたトラック";
+ var alertDescribedVersion$a = "この動画の音声解説付きバージョンを使います";
+ var alertNonDescribedVersion$a = "この動画の解説なしバージョンを使います";
+ var prefMenuCaptions$a = "キャプション";
+ var prefVoicedCaptions$a = "Spoken Captions";
+ var prefMenuDescriptions$a = "音声解説";
+ var prefMenuKeyboard$a = "キーボード";
+ var prefMenuTranscript$a = "字幕";
+ var prefTitleCaptions$a = "キャプションの設定";
+ var prefTitleDescriptions$a = "音声解説の設定";
+ var prefTitleKeyboard$a = "キーボードの設定";
+ var prefTitleTranscript$a = "字幕の設定";
+ var prefIntroDescription1$a = "このメディアプレイヤーは次の2つの方法で音声解説をサポートします: ";
+ var prefDescription1$a = "現在の動画では次の方法が選択可能です: 解説付きの代替バージョン テキストによる解説";
+ var prefDescription2$a = "現在の動画では次の方法が選択可能です: 解説付きの代替バージョンのビデオ";
+ var prefDescription3$a = "現在の動画では次の方法が選択可能です: テキストによる解説(スクリーンリーダーによって読み上げられる)";
+ var prefIntroDescriptionNone$a = "現在の動画にはどちらの形式の音声解説も含まれていません。";
+ var prefIntroDescription3$a = "次のフォームを使って、音声解説に関連する設定を保存できます。";
+ var prefIntroDescription4$a = "設定が保存されたら、音声解説ボタンによって音声解説の表示・非表示を切り替えることができます。";
+ var prefIntroKeyboard1$a = "このページのメディアプレイヤーは、キーボード・ショートカットを使ってこのページのどこからでも操作できます(下の一覧を参照してください)。";
+ var prefIntroKeyboard2$a = "修飾キー(Shift、Alt と Control) は以下で割り当てることができます。";
+ var prefIntroKeyboard3$a = "注意: いくつかのキーの組み合わせは、ブラウザやアプリケーション・ソフトで使われているものと衝突する可能性があります。ご利用の環境で正しく動作する、様々なキーの組み合わせを試してください。";
+ var prefHeadingKeyboard1$a = "ショートカットの修飾キー";
+ var prefHeadingKeyboard2$a = "現在のキーボード・ショートカット";
+ var prefHeadingDescription$a = "音声解説";
+ var prefHeadingTextDescription$a = "テキストによる音声解説";
+ var prefAltKey$a = "Alt";
+ var prefCtrlKey$a = "Control";
+ var prefShiftKey$a = "Shift";
+ var prefNoKeyShortcuts$a = "Disable keyboard shortcuts";
+ var escapeKey$a = "エスケープ";
+ var escapeKeyFunction$a = "現在のダイアログやポップアップメニューを閉じる";
+ var prefDescPause$a = "解説が表示されたら動画を自動的に停止する";
+ var prefDescVisible$a = "解説が見えるようにする";
+ var prefDescVoice$a = "音";
+ var prefDescRate$a = "Spoken Description Rate";
+ var prefCaptionRate$a = "Spoken Caption Rate";
+ var prefDescPitch$a = "ピッチ";
+ var prefDescPitch1$a = "非常に低い";
+ var prefDescPitch2$a = "低い";
+ var prefDescPitch3$a = "標準";
+ var prefDescPitch4$a = "高い";
+ var prefDescPitch5$a = "非常に高い";
+ var sampleDescriptionText$a = "このサンプル・テキストを聞くために設定を合わせます。";
+ var prefHighlight$a = "メディアの再生に合わせて字幕をハイライトする";
+ var prefTabbable$a = "キーボード操作可能な字幕";
+ var prefCaptionsFont$a = "フォント";
+ var prefCaptionsColor$a = "文字色";
+ var prefCaptionsBGColor$a = "背景色";
+ var prefCaptionsSize$a = "フォントサイズ";
+ var prefCaptionsOpacity$a = "不透明度";
+ var prefCaptionsStyle$a = "書式";
+ var serif$a = "セリフ";
+ var sans$a = "サンセリフ";
+ var cursive$a = "cursive";
+ var fantasy$a = "fantasy";
+ var monospace$a = "monospace";
+ var white$a = "白";
+ var yellow$a = "黄色";
+ var green$a = "緑";
+ var cyan$a = "シアン";
+ var blue$a = "青";
+ var magenta$a = "マゼンタ";
+ var red$a = "赤";
+ var black$a = "黒";
+ var transparent$a = "透明";
+ var solid$a = "不透明";
+ var captionsStylePopOn$a = "ポップ・オン";
+ var captionsStyleRollUp$a = "ロール・アップ";
+ var prefCaptionsPosition$a = "位置";
+ var captionsPositionOverlay$a = "オーバーレイ表示";
+ var captionsPositionBelow$a = "動画の下部";
+ var sampleCaptionText$a = "キャプション表示の例";
+ var prefSuccess$a = "変更が保存されました。";
+ var prefNoChange$a = "設定が変更されていません。";
+ var save$a = "保存";
+ var cancel$a = "キャンセル";
+ var dismissButton$a = "Dismiss";
+ var windowButtonLabel$a = "ウィンドウの設定";
+ var windowMove$a = "移動";
+ var windowMoveLeft$a = "Window moved left";
+ var windowMoveRight$a = "Window moved right";
+ var windowMoveUp$a = "Window moved up";
+ var windowMoveDown$a = "Window moved down";
+ var windowMoveStopped$a = "Window move stopped";
+ var transcriptControls$a = "Transcript Window Controls";
+ var signControls$a = "Sign Language Window Controls";
+ var windowMoveAlert$a = "マウスをドラッグするか矢印キーでウィンドウを移動できます; Enterで終了";
+ var windowResize$a = "サイズを変える";
+ var windowResizeHeading$a = "ウィンドウのサイズ変更";
+ var closeButtonLabel$a = "閉じる";
+ var width$a = "幅";
+ var height$a = "高さ";
+ var resultsSummary1$a = "次を検索:";
+ var resultsSummary2$a = "見つかりました %1 個の検索結果";
+ var resultsSummary3$a = "アイテムに関連付けられている時間をクリックして、その時点からビデオを再生します。";
+ var noResultsFound$a = "見つかりませんでした。";
+ var searchButtonLabel$a = "次から再生 %1";
+ var hour$a = "時間";
+ var minute$a = "分";
+ var second$a = "秒";
+ var hours$a = "時間";
+ var minutes$a = "分";
+ var seconds$a = "秒";
+ var vtsHeading$a = "Video Transcript Sorter";
+ var vtsInstructions1$a = "Use the Video Transcript Sorter to modify text tracks:";
+ var vtsInstructions2$a = "Reorder chapters, descriptions, captions, and/or subtitles so they appear in the proper sequence in Able Player's auto-generated transcript.";
+ var vtsInstructions3$a = "Modify content or start/end times (all are directly editable within the table).";
+ var vtsInstructions4$a = "Add new content, such as chapters or descriptions.";
+ var vtsInstructions5$a = "After editing, click the \"Save Changes\" button to generate new content for all relevant timed text files. The new text can be copied and pasted into new WebVTT files.";
+ var vtsSelectLanguage$a = "Select a language";
+ var vtsSave$a = "Generate new .vtt content";
+ var vtsReturn$a = "Return to Editor";
+ var vtsCancel$a = "Cancelling saving. Any edits you made have been restored in the VTS table.";
+ var vtsRow$a = "Row";
+ var vtsKind$a = "Kind";
+ var vtsStart$a = "Start";
+ var vtsEnd$a = "End";
+ var vtsContent$a = "Content";
+ var vtsActions$a = "Actions";
+ var vtsNewRow$a = "A new row %1 has been inserted.";
+ var vtsDeletedRow$a = "Row %1 has been deleted.";
+ var vtsMovedRow$a = "Row %1 has been moved %2 and is now Row %3.";
+ var ja = {
+ playerHeading: playerHeading$a,
+ audioPlayer: audioPlayer$a,
+ videoPlayer: videoPlayer$a,
+ faster: faster$a,
+ slower: slower$a,
+ play: play$a,
+ pause: pause$a,
+ restart: restart$a,
+ prevTrack: prevTrack$a,
+ nextTrack: nextTrack$a,
+ rewind: rewind$a,
+ forward: forward$a,
+ captions: captions$a,
+ showCaptions: showCaptions$a,
+ hideCaptions: hideCaptions$a,
+ captionsOff: captionsOff$a,
+ showTranscript: showTranscript$a,
+ hideTranscript: hideTranscript$a,
+ turnOnDescriptions: turnOnDescriptions$a,
+ turnOffDescriptions: turnOffDescriptions$a,
+ chapters: chapters$a,
+ language: language$a,
+ sign: sign$a,
+ showSign: showSign$a,
+ hideSign: hideSign$a,
+ seekbarLabel: seekbarLabel$a,
+ mute: mute$a,
+ unmute: unmute$a,
+ volume: volume$a,
+ volumeUpDown: volumeUpDown$a,
+ preferences: preferences$a,
+ enterFullScreen: enterFullScreen$a,
+ exitFullScreen: exitFullScreen$a,
+ speed: speed$a,
+ spacebar: spacebar$a,
+ transcriptTitle: transcriptTitle$a,
+ lyricsTitle: lyricsTitle$a,
+ autoScroll: autoScroll$a,
+ statusPlaying: statusPlaying$a,
+ statusPaused: statusPaused$a,
+ statusStopped: statusStopped$a,
+ statusBuffering: statusBuffering$a,
+ statusEnd: statusEnd$a,
+ selectedTrack: selectedTrack$a,
+ alertDescribedVersion: alertDescribedVersion$a,
+ alertNonDescribedVersion: alertNonDescribedVersion$a,
+ prefMenuCaptions: prefMenuCaptions$a,
+ prefVoicedCaptions: prefVoicedCaptions$a,
+ prefMenuDescriptions: prefMenuDescriptions$a,
+ prefMenuKeyboard: prefMenuKeyboard$a,
+ prefMenuTranscript: prefMenuTranscript$a,
+ prefTitleCaptions: prefTitleCaptions$a,
+ prefTitleDescriptions: prefTitleDescriptions$a,
+ prefTitleKeyboard: prefTitleKeyboard$a,
+ prefTitleTranscript: prefTitleTranscript$a,
+ prefIntroDescription1: prefIntroDescription1$a,
+ prefDescription1: prefDescription1$a,
+ prefDescription2: prefDescription2$a,
+ prefDescription3: prefDescription3$a,
+ prefIntroDescriptionNone: prefIntroDescriptionNone$a,
+ prefIntroDescription3: prefIntroDescription3$a,
+ prefIntroDescription4: prefIntroDescription4$a,
+ prefIntroKeyboard1: prefIntroKeyboard1$a,
+ prefIntroKeyboard2: prefIntroKeyboard2$a,
+ prefIntroKeyboard3: prefIntroKeyboard3$a,
+ prefHeadingKeyboard1: prefHeadingKeyboard1$a,
+ prefHeadingKeyboard2: prefHeadingKeyboard2$a,
+ prefHeadingDescription: prefHeadingDescription$a,
+ prefHeadingTextDescription: prefHeadingTextDescription$a,
+ prefAltKey: prefAltKey$a,
+ prefCtrlKey: prefCtrlKey$a,
+ prefShiftKey: prefShiftKey$a,
+ prefNoKeyShortcuts: prefNoKeyShortcuts$a,
+ escapeKey: escapeKey$a,
+ escapeKeyFunction: escapeKeyFunction$a,
+ prefDescPause: prefDescPause$a,
+ prefDescVisible: prefDescVisible$a,
+ prefDescVoice: prefDescVoice$a,
+ prefDescRate: prefDescRate$a,
+ prefCaptionRate: prefCaptionRate$a,
+ prefDescPitch: prefDescPitch$a,
+ prefDescPitch1: prefDescPitch1$a,
+ prefDescPitch2: prefDescPitch2$a,
+ prefDescPitch3: prefDescPitch3$a,
+ prefDescPitch4: prefDescPitch4$a,
+ prefDescPitch5: prefDescPitch5$a,
+ sampleDescriptionText: sampleDescriptionText$a,
+ prefHighlight: prefHighlight$a,
+ prefTabbable: prefTabbable$a,
+ prefCaptionsFont: prefCaptionsFont$a,
+ prefCaptionsColor: prefCaptionsColor$a,
+ prefCaptionsBGColor: prefCaptionsBGColor$a,
+ prefCaptionsSize: prefCaptionsSize$a,
+ prefCaptionsOpacity: prefCaptionsOpacity$a,
+ prefCaptionsStyle: prefCaptionsStyle$a,
+ serif: serif$a,
+ sans: sans$a,
+ cursive: cursive$a,
+ fantasy: fantasy$a,
+ monospace: monospace$a,
+ white: white$a,
+ yellow: yellow$a,
+ green: green$a,
+ cyan: cyan$a,
+ blue: blue$a,
+ magenta: magenta$a,
+ red: red$a,
+ black: black$a,
+ transparent: transparent$a,
+ solid: solid$a,
+ captionsStylePopOn: captionsStylePopOn$a,
+ captionsStyleRollUp: captionsStyleRollUp$a,
+ prefCaptionsPosition: prefCaptionsPosition$a,
+ captionsPositionOverlay: captionsPositionOverlay$a,
+ captionsPositionBelow: captionsPositionBelow$a,
+ sampleCaptionText: sampleCaptionText$a,
+ prefSuccess: prefSuccess$a,
+ prefNoChange: prefNoChange$a,
+ save: save$a,
+ cancel: cancel$a,
+ dismissButton: dismissButton$a,
+ windowButtonLabel: windowButtonLabel$a,
+ windowMove: windowMove$a,
+ windowMoveLeft: windowMoveLeft$a,
+ windowMoveRight: windowMoveRight$a,
+ windowMoveUp: windowMoveUp$a,
+ windowMoveDown: windowMoveDown$a,
+ windowMoveStopped: windowMoveStopped$a,
+ transcriptControls: transcriptControls$a,
+ signControls: signControls$a,
+ windowMoveAlert: windowMoveAlert$a,
+ windowResize: windowResize$a,
+ windowResizeHeading: windowResizeHeading$a,
+ closeButtonLabel: closeButtonLabel$a,
+ width: width$a,
+ height: height$a,
+ resultsSummary1: resultsSummary1$a,
+ resultsSummary2: resultsSummary2$a,
+ resultsSummary3: resultsSummary3$a,
+ noResultsFound: noResultsFound$a,
+ searchButtonLabel: searchButtonLabel$a,
+ hour: hour$a,
+ minute: minute$a,
+ second: second$a,
+ hours: hours$a,
+ minutes: minutes$a,
+ seconds: seconds$a,
+ vtsHeading: vtsHeading$a,
+ vtsInstructions1: vtsInstructions1$a,
+ vtsInstructions2: vtsInstructions2$a,
+ vtsInstructions3: vtsInstructions3$a,
+ vtsInstructions4: vtsInstructions4$a,
+ vtsInstructions5: vtsInstructions5$a,
+ vtsSelectLanguage: vtsSelectLanguage$a,
+ vtsSave: vtsSave$a,
+ vtsReturn: vtsReturn$a,
+ vtsCancel: vtsCancel$a,
+ vtsRow: vtsRow$a,
+ vtsKind: vtsKind$a,
+ vtsStart: vtsStart$a,
+ vtsEnd: vtsEnd$a,
+ vtsContent: vtsContent$a,
+ vtsActions: vtsActions$a,
+ vtsNewRow: vtsNewRow$a,
+ vtsDeletedRow: vtsDeletedRow$a,
+ vtsMovedRow: vtsMovedRow$a
+ };
+
+ var playerHeading$9 = "Pemain media";
+ var audioPlayer$9 = "Audio player";
+ var videoPlayer$9 = "Video player";
+ var faster$9 = "Lebih laju";
+ var slower$9 = "Lebih perlahan";
+ var play$9 = "Main";
+ var pause$9 = "Jeda";
+ var restart$9 = "Mula semula";
+ var prevTrack$9 = "Trek sebelumnya";
+ var nextTrack$9 = "Trek seterusnya";
+ var rewind$9 = "Undur";
+ var forward$9 = "Majukan";
+ var captions$9 = "Sarikata";
+ var showCaptions$9 = "Tunjuk sarikata";
+ var hideCaptions$9 = "Sembunyi sarikata";
+ var captionsOff$9 = "Sarikata dimatikan";
+ var showTranscript$9 = "Tunjuk transkrip";
+ var hideTranscript$9 = "Sembunyi transkrip";
+ var turnOnDescriptions$9 = "Hidupkan deskripsi";
+ var turnOffDescriptions$9 = "Matikan deskripsi";
+ var chapters$9 = "Bab";
+ var language$9 = "Bahasa";
+ var sign$9 = "Bahasa isyarat";
+ var showSign$9 = "Tunjuk bahasa isyarat";
+ var hideSign$9 = "Sembunyi bahasa isyarat";
+ var seekbarLabel$9 = "garis masa";
+ var mute$9 = "Bisukan";
+ var unmute$9 = "Nyahbisukan";
+ var volume$9 = "Volum";
+ var volumeUpDown$9 = "Naik turun volum";
+ var preferences$9 = "Keutamaan";
+ var enterFullScreen$9 = "Masuk skrin penuh";
+ var exitFullScreen$9 = "Keluar skrin penuh";
+ var speed$9 = "Kelajuan";
+ var spacebar$9 = "bar ruang";
+ var transcriptTitle$9 = "Transkrip";
+ var lyricsTitle$9 = "Lirik";
+ var autoScroll$9 = "Skrol automatik";
+ var statusPlaying$9 = "Sedang dimainkan";
+ var statusPaused$9 = "Dijeda";
+ var statusStopped$9 = "Dihentikan";
+ var statusBuffering$9 = "Memuatkan";
+ var statusEnd$9 = "Akhir trek";
+ var selectedTrack$9 = "Trek dipilih";
+ var alertDescribedVersion$9 = "Menggunakan versi video dengan deskripsi audio";
+ var alertNonDescribedVersion$9 = "Menggunakan versi video tanpa deskripsi audio";
+ var prefMenuCaptions$9 = "Sarikata";
+ var prefVoicedCaptions$9 = "Spoken Captions";
+ var prefMenuDescriptions$9 = "Deskripsi";
+ var prefMenuKeyboard$9 = "Papan kekunci";
+ var prefMenuTranscript$9 = "Transkrip";
+ var prefTitleCaptions$9 = "Keutamaan Sarikata";
+ var prefTitleDescriptions$9 = "Keutamaan Deskripsi Audio";
+ var prefTitleKeyboard$9 = "Keutamaan Papan Kekunci";
+ var prefTitleTranscript$9 = "Keutamaan Transkrip";
+ var prefIntroDescription1$9 = "Pemain media ini menyokong deskripsi audio dalam dua cara: ";
+ var prefDescription1$9 = "Video semasa mempunyai versi berdeskripsi alternatif, deskripsi berasaskan teks.";
+ var prefDescription2$9 = "Video semasa mempunyai versi video berdeskripsi alternatif.";
+ var prefDescription3$9 = "Video semasa mempunyai deskripsi berasaskan teks, diumumkan oleh pembaca skrin.";
+ var prefIntroDescriptionNone$9 = "Video semasa tiada deskripsi audio dalam mana-mana format.";
+ var prefIntroDescription3$9 = "Gunakan borang berikut untuk menetapkan keutamaan berkaitan deskripsi audio berasaskan teks.";
+ var prefIntroDescription4$9 = "Selepas anda menyimpan tetapan, deskripsi audio boleh dihidupkan/dimatikan menggunakan butang Deskripsi.";
+ var prefIntroKeyboard1$9 = "Pemain media di laman web ini boleh dikendalikan dari mana-mana sahaja di halaman menggunakan pintasan papan kekunci (lihat di bawah untuk senarai).";
+ var prefIntroKeyboard2$9 = "Kekunci pengubah (Shift, Alt, dan Control) boleh ditetapkan di bawah.";
+ var prefIntroKeyboard3$9 = "NOTA: Sesetengah kombinasi kekunci mungkin bertindah dengan kekunci yang digunakan oleh pelayar dan/atau aplikasi lain. Cuba pelbagai kombinasi kekunci pengubah untuk mencari yang sesuai untuk anda.";
+ var prefHeadingKeyboard1$9 = "Kekunci pengubah untuk pintasan";
+ var prefHeadingKeyboard2$9 = "Pintasan papan kekunci semasa";
+ var prefHeadingDescription$9 = "Deskripsi audio";
+ var prefHeadingTextDescription$9 = "Deskripsi audio berasaskan teks";
+ var prefAltKey$9 = "Alt";
+ var prefCtrlKey$9 = "Control";
+ var prefShiftKey$9 = "Shift";
+ var prefNoKeyShortcuts$9 = "Disable keyboard shortcuts";
+ var escapeKey$9 = "Escape";
+ var escapeKeyFunction$9 = "Tutup dialog atau menu popup semasa";
+ var prefDescPause$9 = "Jeda video secara automatik apabila deskripsi bermula";
+ var prefDescVisible$9 = "Paparkan deskripsi";
+ var prefDescVoice$9 = "Suara";
+ var prefDescRate$9 = "Spoken Description Rate";
+ var prefCaptionRate$9 = "Spoken Caption Rate";
+ var prefDescPitch$9 = "Nada";
+ var prefDescPitch1$9 = "Sangat rendah";
+ var prefDescPitch2$9 = "Rendah";
+ var prefDescPitch3$9 = "Lalai";
+ var prefDescPitch4$9 = "Tinggi";
+ var prefDescPitch5$9 = "Sangat tinggi";
+ var sampleDescriptionText$9 = "Laraskan tetapan untuk mendengar teks contoh ini.";
+ var prefHighlight$9 = "Serlahkan transkrip semasa media dimainkan";
+ var prefTabbable$9 = "Aktifkan transkrip dengan papan kekunci";
+ var prefCaptionsFont$9 = "Fon";
+ var prefCaptionsColor$9 = "Warna Teks";
+ var prefCaptionsBGColor$9 = "Latar Belakang";
+ var prefCaptionsSize$9 = "Saiz Fon";
+ var prefCaptionsOpacity$9 = "Kelegapan";
+ var prefCaptionsStyle$9 = "Gaya";
+ var serif$9 = "serif";
+ var sans$9 = "sans-serif";
+ var cursive$9 = "cursive";
+ var fantasy$9 = "fantasy";
+ var monospace$9 = "monospace";
+ var white$9 = "putih";
+ var yellow$9 = "kuning";
+ var green$9 = "hijau";
+ var cyan$9 = "sian";
+ var blue$9 = "biru";
+ var magenta$9 = "magenta";
+ var red$9 = "merah";
+ var black$9 = "hitam";
+ var transparent$9 = "telus";
+ var solid$9 = "pepejal";
+ var captionsStylePopOn$9 = "Pop-on";
+ var captionsStyleRollUp$9 = "Roll-up";
+ var prefCaptionsPosition$9 = "Kedudukan";
+ var captionsPositionOverlay$9 = "Lapisan atas";
+ var captionsPositionBelow$9 = "Di bawah video";
+ var sampleCaptionText$9 = "Teks contoh sarikata";
+ var prefSuccess$9 = "Perubahan anda telah disimpan.";
+ var prefNoChange$9 = "Anda tidak membuat sebarang perubahan.";
+ var save$9 = "Simpan";
+ var cancel$9 = "Batal";
+ var dismissButton$9 = "Dismiss";
+ var windowButtonLabel$9 = "Pilihan tetingkap";
+ var windowMove$9 = "Alih";
+ var windowMoveLeft$9 = "Window moved left";
+ var windowMoveRight$9 = "Window moved right";
+ var windowMoveUp$9 = "Window moved up";
+ var windowMoveDown$9 = "Window moved down";
+ var windowMoveStopped$9 = "Window move stopped";
+ var transcriptControls$9 = "Transcript Window Controls";
+ var signControls$9 = "Sign Language Window Controls";
+ var windowMoveAlert$9 = "Seret atau gunakan kekunci anak panah untuk mengalih tetingkap; Enter untuk berhenti";
+ var windowResize$9 = "Ubah saiz";
+ var windowResizeHeading$9 = "Ubah Saiz Tetingkap";
+ var closeButtonLabel$9 = "Tutup";
+ var width$9 = "Lebar";
+ var height$9 = "Tinggi";
+ var resultsSummary1$9 = "Anda mencari:";
+ var resultsSummary2$9 = "Ditemui %1 item sepadan.";
+ var resultsSummary3$9 = "Klik masa yang berkaitan dengan mana-mana item untuk mainkan video dari titik itu.";
+ var noResultsFound$9 = "Tiada hasil ditemui.";
+ var searchButtonLabel$9 = "Main pada %1";
+ var hour$9 = "jam";
+ var minute$9 = "minit";
+ var second$9 = "saat";
+ var hours$9 = "jam";
+ var minutes$9 = "minit";
+ var seconds$9 = "saat";
+ var vtsHeading$9 = "Video Transcript Sorter";
+ var vtsInstructions1$9 = "Use the Video Transcript Sorter to modify text tracks:";
+ var vtsInstructions2$9 = "Reorder chapters, descriptions, captions, and/or subtitles so they appear in the proper sequence in Able Player's auto-generated transcript.";
+ var vtsInstructions3$9 = "Modify content or start/end times (all are directly editable within the table).";
+ var vtsInstructions4$9 = "Add new content, such as chapters or descriptions.";
+ var vtsInstructions5$9 = "After editing, click the \"Save Changes\" button to generate new content for all relevant timed text files. The new text can be copied and pasted into new WebVTT files.";
+ var vtsSelectLanguage$9 = "Select a language";
+ var vtsSave$9 = "Generate new .vtt content";
+ var vtsReturn$9 = "Return to Editor";
+ var vtsCancel$9 = "Cancelling saving. Any edits you made have been restored in the VTS table.";
+ var vtsRow$9 = "Row";
+ var vtsKind$9 = "Kind";
+ var vtsStart$9 = "Start";
+ var vtsEnd$9 = "End";
+ var vtsContent$9 = "Content";
+ var vtsActions$9 = "Actions";
+ var vtsNewRow$9 = "A new row %1 has been inserted.";
+ var vtsDeletedRow$9 = "Row %1 has been deleted.";
+ var vtsMovedRow$9 = "Row %1 has been moved %2 and is now Row %3.";
+ var ms = {
+ playerHeading: playerHeading$9,
+ audioPlayer: audioPlayer$9,
+ videoPlayer: videoPlayer$9,
+ faster: faster$9,
+ slower: slower$9,
+ play: play$9,
+ pause: pause$9,
+ restart: restart$9,
+ prevTrack: prevTrack$9,
+ nextTrack: nextTrack$9,
+ rewind: rewind$9,
+ forward: forward$9,
+ captions: captions$9,
+ showCaptions: showCaptions$9,
+ hideCaptions: hideCaptions$9,
+ captionsOff: captionsOff$9,
+ showTranscript: showTranscript$9,
+ hideTranscript: hideTranscript$9,
+ turnOnDescriptions: turnOnDescriptions$9,
+ turnOffDescriptions: turnOffDescriptions$9,
+ chapters: chapters$9,
+ language: language$9,
+ sign: sign$9,
+ showSign: showSign$9,
+ hideSign: hideSign$9,
+ seekbarLabel: seekbarLabel$9,
+ mute: mute$9,
+ unmute: unmute$9,
+ volume: volume$9,
+ volumeUpDown: volumeUpDown$9,
+ preferences: preferences$9,
+ enterFullScreen: enterFullScreen$9,
+ exitFullScreen: exitFullScreen$9,
+ speed: speed$9,
+ spacebar: spacebar$9,
+ transcriptTitle: transcriptTitle$9,
+ lyricsTitle: lyricsTitle$9,
+ autoScroll: autoScroll$9,
+ statusPlaying: statusPlaying$9,
+ statusPaused: statusPaused$9,
+ statusStopped: statusStopped$9,
+ statusBuffering: statusBuffering$9,
+ statusEnd: statusEnd$9,
+ selectedTrack: selectedTrack$9,
+ alertDescribedVersion: alertDescribedVersion$9,
+ alertNonDescribedVersion: alertNonDescribedVersion$9,
+ prefMenuCaptions: prefMenuCaptions$9,
+ prefVoicedCaptions: prefVoicedCaptions$9,
+ prefMenuDescriptions: prefMenuDescriptions$9,
+ prefMenuKeyboard: prefMenuKeyboard$9,
+ prefMenuTranscript: prefMenuTranscript$9,
+ prefTitleCaptions: prefTitleCaptions$9,
+ prefTitleDescriptions: prefTitleDescriptions$9,
+ prefTitleKeyboard: prefTitleKeyboard$9,
+ prefTitleTranscript: prefTitleTranscript$9,
+ prefIntroDescription1: prefIntroDescription1$9,
+ prefDescription1: prefDescription1$9,
+ prefDescription2: prefDescription2$9,
+ prefDescription3: prefDescription3$9,
+ prefIntroDescriptionNone: prefIntroDescriptionNone$9,
+ prefIntroDescription3: prefIntroDescription3$9,
+ prefIntroDescription4: prefIntroDescription4$9,
+ prefIntroKeyboard1: prefIntroKeyboard1$9,
+ prefIntroKeyboard2: prefIntroKeyboard2$9,
+ prefIntroKeyboard3: prefIntroKeyboard3$9,
+ prefHeadingKeyboard1: prefHeadingKeyboard1$9,
+ prefHeadingKeyboard2: prefHeadingKeyboard2$9,
+ prefHeadingDescription: prefHeadingDescription$9,
+ prefHeadingTextDescription: prefHeadingTextDescription$9,
+ prefAltKey: prefAltKey$9,
+ prefCtrlKey: prefCtrlKey$9,
+ prefShiftKey: prefShiftKey$9,
+ prefNoKeyShortcuts: prefNoKeyShortcuts$9,
+ escapeKey: escapeKey$9,
+ escapeKeyFunction: escapeKeyFunction$9,
+ prefDescPause: prefDescPause$9,
+ prefDescVisible: prefDescVisible$9,
+ prefDescVoice: prefDescVoice$9,
+ prefDescRate: prefDescRate$9,
+ prefCaptionRate: prefCaptionRate$9,
+ prefDescPitch: prefDescPitch$9,
+ prefDescPitch1: prefDescPitch1$9,
+ prefDescPitch2: prefDescPitch2$9,
+ prefDescPitch3: prefDescPitch3$9,
+ prefDescPitch4: prefDescPitch4$9,
+ prefDescPitch5: prefDescPitch5$9,
+ sampleDescriptionText: sampleDescriptionText$9,
+ prefHighlight: prefHighlight$9,
+ prefTabbable: prefTabbable$9,
+ prefCaptionsFont: prefCaptionsFont$9,
+ prefCaptionsColor: prefCaptionsColor$9,
+ prefCaptionsBGColor: prefCaptionsBGColor$9,
+ prefCaptionsSize: prefCaptionsSize$9,
+ prefCaptionsOpacity: prefCaptionsOpacity$9,
+ prefCaptionsStyle: prefCaptionsStyle$9,
+ serif: serif$9,
+ sans: sans$9,
+ cursive: cursive$9,
+ fantasy: fantasy$9,
+ monospace: monospace$9,
+ white: white$9,
+ yellow: yellow$9,
+ green: green$9,
+ cyan: cyan$9,
+ blue: blue$9,
+ magenta: magenta$9,
+ red: red$9,
+ black: black$9,
+ transparent: transparent$9,
+ solid: solid$9,
+ captionsStylePopOn: captionsStylePopOn$9,
+ captionsStyleRollUp: captionsStyleRollUp$9,
+ prefCaptionsPosition: prefCaptionsPosition$9,
+ captionsPositionOverlay: captionsPositionOverlay$9,
+ captionsPositionBelow: captionsPositionBelow$9,
+ sampleCaptionText: sampleCaptionText$9,
+ prefSuccess: prefSuccess$9,
+ prefNoChange: prefNoChange$9,
+ save: save$9,
+ cancel: cancel$9,
+ dismissButton: dismissButton$9,
+ windowButtonLabel: windowButtonLabel$9,
+ windowMove: windowMove$9,
+ windowMoveLeft: windowMoveLeft$9,
+ windowMoveRight: windowMoveRight$9,
+ windowMoveUp: windowMoveUp$9,
+ windowMoveDown: windowMoveDown$9,
+ windowMoveStopped: windowMoveStopped$9,
+ transcriptControls: transcriptControls$9,
+ signControls: signControls$9,
+ windowMoveAlert: windowMoveAlert$9,
+ windowResize: windowResize$9,
+ windowResizeHeading: windowResizeHeading$9,
+ closeButtonLabel: closeButtonLabel$9,
+ width: width$9,
+ height: height$9,
+ resultsSummary1: resultsSummary1$9,
+ resultsSummary2: resultsSummary2$9,
+ resultsSummary3: resultsSummary3$9,
+ noResultsFound: noResultsFound$9,
+ searchButtonLabel: searchButtonLabel$9,
+ hour: hour$9,
+ minute: minute$9,
+ second: second$9,
+ hours: hours$9,
+ minutes: minutes$9,
+ seconds: seconds$9,
+ vtsHeading: vtsHeading$9,
+ vtsInstructions1: vtsInstructions1$9,
+ vtsInstructions2: vtsInstructions2$9,
+ vtsInstructions3: vtsInstructions3$9,
+ vtsInstructions4: vtsInstructions4$9,
+ vtsInstructions5: vtsInstructions5$9,
+ vtsSelectLanguage: vtsSelectLanguage$9,
+ vtsSave: vtsSave$9,
+ vtsReturn: vtsReturn$9,
+ vtsCancel: vtsCancel$9,
+ vtsRow: vtsRow$9,
+ vtsKind: vtsKind$9,
+ vtsStart: vtsStart$9,
+ vtsEnd: vtsEnd$9,
+ vtsContent: vtsContent$9,
+ vtsActions: vtsActions$9,
+ vtsNewRow: vtsNewRow$9,
+ vtsDeletedRow: vtsDeletedRow$9,
+ vtsMovedRow: vtsMovedRow$9
+ };
+
+ var playerHeading$8 = "Mediespiller";
+ var audioPlayer$8 = "Audio player";
+ var videoPlayer$8 = "Video player";
+ var faster$8 = "Raskere";
+ var slower$8 = "Saktere";
+ var play$8 = "Spill av";
+ var pause$8 = "Pause";
+ var restart$8 = "Start på nytt";
+ var prevTrack$8 = "Forrige spor";
+ var nextTrack$8 = "Neste spor";
+ var rewind$8 = "Spol tilbake";
+ var forward$8 = "Spol fremover";
+ var captions$8 = "Undertekster";
+ var showCaptions$8 = "Vis undertekster";
+ var hideCaptions$8 = "Skjul undertekster";
+ var captionsOff$8 = "Slå av undertekster";
+ var showTranscript$8 = "Vis transkripsjon";
+ var hideTranscript$8 = "Skjul transkripsjon";
+ var turnOnDescriptions$8 = "Slå på synstolking";
+ var turnOffDescriptions$8 = "Slå av synstolking";
+ var chapters$8 = "Kapitler";
+ var language$8 = "Språk";
+ var sign$8 = "Tegnspråk";
+ var showSign$8 = "Vis tegnspråk";
+ var hideSign$8 = "Skjul tegnspråk";
+ var seekbarLabel$8 = "tidslinje";
+ var mute$8 = "Lyd av";
+ var unmute$8 = "Lyd på";
+ var volume$8 = "Volum";
+ var volumeUpDown$8 = "Volumkontroll";
+ var preferences$8 = "Innstillinger";
+ var enterFullScreen$8 = "Vis fullskjerm";
+ var exitFullScreen$8 = "Avslutt fullskjerm";
+ var speed$8 = "Hastighet";
+ var spacebar$8 = "ordskiller";
+ var transcriptTitle$8 = "Transkripsjon";
+ var lyricsTitle$8 = "Teksting, verselinjer";
+ var autoScroll$8 = "Automatisk rulling";
+ var statusPlaying$8 = "Spiller av";
+ var statusPaused$8 = "Satt på pause";
+ var statusStopped$8 = "Stoppet";
+ var statusBuffering$8 = "Mottar data";
+ var statusEnd$8 = "Slutt på sporet";
+ var selectedTrack$8 = "Valgt spor";
+ var alertDescribedVersion$8 = "Bruker videoversjon med synstolking";
+ var alertNonDescribedVersion$8 = "Bruker videoversjon uten synstolking";
+ var prefMenuCaptions$8 = "Undertekster";
+ var prefVoicedCaptions$8 = "Spoken Captions";
+ var prefMenuDescriptions$8 = "Synstolking";
+ var prefMenuKeyboard$8 = "Tastatur";
+ var prefMenuTranscript$8 = "Transkripsjon";
+ var prefTitleCaptions$8 = "Undertekstinnstillinger";
+ var prefTitleDescriptions$8 = "Synstolkingsinnstillinger";
+ var prefTitleKeyboard$8 = "Tastaturinnstillinger";
+ var prefTitleTranscript$8 = "Transkripsjonsinnstillinger";
+ var prefIntroDescription1$8 = "Denne mediespilleren støtter lydbeskrivelse på to måter: ";
+ var prefDescription1$8 = "Denne videoen har en alternativ synstolket versjon, tekstbasert synstolking.";
+ var prefDescription2$8 = "Denne videoen har alternativ synstolket versjon av video.";
+ var prefDescription3$8 = "Denne videoen har tekstbasert synstolket versjon opplest av skjermleser.";
+ var prefIntroDescriptionNone$8 = "Denne videoen har ikke synstolking i noen av formatene.";
+ var prefIntroDescription3$8 = "Bruk følgende skjema for å gjøre dine valg angående tekstbasert synstolking.";
+ var prefIntroDescription4$8 = "Etter at du har lagret dine valg kan synstolking slås av og på med synstolkingsknappen.";
+ var prefIntroKeyboard1$8 = "Mediespilleren på denne nettsiden kan styres fra hvor som helst på siden ved hjelp av tastatursnarveier (se liste nedenfor).";
+ var prefIntroKeyboard2$8 = "Metataster (Shift, Alt, og Control) kan legges til nedenfor.";
+ var prefIntroKeyboard3$8 = "NB! Noen tastekombinasjoner kan komme i konflikt med taster som brukes av nettleseren din og/eller andre programmer. Prøv forskjellige tastekombinasjoner for å finne de som fungerer for deg.";
+ var prefHeadingKeyboard1$8 = "Metataster som brukes til tastekombinasjoner";
+ var prefHeadingKeyboard2$8 = "Nåværende tastekombinasjoner";
+ var prefHeadingDescription$8 = "Synstolking";
+ var prefHeadingTextDescription$8 = "Tekstbasert synstolking";
+ var prefAltKey$8 = "Alt";
+ var prefCtrlKey$8 = "Control";
+ var prefShiftKey$8 = "Shift";
+ var prefNoKeyShortcuts$8 = "Disable keyboard shortcuts";
+ var escapeKey$8 = "Escape";
+ var escapeKeyFunction$8 = "Lukk dialogboks eller popup-meny";
+ var prefDescPause$8 = "Sett video automatisk på pause når synstolking starter";
+ var prefDescVisible$8 = "Vis synstolking";
+ var prefDescVoice$8 = "Stemme";
+ var prefDescRate$8 = "Spoken Description Rate";
+ var prefCaptionRate$8 = "Spoken Caption Rate";
+ var prefDescPitch$8 = "Toneleie";
+ var prefDescPitch1$8 = "Meget lavt";
+ var prefDescPitch2$8 = "Lavt";
+ var prefDescPitch3$8 = "Normalt";
+ var prefDescPitch4$8 = "Høyt";
+ var prefDescPitch5$8 = "Meget høyt";
+ var sampleDescriptionText$8 = "Juster innstillingene for å høre denne eksempelteksten.";
+ var prefHighlight$8 = "Marker det som leses i transkripsjon ved avspilling";
+ var prefTabbable$8 = "Tastaturaktivert transkripsjon";
+ var prefCaptionsFont$8 = "Skrifttype";
+ var prefCaptionsColor$8 = "Skriftfarge";
+ var prefCaptionsBGColor$8 = "Bakgrunn";
+ var prefCaptionsSize$8 = "Skriftstørrelse";
+ var prefCaptionsOpacity$8 = "Ugjennomsiktighet";
+ var prefCaptionsStyle$8 = "Stil";
+ var serif$8 = "serif";
+ var sans$8 = "sans-serif";
+ var cursive$8 = "kursiv";
+ var fantasy$8 = "fantasi";
+ var monospace$8 = "ikke proporsjonal";
+ var white$8 = "hvit";
+ var yellow$8 = "gul";
+ var green$8 = "grønn";
+ var cyan$8 = "cyan";
+ var blue$8 = "blå";
+ var magenta$8 = "magenta";
+ var red$8 = "rød";
+ var black$8 = "sort";
+ var transparent$8 = "gjennomsiktig";
+ var solid$8 = "ugjennomsiktig";
+ var captionsStylePopOn$8 = "Dukker opp";
+ var captionsStyleRollUp$8 = "Ruller opp";
+ var prefCaptionsPosition$8 = "Posisjon";
+ var captionsPositionOverlay$8 = "Legg oppå video";
+ var captionsPositionBelow$8 = "Legg under video";
+ var sampleCaptionText$8 = "Eksempel på undertekst";
+ var prefSuccess$8 = "Dine endringer er lagret.";
+ var prefNoChange$8 = "Du gjorde ingen endringer.";
+ var save$8 = "Lagre";
+ var cancel$8 = "Avbryt";
+ var dismissButton$8 = "Dismiss";
+ var windowButtonLabel$8 = "Vindusinnstillinger";
+ var windowMove$8 = "Flytt";
+ var windowMoveLeft$8 = "Window moved left";
+ var windowMoveRight$8 = "Window moved right";
+ var windowMoveUp$8 = "Window moved up";
+ var windowMoveDown$8 = "Window moved down";
+ var windowMoveStopped$8 = "Window move stopped";
+ var transcriptControls$8 = "Transcript Window Controls";
+ var signControls$8 = "Sign Language Window Controls";
+ var windowMoveAlert$8 = "Dra eller bruk piltaster for å flytte vinduet; Enter-tast for å stoppe";
+ var windowResize$8 = "Endre størrelse";
+ var windowResizeHeading$8 = "Endre vindusstørrelse";
+ var closeButtonLabel$8 = "Lukk";
+ var width$8 = "Bredde";
+ var height$8 = "Høyde";
+ var resultsSummary1$8 = "Du søkte etter:";
+ var resultsSummary2$8 = "Funnet %1 passende treff.";
+ var resultsSummary3$8 = "Klikk tidspunkt på aktuelt treff for å avspille video derfra.";
+ var noResultsFound$8 = "Ingen treff funnet.";
+ var searchButtonLabel$8 = "Spill av fra %1";
+ var hour$8 = "time";
+ var minute$8 = "minutt";
+ var second$8 = "sekund";
+ var hours$8 = "timer";
+ var minutes$8 = "minutter";
+ var seconds$8 = "sekunder";
+ var vtsHeading$8 = "Video Transcript Sorter";
+ var vtsInstructions1$8 = "Use the Video Transcript Sorter to modify text tracks:";
+ var vtsInstructions2$8 = "Reorder chapters, descriptions, captions, and/or subtitles so they appear in the proper sequence in Able Player's auto-generated transcript.";
+ var vtsInstructions3$8 = "Modify content or start/end times (all are directly editable within the table).";
+ var vtsInstructions4$8 = "Add new content, such as chapters or descriptions.";
+ var vtsInstructions5$8 = "After editing, click the \"Save Changes\" button to generate new content for all relevant timed text files. The new text can be copied and pasted into new WebVTT files.";
+ var vtsSelectLanguage$8 = "Select a language";
+ var vtsSave$8 = "Generate new .vtt content";
+ var vtsReturn$8 = "Return to Editor";
+ var vtsCancel$8 = "Cancelling saving. Any edits you made have been restored in the VTS table.";
+ var vtsRow$8 = "Row";
+ var vtsKind$8 = "Kind";
+ var vtsStart$8 = "Start";
+ var vtsEnd$8 = "End";
+ var vtsContent$8 = "Content";
+ var vtsActions$8 = "Actions";
+ var vtsNewRow$8 = "A new row %1 has been inserted.";
+ var vtsDeletedRow$8 = "Row %1 has been deleted.";
+ var vtsMovedRow$8 = "Row %1 has been moved %2 and is now Row %3.";
+ var nb = {
+ playerHeading: playerHeading$8,
+ audioPlayer: audioPlayer$8,
+ videoPlayer: videoPlayer$8,
+ faster: faster$8,
+ slower: slower$8,
+ play: play$8,
+ pause: pause$8,
+ restart: restart$8,
+ prevTrack: prevTrack$8,
+ nextTrack: nextTrack$8,
+ rewind: rewind$8,
+ forward: forward$8,
+ captions: captions$8,
+ showCaptions: showCaptions$8,
+ hideCaptions: hideCaptions$8,
+ captionsOff: captionsOff$8,
+ showTranscript: showTranscript$8,
+ hideTranscript: hideTranscript$8,
+ turnOnDescriptions: turnOnDescriptions$8,
+ turnOffDescriptions: turnOffDescriptions$8,
+ chapters: chapters$8,
+ language: language$8,
+ sign: sign$8,
+ showSign: showSign$8,
+ hideSign: hideSign$8,
+ seekbarLabel: seekbarLabel$8,
+ mute: mute$8,
+ unmute: unmute$8,
+ volume: volume$8,
+ volumeUpDown: volumeUpDown$8,
+ preferences: preferences$8,
+ enterFullScreen: enterFullScreen$8,
+ exitFullScreen: exitFullScreen$8,
+ speed: speed$8,
+ spacebar: spacebar$8,
+ transcriptTitle: transcriptTitle$8,
+ lyricsTitle: lyricsTitle$8,
+ autoScroll: autoScroll$8,
+ statusPlaying: statusPlaying$8,
+ statusPaused: statusPaused$8,
+ statusStopped: statusStopped$8,
+ statusBuffering: statusBuffering$8,
+ statusEnd: statusEnd$8,
+ selectedTrack: selectedTrack$8,
+ alertDescribedVersion: alertDescribedVersion$8,
+ alertNonDescribedVersion: alertNonDescribedVersion$8,
+ prefMenuCaptions: prefMenuCaptions$8,
+ prefVoicedCaptions: prefVoicedCaptions$8,
+ prefMenuDescriptions: prefMenuDescriptions$8,
+ prefMenuKeyboard: prefMenuKeyboard$8,
+ prefMenuTranscript: prefMenuTranscript$8,
+ prefTitleCaptions: prefTitleCaptions$8,
+ prefTitleDescriptions: prefTitleDescriptions$8,
+ prefTitleKeyboard: prefTitleKeyboard$8,
+ prefTitleTranscript: prefTitleTranscript$8,
+ prefIntroDescription1: prefIntroDescription1$8,
+ prefDescription1: prefDescription1$8,
+ prefDescription2: prefDescription2$8,
+ prefDescription3: prefDescription3$8,
+ prefIntroDescriptionNone: prefIntroDescriptionNone$8,
+ prefIntroDescription3: prefIntroDescription3$8,
+ prefIntroDescription4: prefIntroDescription4$8,
+ prefIntroKeyboard1: prefIntroKeyboard1$8,
+ prefIntroKeyboard2: prefIntroKeyboard2$8,
+ prefIntroKeyboard3: prefIntroKeyboard3$8,
+ prefHeadingKeyboard1: prefHeadingKeyboard1$8,
+ prefHeadingKeyboard2: prefHeadingKeyboard2$8,
+ prefHeadingDescription: prefHeadingDescription$8,
+ prefHeadingTextDescription: prefHeadingTextDescription$8,
+ prefAltKey: prefAltKey$8,
+ prefCtrlKey: prefCtrlKey$8,
+ prefShiftKey: prefShiftKey$8,
+ prefNoKeyShortcuts: prefNoKeyShortcuts$8,
+ escapeKey: escapeKey$8,
+ escapeKeyFunction: escapeKeyFunction$8,
+ prefDescPause: prefDescPause$8,
+ prefDescVisible: prefDescVisible$8,
+ prefDescVoice: prefDescVoice$8,
+ prefDescRate: prefDescRate$8,
+ prefCaptionRate: prefCaptionRate$8,
+ prefDescPitch: prefDescPitch$8,
+ prefDescPitch1: prefDescPitch1$8,
+ prefDescPitch2: prefDescPitch2$8,
+ prefDescPitch3: prefDescPitch3$8,
+ prefDescPitch4: prefDescPitch4$8,
+ prefDescPitch5: prefDescPitch5$8,
+ sampleDescriptionText: sampleDescriptionText$8,
+ prefHighlight: prefHighlight$8,
+ prefTabbable: prefTabbable$8,
+ prefCaptionsFont: prefCaptionsFont$8,
+ prefCaptionsColor: prefCaptionsColor$8,
+ prefCaptionsBGColor: prefCaptionsBGColor$8,
+ prefCaptionsSize: prefCaptionsSize$8,
+ prefCaptionsOpacity: prefCaptionsOpacity$8,
+ prefCaptionsStyle: prefCaptionsStyle$8,
+ serif: serif$8,
+ sans: sans$8,
+ cursive: cursive$8,
+ fantasy: fantasy$8,
+ monospace: monospace$8,
+ white: white$8,
+ yellow: yellow$8,
+ green: green$8,
+ cyan: cyan$8,
+ blue: blue$8,
+ magenta: magenta$8,
+ red: red$8,
+ black: black$8,
+ transparent: transparent$8,
+ solid: solid$8,
+ captionsStylePopOn: captionsStylePopOn$8,
+ captionsStyleRollUp: captionsStyleRollUp$8,
+ prefCaptionsPosition: prefCaptionsPosition$8,
+ captionsPositionOverlay: captionsPositionOverlay$8,
+ captionsPositionBelow: captionsPositionBelow$8,
+ sampleCaptionText: sampleCaptionText$8,
+ prefSuccess: prefSuccess$8,
+ prefNoChange: prefNoChange$8,
+ save: save$8,
+ cancel: cancel$8,
+ dismissButton: dismissButton$8,
+ windowButtonLabel: windowButtonLabel$8,
+ windowMove: windowMove$8,
+ windowMoveLeft: windowMoveLeft$8,
+ windowMoveRight: windowMoveRight$8,
+ windowMoveUp: windowMoveUp$8,
+ windowMoveDown: windowMoveDown$8,
+ windowMoveStopped: windowMoveStopped$8,
+ transcriptControls: transcriptControls$8,
+ signControls: signControls$8,
+ windowMoveAlert: windowMoveAlert$8,
+ windowResize: windowResize$8,
+ windowResizeHeading: windowResizeHeading$8,
+ closeButtonLabel: closeButtonLabel$8,
+ width: width$8,
+ height: height$8,
+ resultsSummary1: resultsSummary1$8,
+ resultsSummary2: resultsSummary2$8,
+ resultsSummary3: resultsSummary3$8,
+ noResultsFound: noResultsFound$8,
+ searchButtonLabel: searchButtonLabel$8,
+ hour: hour$8,
+ minute: minute$8,
+ second: second$8,
+ hours: hours$8,
+ minutes: minutes$8,
+ seconds: seconds$8,
+ vtsHeading: vtsHeading$8,
+ vtsInstructions1: vtsInstructions1$8,
+ vtsInstructions2: vtsInstructions2$8,
+ vtsInstructions3: vtsInstructions3$8,
+ vtsInstructions4: vtsInstructions4$8,
+ vtsInstructions5: vtsInstructions5$8,
+ vtsSelectLanguage: vtsSelectLanguage$8,
+ vtsSave: vtsSave$8,
+ vtsReturn: vtsReturn$8,
+ vtsCancel: vtsCancel$8,
+ vtsRow: vtsRow$8,
+ vtsKind: vtsKind$8,
+ vtsStart: vtsStart$8,
+ vtsEnd: vtsEnd$8,
+ vtsContent: vtsContent$8,
+ vtsActions: vtsActions$8,
+ vtsNewRow: vtsNewRow$8,
+ vtsDeletedRow: vtsDeletedRow$8,
+ vtsMovedRow: vtsMovedRow$8
};
-})(jQuery);
-
-(function ($) {
- AblePlayer.prototype.onMediaUpdateTime = function (duration, elapsed) {
-
- var thisObj = this;
- this.getMediaTimes(duration,elapsed).then(function(mediaTimes) {
- thisObj.duration = mediaTimes['duration'];
- thisObj.elapsed = mediaTimes['elapsed'];
- if (thisObj.duration > 0) {
- if (thisObj.prefHighlight === 1) {
- thisObj.highlightTranscript(thisObj.elapsed);
- }
- thisObj.updateCaption(thisObj.elapsed);
- thisObj.showDescription(thisObj.elapsed);
- thisObj.updateChapter(thisObj.elapsed);
- thisObj.updateMeta(thisObj.elapsed);
- thisObj.refreshControls('timeline', thisObj.duration, thisObj.elapsed);
- }
- });
- };
-
- AblePlayer.prototype.onMediaPause = function () {
-
- if (this.controlsHidden) {
- this.fadeControls('in');
- this.controlsHidden = false;
- }
- if (this.hideControlsTimeoutStatus === 'active') {
- window.clearTimeout(this.hideControlsTimeout);
- this.hideControlsTimeoutStatus = 'clear';
-
- }
- this.refreshControls('playpause');
- };
-
- AblePlayer.prototype.onMediaComplete = function () {
- if (this.hasPlaylist && !this.cueingPlaylistItem) {
- if (this.playlistIndex === (this.$playlist.length - 1)) {
- if (this.loop) {
- this.playlistIndex = 0;
- this.cueingPlaylistItem = true;
- this.cuePlaylistItem(0);
- } else {
- this.playing = false;
- this.paused = true;
- }
- } else {
- this.playlistIndex++;
- this.cueingPlaylistItem = true;
- this.cuePlaylistItem(this.playlistIndex)
- }
- }
- this.refreshControls();
- };
-
- AblePlayer.prototype.onMediaNewSourceLoad = function () {
-
- var loadIsComplete = false;
-
- if (this.cueingPlaylistItem) {
- this.cueingPlaylistItem = false;
- }
- if (this.recreatingPlayer) {
- this.recreatingPlayer = false;
- }
- if (this.playbackRate) {
- this.setPlaybackRate(this.playbackRate);
- }
- if (this.userClickedPlaylist) {
- if (!this.startedPlaying || this.okToPlay) {
- this.playMedia();
- loadIsComplete = true;
- }
- } else if (this.seekTrigger == 'restart' ||
- this.seekTrigger == 'chapter' ||
- this.seekTrigger == 'transcript' ||
- this.seekTrigger == 'search'
- ) {
- this.playMedia();
- loadIsComplete = true;
- } else if (this.swappingSrc) {
- if (this.hasPlaylist) {
- if ((this.playlistIndex !== this.$playlist.length) || this.loop) {
- this.playMedia();
- loadIsComplete = true;
- }
- } else if (this.swapTime > 0) {
- if (this.seekStatus === 'complete') {
- if (this.okToPlay) {
- this.playMedia();
- }
- loadIsComplete = true;
- } else if (this.seekStatus === 'seeking') {
- } else {
- if (this.swapTime === this.elapsed) {
- this.seekStatus = 'complete';
- if (this.okToPlay) {
- this.playMedia();
- }
- loadIsComplete = true;
- } else {
- if (this.hasDescTracks) {
- loadIsComplete = true;
- } else if (this.durationsAreCloseEnough(this.duration,this.prevDuration)) {
- this.seekStatus = 'seeking';
- this.seekTo(this.swapTime);
- } else {
- loadIsComplete = true;
- }
- }
- }
- } else {
- if (this.playing) {
- this.playMedia();
- loadIsComplete = true;
- }
- }
- } else if (!this.startedPlaying) {
- if (this.startTime > 0) {
- if (this.seeking) {
- this.seeking = false;
- if (this.okToPlay) {
- this.playMedia();
- }
- loadIsComplete = true;
- } else {
- this.seekTo(this.startTime);
- }
- } else if (this.defaultChapter && typeof this.selectedChapters !== 'undefined') {
- this.seekToChapter(this.defaultChapter);
- } else {
- if (this.okToPlay) {
- this.playMedia();
- }
- loadIsComplete = true;
- }
- } else if (this.hasPlaylist) {
- if ((this.playlistIndex !== this.$playlist.length) || this.loop) {
- this.playMedia();
- loadIsComplete = true;
- }
- } else {
- loadIsComplete = true;
- }
- if (loadIsComplete) {
- this.swappingSrc = false;
- this.seekStatus = null;
- this.swapTime = 0;
- this.seekTrigger = null;
- this.seekingFromTranscript = false;
- this.userClickedPlaylist = false;
- this.okToPlay = false;
- }
- this.refreshControls();
- if (this.$focusedElement) {
- this.restoreFocus();
- this.$focusedElement = null;
- this.activeMedia = null;
- }
- };
-
- AblePlayer.prototype.durationsAreCloseEnough = function(d1,d2) {
-
-
- var tolerance, diff;
-
- tolerance = 1;
- diff = Math.abs(Math.round(d1) - Math.round(d2));
-
- return (diff <= tolerance) ? true : false;
- };
-
- AblePlayer.prototype.restoreFocus = function() {
-
-
- var classList, $mediaParent;
-
- if ( this.$focusedElement && null !== this.activeMedia ) {
- $mediaParent = $( '#' + this.activeMedia ).closest( '.able' );
- if ( (this.$focusedElement).attr('role') === 'button' ) {
- classList = this.$focusedElement.attr("class").split(/\s+/);
- $.each(classList, function(index, item) {
- if (item.substring(0,20) === 'able-button-handler-') {
- $mediaParent.find('div.able-controller div.' + item).trigger('focus');
- }
- });
- }
- }
-
- };
-
- AblePlayer.prototype.addSeekbarListeners = function () {
-
- var thisObj = this;
-
- this.seekBar.bodyDiv.on('startTracking', function (e) {
- thisObj.pausedBeforeTracking = thisObj.paused;
- thisObj.pauseMedia();
- }).on('tracking', function (e, position) {
- thisObj.highlightTranscript(position);
- thisObj.updateCaption(position);
- thisObj.showDescription(position);
- thisObj.updateChapter(thisObj.convertChapterTimeToVideoTime(position));
- thisObj.updateMeta(position);
- thisObj.refreshControls();
- }).on('stopTracking', function (e, position) {
- if (thisObj.useChapterTimes) {
- thisObj.seekTo(thisObj.convertChapterTimeToVideoTime(position));
- } else {
- thisObj.seekTo(position);
- }
- if (!thisObj.pausedBeforeTracking) {
- setTimeout(function () {
- thisObj.playMedia();
- }, 200);
- }
- });
- };
-
- AblePlayer.prototype.onClickPlayerButton = function (el) {
- var whichButton, prefsPopup;
- whichButton = this.getButtonNameFromClass($(el).attr('class'));
- switch ( whichButton ) {
- case 'play':
- this.clickedPlay = true;
- this.handlePlay();
- break;
- case 'restart':
- this.seekTrigger = 'restart';
- this.handleRestart();
- break;
- case 'previous':
- this.userClickedPlaylist = true;
- this.okToPlay = true;
- this.seekTrigger = 'previous';
- this.buttonWithFocus = 'previous';
- this.handlePrevTrack();
- break;
- case 'next':
- this.userClickedPlaylist = true;
- this.okToPlay = true;
- this.seekTrigger = 'next';
- this.buttonWithFocus = 'next';
- this.handleNextTrack();
- break;
- case 'rewind':
- this.seekTrigger = 'rewind';
- this.handleRewind();
- break;
- case 'forward':
- this.seekTrigger = 'forward';
- this.handleFastForward();
- break;
- case 'mute':
- this.handleMute();
- break;
- case 'volume':
- this.handleVolumeButtonClick();
- break;
- case 'faster':
- this.handleRateIncrease();
- break;
- case 'slower':
- this.handleRateDecrease();
- break;
- case 'captions':
- this.handleCaptionToggle();
- break;
- case 'chapters':
- this.handleChapters();
- break;
- case 'descriptions':
- this.handleDescriptionToggle();
- break;
- case 'sign':
- if ( ! this.closingSign ) {
- this.handleSignToggle();
- }
- break;
- case 'preferences':
- if ($(el).attr('data-prefs-popup') === 'menu') {
- this.handlePrefsClick();
- } else {
- this.showingPrefsDialog = true;
- this.closePopups();
- prefsPopup = $(el).attr('data-prefs-popup');
- if (prefsPopup === 'keyboard') {
- this.keyboardPrefsDialog.show();
- } else if (prefsPopup === 'captions') {
- this.captionPrefsDialog.show();
- } else if (prefsPopup === 'descriptions') {
- this.descPrefsDialog.show();
- } else if (prefsPopup === 'transcript') {
- this.transcriptPrefsDialog.show();
- }
- this.showingPrefsDialog = false;
- }
- break;
- case 'transcript':
- if ( !this.closingTranscript ) {
- this.handleTranscriptToggle();
- }
- break;
- case 'fullscreen':
- this.clickedFullscreenButton = true;
- this.handleFullscreenToggle();
- break;
- }
- };
-
- AblePlayer.prototype.getButtonNameFromClass = function (classString) {
- var classes, i;
-
- classes = classString.split(' ');
- for (i = 0; i < classes.length; i++) {
- if (classes[i].substring(0,20) === 'able-button-handler-') {
- return classes[i].substring(20);
- }
- }
- return classString;
- }
-
- AblePlayer.prototype.okToHandleKeyPress = function () {
- let defaultReturn = true;
- if ( this.prefNoKeyShortcuts === 1 ) {
- defaultReturn = false;
- }
- var activeElement = AblePlayer.getActiveDOMElement();
-
- return ($(activeElement).prop('tagName') === 'INPUT') ? false : defaultReturn;
- };
-
- AblePlayer.prototype.onPlayerKeyPress = function (e) {
-
-
- var key, $thisElement;
-
- key = e.key;
- $thisElement = $(document.activeElement);
-
- if (key === 'Escape') {
- if (this.$transcriptArea && $.contains(this.$transcriptArea[0],$thisElement[0]) && !this.hidingPopup) {
- this.handleTranscriptToggle();
- return false;
- }
- }
- if (!this.okToHandleKeyPress()) {
- return false;
- }
-
- if (!(
- $(':focus').is('[contenteditable]') ||
- $(':focus').is('input') ||
- ($(':focus').is('textarea') && !this.stenoMode) ||
- $(':focus').is('select') ||
- e.target.hasAttribute('contenteditable') ||
- e.target.tagName === 'INPUT' ||
- (e.target.tagName === 'TEXTAREA' && !this.stenoMode) ||
- e.target.tagName === 'SELECT'
- )){
- if (key === 'Escape') {
- this.closePopups();
- this.$tooltipDiv.hide();
- this.seekBar.hideSliderTooltips();
- } else if (key === ' ') {
- if ($thisElement.attr('role') === 'button') {
- e.preventDefault();
- $thisElement.trigger( 'click' );
- }
- } else if ( key === 'p' ) {
- if (this.usingModifierKeys(e)) {
- e.preventDefault();
- this.handlePlay();
- }
- } else if (key === 's') {
- if (this.usingModifierKeys(e)) {
- e.preventDefault();
- this.handleRestart();
- }
- } else if (key === 'm') {
- if (this.usingModifierKeys(e)) {
- e.preventDefault();
- this.handleMute();
- }
- } else if (key === 'v') {
- if (this.usingModifierKeys(e)) {
- e.preventDefault();
- this.handleVolumeButtonClick();
- }
- } else if (key >= 0 && key <= 9) {
- if (this.usingModifierKeys(e)) {
- e.preventDefault();
- this.handleVolumeKeystroke(key);
- }
- } else if (key === 'c') {
- if (this.usingModifierKeys(e)) {
- e.preventDefault();
- this.handleCaptionToggle();
- }
- } else if (key === 'd') {
- if (this.usingModifierKeys(e)) {
- e.preventDefault();
- this.handleDescriptionToggle();
- }
- } else if (key === 'f') {
- if (this.usingModifierKeys(e)) {
- e.preventDefault();
- this.handleFastForward();
- }
- } else if (key === 'r') {
- if (this.usingModifierKeys(e)) {
- e.preventDefault();
- this.handleRewind();
- }
- } else if (key === 'b') {
- if (this.usingModifierKeys(e)) {
- e.preventDefault();
- this.handlePrevTrack();
- }
- } else if (key === 'n') {
- if (this.usingModifierKeys(e)) {
- e.preventDefault();
- this.handleNextTrack();
- }
- } else if (key === 'e') {
- if (this.usingModifierKeys(e)) {
- e.preventDefault();
- this.handlePrefsClick();
- }
- } else if (key === 'Enter') {
- if ($thisElement.attr('role') === 'button' || $thisElement.prop('tagName') === 'SPAN') {
- $thisElement.trigger( 'click' );
- } else if ($thisElement.prop('tagName') === 'LI') {
- $thisElement.trigger( 'click' );
- }
- }
- }
- };
-
- AblePlayer.prototype.addHtml5MediaListeners = function () {
-
- var thisObj = this;
-
-
- this.$media
- .on('emptied',function() {
- })
- .on('loadedmetadata',function() {
- thisObj.duration = thisObj.media.duration;
- })
- .on('canplay',function() {
- })
- .on('canplaythrough',function() {
- thisObj.onMediaNewSourceLoad();
- })
- .on('play',function() {
- })
- .on('playing',function() {
- thisObj.playing = true;
- thisObj.paused = false;
- thisObj.swappingSrc = false;
- thisObj.refreshControls('playpause');
- })
- .on('ended',function() {
- thisObj.playing = false;
- thisObj.paused = true;
- thisObj.onMediaComplete();
- })
- .on('progress', function() {
- thisObj.refreshControls('timeline');
- })
- .on('waiting',function() {
- })
- .on('durationchange',function() {
- thisObj.refreshControls('timeline');
- })
- .on('timeupdate',function() {
- thisObj.onMediaUpdateTime();
- })
- .on('pause',function() {
- if (!thisObj.clickedPlay) {
- if (thisObj.hasPlaylist || thisObj.swappingSrc) {
- } else {
- thisObj.playing = false;
- thisObj.paused = true;
- }
- } else {
- thisObj.playing = false;
- thisObj.paused = true;
- }
- thisObj.clickedPlay = false;
- thisObj.onMediaPause();
- })
- .on('ratechange',function() {
- })
- .on('volumechange',function() {
- thisObj.volume = thisObj.getVolume();
- })
- .on('error',function() {
- if (thisObj.debug) {
- switch (thisObj.media.error.code) {
- case 1:
-
- break;
- case 2:
-
- break;
- case 3:
-
- break;
- case 4:
-
- break;
- }
- }
- });
- };
-
- AblePlayer.prototype.addVimeoListeners = function () {
-
- var thisObj = this;
-
- this.vimeoPlayer.on('loaded', function(vimeoId) {
- thisObj.onMediaNewSourceLoad();
- });
- this.vimeoPlayer.on('play', function(data) {
- thisObj.playing = true;
- thisObj.startedPlaying = true;
- thisObj.paused = false;
- thisObj.refreshControls('playpause');
- });
- this.vimeoPlayer.on('ended', function(data) {
- thisObj.playing = false;
- thisObj.paused = true;
- thisObj.onMediaComplete();
- });
- this.vimeoPlayer.on('bufferstart', function() {
- });
- this.vimeoPlayer.on('bufferend', function() {
- });
- this.vimeoPlayer.on('progress', function(data) {
- });
- this.vimeoPlayer.on('seeking', function(data) {
- });
- this.vimeoPlayer.on('seeked', function(data) {
- });
- this.vimeoPlayer.on('timeupdate',function(data) {
- thisObj.onMediaUpdateTime(data['duration'], data['seconds']);
- });
- this.vimeoPlayer.on('pause',function(data) {
- if (!thisObj.clickedPlay) {
- if (thisObj.hasPlaylist || thisObj.swappingSrc) {
- } else {
- thisObj.playing = false;
- thisObj.paused = true;
- }
- } else {
- thisObj.playing = false;
- thisObj.paused = true;
- }
- thisObj.clickedPlay = false;
- thisObj.onMediaPause();
- thisObj.refreshControls('playpause');
- });
- this.vimeoPlayer.on('playbackratechange',function(data) {
- thisObj.vimeoPlaybackRate = data['playbackRate'];
- });
- this.vimeoPlayer.on('texttrackchange', function(data) {
- });
- this.vimeoPlayer.on('volumechange',function(data) {
- thisObj.volume = data['volume'] * 10;
- });
- this.vimeoPlayer.on('error',function(data) {
- });
- };
-
- AblePlayer.prototype.addEventListeners = function () {
-
- var thisObj = this;
-
- $(window).on('resize',function () {
- thisObj.resizePlayer();
- });
-
- if (window.MutationObserver) {
- var target = this.$ableDiv[0];
- var observer = new MutationObserver(function(mutations) {
- mutations.forEach(function(mutation) {
- if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
- if (thisObj.$ableDiv.is(':visible')) {
- thisObj.refreshControls();
- }
- }
- });
- });
- var config = { attributes: true, childList: true, characterData: true };
- observer.observe(target, config);
- }
- if (typeof this.seekBar !== 'undefined') {
- this.addSeekbarListeners();
- } else {
- setTimeout(function() {
- if (typeof thisObj.seekBar !== 'undefined') {
- thisObj.addSeekbarListeners();
- }
- },2000);
- }
-
- this.$controllerDiv.find('div[role="button"]').on('click',function(e){
- e.stopPropagation();
- thisObj.onClickPlayerButton(this);
- });
-
- $('body').on('click', function(e) {
-
- if (e.button !== 0) {
- return false;
- }
- if ($('.able-popup:visible').length || $('.able-volume-slider:visible').length ) {
- thisObj.closePopups();
- }
- if (e.target.tagName === 'VIDEO') {
- thisObj.clickedPlay = true;
- }
- });
-
- this.$ableDiv.on('mousemove',function() {
- if (thisObj.controlsHidden) {
- thisObj.fadeControls('in');
- thisObj.controlsHidden = false;
- if (thisObj.hideControlsTimeoutStatus === 'active') {
- window.clearTimeout(thisObj.hideControlsTimeout);
- thisObj.hideControlsTimeoutStatus = 'clear';
- }
- if (thisObj.hideControls) {
- thisObj.invokeHideControlsTimeout();
- }
- } else {
- if (thisObj.hideControlsTimeoutStatus === 'active') {
- window.clearTimeout(thisObj.hideControlsTimeout);
- thisObj.hideControlsTimeoutStatus = 'clear';
- if (thisObj.hideControls) {
- thisObj.invokeHideControlsTimeout();
- }
- }
- }
- });
-
- $(document).on( 'keydown', function(e) {
- if (thisObj.controlsHidden) {
- thisObj.fadeControls('in');
- thisObj.controlsHidden = false;
- if (thisObj.hideControlsTimeoutStatus === 'active') {
- window.clearTimeout(thisObj.hideControlsTimeout);
- thisObj.hideControlsTimeoutStatus = 'clear';
- }
- if (thisObj.hideControls) {
- thisObj.invokeHideControlsTimeout();
- }
- } else {
- if (thisObj.hideControlsTimeoutStatus === 'active') {
- window.clearTimeout(thisObj.hideControlsTimeout);
- thisObj.hideControlsTimeoutStatus = 'clear';
-
- if (thisObj.hideControls) {
- thisObj.invokeHideControlsTimeout();
- }
- }
- }
- });
-
- this.$ableDiv.on( 'keydown', function (e) {
- if (AblePlayer.nextIndex > 1) {
- thisObj.onPlayerKeyPress(e);
- }
- });
-
- if (this.stenoMode && (typeof this.stenoFrameContents !== 'undefined')) {
- this.stenoFrameContents.on('keydown',function(e) {
- thisObj.onPlayerKeyPress(e);
- });
- };
-
- if (this.$transcriptArea) {
- this.$transcriptArea.on('keydown',function (e) {
- if (AblePlayer.nextIndex > 1) {
- thisObj.onPlayerKeyPress(e);
- }
- });
- }
-
- if (this.$playlist) {
- this.$playlist.on( 'click', function(e) {
- if (!thisObj.userClickedPlaylist) {
- thisObj.userClickedPlaylist = true;
- thisObj.playlistIndex = $(this).index();
- thisObj.cuePlaylistItem(thisObj.playlistIndex);
- }
- });
- }
-
- this.$media.on( 'click', function () {
- thisObj.handlePlay();
- });
-
- if (this.player === 'html5') {
- this.addHtml5MediaListeners();
- } else if (this.player === 'vimeo') {
- this.addVimeoListeners();
- } else if (this.player === 'youtube') {
- setInterval(function () {
- thisObj.onMediaUpdateTime();
- }, 300);
- }
- };
-})(jQuery);
-
-(function ($) {
- AblePlayer.prototype.initDragDrop = function ( which ) {
-
-
-
-
- var thisObj, $window, $toolbar, windowName, $resizeHandle, $resizeSvg,
- i, x1, y1, x2, y2, $resizeLine, resizeZIndex;
-
- thisObj = this;
-
- if (which === 'transcript') {
- $window = this.$transcriptArea;
- windowName = 'transcript-window';
- $toolbar = this.$transcriptToolbar;
- $toolbar.attr( 'aria-label', this.translate( 'transcriptControls', 'Transcript Window Controls' ) );
- } else if (which === 'sign') {
- $window = this.$signWindow;
- windowName = 'sign-window';
- $toolbar = this.$signToolbar;
- $toolbar.attr( 'aria-label', this.translate( 'signControls', 'Sign Language Window Controls' ) );
- }
-
- $toolbar.addClass('able-draggable');
- $toolbar.attr( 'role', 'application' );
-
- $dragHandle = $('
',{
- 'class': 'able-drag-handle'
- });
-
- $dragHandle.html('
');
- $resizeHandle = $('
',{
- 'class': 'able-resizable'
- });
-
- $resizeSvg = $('').attr({
- 'width': '100%',
- 'height': '100%',
- 'viewBox': '0 0 100 100',
- 'preserveAspectRatio': 'none'
- });
- for (i=1; i<=3; i++) {
- if (i === 1) {
- x1 = '100';
- y1 = '0';
- x2 = '0';
- y2 = '100';
- } else if (i === 2) {
- x1 = '33';
- y1 = '100';
- x2 = '100';
- y2 = '33';
- } else if (i === 3) {
- x1 = '67';
- y1 = '100';
- x2 = '100';
- y2 = '67';
- }
- $resizeLine = $('