PageSourceSearch

https://www.rosario3.com/__export/1540303315000/system/modules/com…/resources/scripts/libs/videojs.ima.js

js rosario3.com collected 2026-10-02 03:36:25 UTC 80,224 bytes, 2,678 lines download raw bytes

1(function (global, factory) {
2	typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('video.js')) :
3	typeof define === 'function' && define.amd ? define(['video.js'], factory) :
4	(factory(global.videojs));
5}(this, (function (videojs) { 'use strict';
6
7videojs = videojs && videojs.hasOwnProperty('default') ? videojs['default'] : videojs;
8
9/**
10 * Copyright 2017 Google Inc.
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 *     http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *
24 * IMA SDK integration plugin for Video.js. For more information see
25 * https://www.github.com/googleads/videojs-ima
26 */
27
28/**
29 * Wraps the video.js player for the plugin.
30 *
31 * @param {Object} player Video.js player instance.
32 * @param {Object} adsPluginSettings Settings for the contrib-ads plugin.
33 * @param {Controller} controller Reference to the parent controller.
34 */
35var PlayerWrapper = function PlayerWrapper(player, adsPluginSettings, controller) {
36  /**
37   * Instance of the video.js player.
38   */
39  this.vjsPlayer = player;
40
41  /**
42   * Plugin controller.
43   */
44  this.controller = controller;
45
46  /**
47   * Timer used to track content progress.
48   */
49  this.contentTrackingTimer = null;
50
51  /**
52   * True if our content video has completed, false otherwise.
53   */
54  this.contentComplete = false;
55
56  /**
57   * Handle to interval that repeatedly updates current time.
58   */
59  this.updateTimeIntervalHandle = null;
60
61  /**
62   * Interval (ms) to check for player resize for fluid support.
63   */
64  this.updateTimeInterval = 1000;
65
66  /**
67   * Handle to interval that repeatedly checks for seeking.
68   */
69  this.seekCheckIntervalHandle = null;
70
71  /**
72   * Interval (ms) on which to check if the user is seeking through the
73   * content.
74   */
75  this.seekCheckInterval = 1000;
76
77  /**
78   * Handle to interval that repeatedly checks for player resize.
79   */
80  this.resizeCheckIntervalHandle = null;
81
82  /**
83   * Interval (ms) to check for player resize for fluid support.
84   */
85  this.resizeCheckInterval = 250;
86
87  /**
88   * Threshold by which to judge user seeking. We check every 1000 ms to see
89   * if the user is seeking. In order for us to decide that they are *not*
90   * seeking, the content video playhead must only change by 900-1100 ms
91   * between checks. Any greater change and we assume the user is seeking
92   * through the video.
93   */
94  this.seekThreshold = 100;
95
96  /**
97   * Content ended listeners passed by the publisher to the plugin. Publishers
98   * should allow the plugin to handle content ended to ensure proper support
99   * of custom ad playback.
100   */
101  this.contentEndedListeners = [];
102
103  /**
104   * Stores the content source so we can re-populate it manually after a
105   * post-roll on iOS.
106   */
107  this.contentSource = '';
108
109  /**
110   * Stores data for the content playhead tracker.
111   */
112  this.contentPlayheadTracker = {
113    currentTime: 0,
114    previousTime: 0,
115    seeking: false,
116    duration: 0
117  };
118
119  /**
120   * Player dimensions. Used in our resize check.
121   */
122  this.vjsPlayerDimensions = {
123    width: this.getPlayerWidth(),
124    height: this.getPlayerHeight()
125  };
126
127  /**
128   * Video.js control bar.
129   */
130  this.vjsControls = this.vjsPlayer.getChild('controlBar');
131
132  /**
133   * Vanilla HTML5 video player underneath the video.js player.
134   */
135  this.h5Player = null;
136
137  this.vjsPlayer.one('play', this.setUpPlayerIntervals.bind(this));
138  this.boundContentEndedListener = this.localContentEndedListener.bind(this);
139  this.vjsPlayer.on('contentended', this.boundContentEndedListener);
140  this.vjsPlayer.on('dispose', this.playerDisposedListener.bind(this));
141  this.vjsPlayer.on('readyforpreroll', this.onReadyForPreroll.bind(this));
142  this.vjsPlayer.ready(this.onPlayerReady.bind(this));
143
144  this.vjsPlayer.ads(adsPluginSettings);
145};
146
147/**
148 * Set up the intervals we use on the player.
149 */
150PlayerWrapper.prototype.setUpPlayerIntervals = function () {
151  this.updateTimeIntervalHandle = setInterval(this.updateCurrentTime.bind(this), this.updateTimeInterval);
152  this.seekCheckIntervalHandle = setInterval(this.checkForSeeking.bind(this), this.seekCheckInterval);
153  this.resizeCheckIntervalHandle = setInterval(this.checkForResize.bind(this), this.resizeCheckInterval);
154};
155
156/**
157 * Updates the current time of the video
158 */
159PlayerWrapper.prototype.updateCurrentTime = function () {
160  if (!this.contentPlayheadTracker.seeking) {
161    this.contentPlayheadTracker.currentTime = this.vjsPlayer.currentTime();
162  }
163};
164
165/**
166 * Detects when the user is seeking through a video.
167 * This is used to prevent mid-rolls from playing while a user is seeking.
168 *
169 * There *is* a seeking property of the HTML5 video element, but it's not
170 * properly implemented on all platforms (e.g. mobile safari), so we have to
171 * check ourselves to be sure.
172 */
173PlayerWrapper.prototype.checkForSeeking = function () {
174  var tempCurrentTime = this.vjsPlayer.currentTime();
175  var diff = (tempCurrentTime - this.contentPlayheadTracker.previousTime) * 1000;
176  if (Math.abs(diff) > this.seekCheckInterval + this.seekThreshold) {
177    this.contentPlayheadTracker.seeking = true;
178  } else {
179    this.contentPlayheadTracker.seeking = false;
vendor: 4,937 bytes, lines 180-362
180  }
181  this.contentPlayheadTracker.previousTime = this.vjsPlayer.currentTime();
182};
183
184/**
185 * Detects when the player is resized (for fluid support) and resizes the
186 * ads manager to match.
187 */
188PlayerWrapper.prototype.checkForResize = function () {
189  var currentWidth = this.getPlayerWidth();
190  var currentHeight = this.getPlayerHeight();
191
192  if (currentWidth != this.vjsPlayerDimensions.width || currentHeight != this.vjsPlayerDimensions.height) {
193    this.vjsPlayerDimensions.width = currentWidth;
194    this.vjsPlayerDimensions.height = currentHeight;
195    this.controller.onPlayerResize(currentWidth, currentHeight);
196  }
197};
198
199/**
200 * Local content ended listener for contentComplete.
201 */
202PlayerWrapper.prototype.localContentEndedListener = function () {
203  if (!this.contentComplete) {
204    this.contentComplete = true;
205    this.controller.onContentComplete();
206  }
207
208  for (var index in this.contentEndedListeners) {
209    if (typeof this.contentEndedListeners[index] === 'function') {
210      this.contentEndedListeners[index]();
211    }
212  }
213
214  clearInterval(this.updateTimeIntervalHandle);
215  clearInterval(this.seekCheckIntervalHandle);
216  clearInterval(this.resizeCheckIntervalHandle);
217  if (this.vjsPlayer.el()) {
218    this.vjsPlayer.one('play', this.setUpPlayerIntervals.bind(this));
219  }
220};
221
222/**
223 * Called when it's time to play a post-roll but we don't have one to play.
224 */
225PlayerWrapper.prototype.onNoPostroll = function () {
226  this.vjsPlayer.trigger('nopostroll');
227};
228
229/**
230 * Detects when the video.js player has been disposed.
231 */
232PlayerWrapper.prototype.playerDisposedListener = function () {
233  this.contentEndedListeners = [];
234  this.controller.onPlayerDisposed();
235
236  this.contentComplete = true;
237  this.vjsPlayer.off('contentended', this.boundContentEndedListener);
238
239  // Bug fix: https://github.com/googleads/videojs-ima/issues/306
240  if (this.vjsPlayer.ads.adTimeoutTimeout) {
241    clearTimeout(this.vjsPlayer.ads.adTimeoutTimeout);
242  }
243
244  var intervalsToClear = [this.updateTimeIntervalHandle, this.seekCheckIntervalHandle, this.resizeCheckIntervalHandle];
245  for (var index in intervalsToClear) {
246    if (intervalsToClear[index]) {
247      clearInterval(intervalsToClear[index]);
248    }
249  }
250};
251
252/**
253 * Start ad playback, or content video playback in the absence of a
254 * pre-roll.
255 */
256PlayerWrapper.prototype.onReadyForPreroll = function () {
257  this.controller.onPlayerReadyForPreroll();
258};
259
260/**
261 * Called when the player fires its 'ready' event.
262 */
263PlayerWrapper.prototype.onPlayerReady = function () {
264  this.h5Player = document.getElementById(this.getPlayerId()).getElementsByClassName('vjs-tech')[0];
265
266  // Detect inline options
267  if (this.h5Player.hasAttribute('autoplay')) {
268    this.controller.setSetting('adWillAutoPlay', true);
269  }
270
271  // Sync ad volume with player volume.
272  this.onVolumeChange();
273  this.vjsPlayer.on('fullscreenchange', this.onFullscreenChange.bind(this));
274  this.vjsPlayer.on('volumechange', this.onVolumeChange.bind(this));
275
276  this.controller.onPlayerReady();
277};
278
279/**
280 * Listens for the video.js player to change its fullscreen status. This
281 * keeps the fullscreen-ness of the AdContainer in sync with the player.
282 */
283PlayerWrapper.prototype.onFullscreenChange = function () {
284  if (this.vjsPlayer.isFullscreen()) {
285    this.controller.onPlayerEnterFullscreen();
286  } else {
287    this.controller.onPlayerExitFullscreen();
288  }
289};
290
291/**
292 * Listens for the video.js player to change its volume. This keeps the ad
293 * volume in sync with the content volume if the volume of the player is
294 * changed while content is playing.
295 */
296PlayerWrapper.prototype.onVolumeChange = function () {
297  var newVolume = this.vjsPlayer.muted() ? 0 : this.vjsPlayer.volume();
298  this.controller.onPlayerVolumeChanged(newVolume);
299};
300
301/**
302 * Inject the ad container div into the DOM.
303 *
304 * @param{HTMLElement} adContainerDiv The ad container div.
305 */
306PlayerWrapper.prototype.injectAdContainerDiv = function (adContainerDiv) {
307  this.vjsControls.el().parentNode.appendChild(adContainerDiv);
308};
309
310/**
311 * @return {Object} The content player.
312 */
313PlayerWrapper.prototype.getContentPlayer = function () {
314  return this.h5Player;
315};
316
317/**
318 * @return {number} The volume, 0-1.
319 */
320PlayerWrapper.prototype.getVolume = function () {
321  return this.vjsPlayer.muted() ? 0 : this.vjsPlayer.volume();
322};
323
324/**
325 * Set the volume of the player. 0-1.
326 *
327 * @param {number} volume The new volume.
328 */
329PlayerWrapper.prototype.setVolume = function (volume) {
330  this.vjsPlayer.volume(volume);
331  if (volume == 0) {
332    this.vjsPlayer.muted(true);
333  } else {
334    this.vjsPlayer.muted(false);
335  }
336};
337
338/**
339 * Ummute the player.
340 */
341PlayerWrapper.prototype.unmute = function () {
342  this.vjsPlayer.muted(false);
343};
344
345/**
346 * Mute the player.
347 */
348PlayerWrapper.prototype.mute = function () {
349  this.vjsPlayer.muted(true);
350};
351
352/**
353 * Play the video.
354 */
355PlayerWrapper.prototype.play = function () {
356  this.vjsPlayer.play();
357};
358
359/**
360 * Get the player width.
361 *
362 * @return {number}
362 The player's width.
363 */
364PlayerWrapper.prototype.getPlayerWidth = function () {
365  var width = (getComputedStyle(this.vjsPlayer.el()) || {}).width;
366
367  if (!width || parseInt(width, 10) === 0) {
368    width = (this.vjsPlayer.el().getBoundingClientRect() || {}).width;
369  }
370
371  return parseInt(width, 10) || this.vjsPlayer.width();
372};
373
374/**
375 * Get the player height.
376 *
377 * @return {number} The player's height.
378 */
379PlayerWrapper.prototype.getPlayerHeight = function () {
380  var height = (getComputedStyle(this.vjsPlayer.el()) || {}).height;
381
382  if (!height || parseInt(height, 10) === 0) {
383    height = (this.vjsPlayer.el().getBoundingClientRect() || {}).height;
384  }
385
386  return parseInt(height, 10) || this.vjsPlayer.height();
387};
388
389/**
390 * @return {Object} The vjs player's options object.
391 */
392PlayerWrapper.prototype.getPlayerOptions = function () {
393  return this.vjsPlayer.options_;
394};
395
396/**
397 * Returns the instance of the player id.
398 * @return {string} The player id.
399 */
400PlayerWrapper.prototype.getPlayerId = function () {
401  return this.vjsPlayer.id();
402};
403
404/**
405 * Toggle fullscreen state.
406 */
407PlayerWrapper.prototype.toggleFullscreen = function () {
408  if (this.vjsPlayer.isFullscreen()) {
409    this.vjsPlayer.exitFullscreen();
410  } else {
411    this.vjsPlayer.requestFullscreen();
412  }
413};
414
415/**
416 * Returns the content playhead tracker.
417 *
418 * @return {Object} The content playhead tracker.
419 */
420PlayerWrapper.prototype.getContentPlayheadTracker = function () {
421  return this.contentPlayheadTracker;
422};
423
424/**
425 * Handles ad errors.
426 *
427 * @param {Object} adErrorEvent The ad error event thrown by the IMA SDK.
428 */
429PlayerWrapper.prototype.onAdError = function (adErrorEvent) {
430  this.vjsControls.show();
431  var errorMessage = adErrorEvent.getError !== undefined ? adErrorEvent.getError() : adErrorEvent.stack;
432  this.vjsPlayer.trigger({ type: 'adserror', data: {
433      AdError: errorMessage,
434      AdErrorEvent: adErrorEvent
435    } });
436};
437
438/**
439 * Handles ad break starting.
440 */
441PlayerWrapper.prototype.onAdBreakStart = function () {
442  this.contentSource = this.vjsPlayer.currentSrc();
443  this.vjsPlayer.off('contentended', this.boundContentEndedListener);
444  this.vjsPlayer.ads.startLinearAdMode();
445  this.vjsControls.hide();
446  this.vjsPlayer.pause();
447};
448
449/**
450 * Handles ad break ending.
451 */
452PlayerWrapper.prototype.onAdBreakEnd = function () {
453  this.vjsPlayer.on('contentended', this.boundContentEndedListener);
454  if (this.vjsPlayer.ads.inAdBreak()) {
455    this.vjsPlayer.ads.endLinearAdMode();
456  }
457  this.vjsControls.show();
458};
459
460/**
461 * Handles an individual ad start.
462 */
463PlayerWrapper.prototype.onAdStart = function () {
464  this.vjsPlayer.trigger('ads-ad-started');
465};
466
467/**
468 * Handles when all ads have finished playing.
469 */
470PlayerWrapper.prototype.onAllAdsCompleted = function () {
471  if (this.contentComplete == true) {
472    if (this.h5Player.src != this.contentSource) {
473      this.vjsPlayer.src(this.contentSource);
474    }
475    this.controller.onContentAndAdsCompleted();
476  }
477};
478
479/**
480 * Triggers adsready for contrib-ads.
481 */
482PlayerWrapper.prototype.onAdsReady = function () {
483  this.vjsPlayer.trigger('adsready');
484};
485
486/**
487 * Changes the player source.
488 * @param {?string} contentSrc The URI for the content to be played. Leave
489 *     blank to use the existing content.
490 * @param {?boolean} playOnLoad True to play the content once it has loaded,
491 *     false to only load the content but not start playback.
492 */
493PlayerWrapper.prototype.changeSource = function (contentSrc, playOnLoad) {
494  // Only try to pause the player when initialised with a source already
495  if (this.vjsPlayer.currentSrc()) {
496    this.vjsPlayer.currentTime(0);
497    this.vjsPlayer.pause();
498  }
499  if (contentSrc) {
500    this.vjsPlayer.src(contentSrc);
501  }
502  if (playOnLoad) {
503    this.vjsPlayer.one('loadedmetadata', this.playContentFromZero.bind(this));
504  } else {
505    this.vjsPlayer.one('loadedmetadata', this.seekContentToZero.bind(this));
506  }
507};
508
509/**
510 * Seeks content to 00:00:00. This is used as an event handler for the
511 * loadedmetadata event, since seeking is not possible until that event has
512 * fired.
513 */
514PlayerWrapper.prototype.seekContentToZero = function () {
515  this.vjsPlayer.currentTime(0);
516};
517
518/**
519 * Seeks content to 00:00:00 and starts playback. This is used as an event
520 * handler for the loadedmetadata event, since seeking is not possible until
521 * that event has fired.
522 */
523PlayerWrapper.prototype.playContentFromZero = function () {
524  this.vjsPlayer.currentTime(0);
525  this.vjsPlayer.play();
526};
527
528/**
529 * Triggers an event on the VJS player
530 * @param  {string} name The event name.
531 * @param  {Object} data The event data.
532 */
533PlayerWrapper.prototype.triggerPlayerEvent = function (name, data) {
534  this.vjsPlayer.trigger(name, data);
535};
536
537/**
538 * Listener JSDoc for ESLint. This listener can be passed to
539 * addContentEndedListener.
540 * @callback listener
541 */
542
543/**
544 * Adds a listener for the 'contentended' event of the video player. This should
545 * be used instead of setting an 'contentended' listener directly to ensure that
546 * the ima can do proper cleanup of the SDK before other event listeners are
547 * called.
548 * @param {listener} listener The listener to be called when content
549 *     completes.
550 */
551PlayerWrapper.prototype.addContentEndedListener = function (listener) {
552  this.contentEndedListeners.push(listener);
553};
554
555/**
556 * Reset the player.
557 */
558PlayerWrapper.prototype.reset = function () {
559  this.vjsPlayer.on('contentended', this.boundContentEndedListener);
560  this.vjsControls.show();
561  if (this.vjsPlayer.ads.inAdBreak()) {
562    this.vjsPlayer.ads.endLinearAdMode();
563  }
564  // Reset the content time we give the SDK. Fixes an issue where requesting
565  // VMAP followed by VMAP would play the second mid-rolls as pre-rolls if
566  // the first playthrough of the video passed the second response's
567  // mid-roll time.
568  this.contentPlayheadTracker.currentTime = 0;
569  this.contentComplete = false;
vendor: 13,003 bytes, lines 570-1014
570};
571
572/**
573 * Copyright 2017 Google Inc.
574 *
575 * Licensed under the Apache License, Version 2.0 (the "License");
576 * you may not use this file except in compliance with the License.
577 * You may obtain a copy of the License at
578 *
579 *     http://www.apache.org/licenses/LICENSE-2.0
580 *
581 * Unless required by applicable law or agreed to in writing, software
582 * distributed under the License is distributed on an "AS IS" BASIS,
583 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
584 * See the License for the specific language governing permissions and
585 * limitations under the License.
586 *
587 * IMA SDK integration plugin for Video.js. For more information see
588 * https://www.github.com/googleads/videojs-ima
589 */
590
591/**
592 * Ad UI implementation.
593 *
594 * @param {Controller} controller Plugin controller.
595 * @constructor
596 * @struct
597 * @final
598 */
599var AdUi = function AdUi(controller) {
600  /**
601   * Plugin controller.
602   */
603  this.controller = controller;
604
605  /**
606   * Div used as an ad container.
607   */
608  this.adContainerDiv = document.createElement('div');
609
610  /**
611   * Div used to display ad controls.
612   */
613  this.controlsDiv = document.createElement('div');
614
615  /**
616   * Div used to display ad countdown timer.
617   */
618  this.countdownDiv = document.createElement('div');
619
620  /**
621   * Div used to display add seek bar.
622   */
623  this.seekBarDiv = document.createElement('div');
624
625  /**
626   * Div used to display ad progress (in seek bar).
627   */
628  this.progressDiv = document.createElement('div');
629
630  /**
631   * Div used to display ad play/pause button.
632   */
633  this.playPauseDiv = document.createElement('div');
634
635  /**
636   * Div used to display ad mute button.
637   */
638  this.muteDiv = document.createElement('div');
639
640  /**
641   * Div used by the volume slider.
642   */
643  this.sliderDiv = document.createElement('div');
644
645  /**
646   * Volume slider level visuals
647   */
648  this.sliderLevelDiv = document.createElement('div');
649
650  /**
651   * Div used to display ad fullscreen button.
652   */
653  this.fullscreenDiv = document.createElement('div');
654
655  /**
656   * Bound event handler for onMouseUp.
657   */
658  this.boundOnMouseUp = this.onMouseUp.bind(this);
659
660  /**
661   * Bound event handler for onMouseMove.
662   */
663  this.boundOnMouseMove = this.onMouseMove.bind(this);
664
665  /**
666   * Stores data for the ad playhead tracker.
667   */
668  this.adPlayheadTracker = {
669    'currentTime': 0,
670    'duration': 0,
671    'isPod': false,
672    'adPosition': 0,
673    'totalAds': 0
674  };
675
676  /**
677   * Used to prefix videojs ima controls.
678   */
679  this.controlPrefix = this.controller.getPlayerId() + '_';
680
681  /**
682   * Boolean flag to show or hide the ad countdown timer.
683   */
684  this.showCountdown = true;
685  if (this.controller.getSettings().showCountdown === false) {
686    this.showCountdown = false;
687  }
688
689  this.createAdContainer();
690};
691
692/**
693 * Creates the ad container.
694 */
695AdUi.prototype.createAdContainer = function () {
696  this.assignControlAttributes(this.adContainerDiv, 'ima-ad-container');
697  this.adContainerDiv.style.position = 'absolute';
698  this.adContainerDiv.style.zIndex = 1111;
699  this.adContainerDiv.addEventListener('mouseenter', this.showAdControls.bind(this), false);
700  this.adContainerDiv.addEventListener('mouseleave', this.hideAdControls.bind(this), false);
701  this.createControls();
702  this.controller.injectAdContainerDiv(this.adContainerDiv);
703};
704
705/**
706 * Create the controls.
707 */
708AdUi.prototype.createControls = function () {
709  this.assignControlAttributes(this.controlsDiv, 'ima-controls-div');
710  this.controlsDiv.style.width = '100%';
711
712  this.assignControlAttributes(this.countdownDiv, 'ima-countdown-div');
713  this.countdownDiv.innerHTML = this.controller.getSettings().adLabel;
714  this.countdownDiv.style.display = this.showCountdown ? 'block' : 'none';
715
716  this.assignControlAttributes(this.seekBarDiv, 'ima-seek-bar-div');
717  this.seekBarDiv.style.width = '100%';
718
719  this.assignControlAttributes(this.progressDiv, 'ima-progress-div');
720
721  this.assignControlAttributes(this.playPauseDiv, 'ima-play-pause-div');
722  this.addClass(this.playPauseDiv, 'ima-playing');
723  this.playPauseDiv.addEventListener('click', this.onAdPlayPauseClick.bind(this), false);
724
725  this.assignControlAttributes(this.muteDiv, 'ima-mute-div');
726  this.addClass(this.muteDiv, 'ima-non-muted');
727  this.muteDiv.addEventListener('click', this.onAdMuteClick.bind(this), false);
728
729  this.assignControlAttributes(this.sliderDiv, 'ima-slider-div');
730  this.sliderDiv.addEventListener('mousedown', this.onAdVolumeSliderMouseDown.bind(this), false);
731
732  // Hide volume slider controls on iOS as they aren't supported.
733  if (this.controller.getIsIos()) {
734    this.sliderDiv.style.display = 'none';
735  }
736
737  this.assignControlAttributes(this.sliderLevelDiv, 'ima-slider-level-div');
738
739  this.assignControlAttributes(this.fullscreenDiv, 'ima-fullscreen-div');
740  this.addClass(this.fullscreenDiv, 'ima-non-fullscreen');
741  this.fullscreenDiv.addEventListener('click', this.onAdFullscreenClick.bind(this), false);
742
743  this.adContainerDiv.appendChild(this.controlsDiv);
744  this.controlsDiv.appendChild(this.countdownDiv);
745  this.controlsDiv.appendChild(this.seekBarDiv);
746  this.controlsDiv.appendChild(this.playPauseDiv);
747  this.controlsDiv.appendChild(this.muteDiv);
748  this.controlsDiv.appendChild(this.sliderDiv);
749  this.controlsDiv.appendChild(this.fullscreenDiv);
750  this.seekBarDiv.appendChild(this.progressDiv);
751  this.sliderDiv.appendChild(this.sliderLevelDiv);
752};
753
754/**
755 * Listener for clicks on the play/pause button during ad playback.
756 */
757AdUi.prototype.onAdPlayPauseClick = function () {
758  this.controller.onAdPlayPauseClick();
759};
760
761/**
762 * Listener for clicks on the play/pause button during ad playback.
763 */
764AdUi.prototype.onAdMuteClick = function () {
765  this.controller.onAdMuteClick();
766};
767
768/**
769 * Listener for clicks on the fullscreen button during ad playback.
770 */
771AdUi.prototype.onAdFullscreenClick = function () {
772  this.controller.toggleFullscreen();
773};
774
775/**
776 * Show pause and hide play button
777 */
778AdUi.prototype.onAdsPaused = function () {
779  this.addClass(this.playPauseDiv, 'ima-paused');
780  this.removeClass(this.playPauseDiv, 'ima-playing');
781  this.showAdControls();
782};
783
784/**
785 * Show pause and hide play button
786 */
787AdUi.prototype.onAdsResumed = function () {
788  this.onAdsPlaying();
789  this.showAdControls();
790};
791
792/**
793 * Show play and hide pause button
794 */
795AdUi.prototype.onAdsPlaying = function () {
796  this.addClass(this.playPauseDiv, 'ima-playing');
797  this.removeClass(this.playPauseDiv, 'ima-paused');
798};
799
800/**
801 * Takes data from the controller to update the UI.
802 *
803 * @param {number} currentTime Current time of the ad.
804 * @param {number} remainingTime Remaining time of the ad.
805 * @param {number} duration Duration of the ad.
806 * @param {number} adPosition Index of the ad in the pod.
807 * @param {number} totalAds Total number of ads in the pod.
808 */
809AdUi.prototype.updateAdUi = function (currentTime, remainingTime, duration, adPosition, totalAds) {
810  // Update countdown timer data
811  var remainingMinutes = Math.floor(remainingTime / 60);
812  var remainingSeconds = Math.floor(remainingTime % 60);
813  if (remainingSeconds.toString().length < 2) {
814    remainingSeconds = '0' + remainingSeconds;
815  }
816  var podCount = ': ';
817  if (totalAds > 1) {
818    podCount = ' (' + adPosition + ' ' + this.controller.getSettings().adLabelNofN + ' ' + totalAds + '): ';
819  }
820  this.countdownDiv.innerHTML = this.controller.getSettings().adLabel + podCount + remainingMinutes + ':' + remainingSeconds;
821
822  // Update UI
823  var playProgressRatio = currentTime / duration;
824  var playProgressPercent = playProgressRatio * 100;
825  this.progressDiv.style.width = playProgressPercent + '%';
826};
827
828/**
829 * Handles UI changes when the ad is unmuted.
830 */
831AdUi.prototype.unmute = function () {
832  this.addClass(this.muteDiv, 'ima-non-muted');
833  this.removeClass(this.muteDiv, 'ima-muted');
834  this.sliderLevelDiv.style.width = this.controller.getPlayerVolume() * 100 + '%';
835};
836
837/**
838 * Handles UI changes when the ad is muted.
839 */
840AdUi.prototype.mute = function () {
841  this.addClass(this.muteDiv, 'ima-muted');
842  this.removeClass(this.muteDiv, 'ima-non-muted');
843  this.sliderLevelDiv.style.width = '0%';
844};
845
846/*
847 * Listener for mouse down events during ad playback. Used for volume.
848 */
849AdUi.prototype.onAdVolumeSliderMouseDown = function () {
850  document.addEventListener('mouseup', this.boundOnMouseUp, false);
851  document.addEventListener('mousemove', this.boundOnMouseMove, false);
852};
853
854/*
855 * Mouse movement listener used for volume slider.
856 */
857AdUi.prototype.onMouseMove = function (event) {
858  this.changeVolume(event);
859};
860
861/*
862 * Mouse release listener used for volume slider.
863 */
864AdUi.prototype.onMouseUp = function (event) {
865  this.changeVolume(event);
866  document.removeEventListener('mouseup', this.boundOnMouseUp);
867  document.removeEventListener('mousemove', this.boundOnMouseMove);
868};
869
870/*
871 * Utility function to set volume and associated UI
872 */
873AdUi.prototype.changeVolume = function (event) {
874  var percent = (event.clientX - this.sliderDiv.getBoundingClientRect().left) / this.sliderDiv.offsetWidth;
875  percent *= 100;
876  // Bounds value 0-100 if mouse is outside slider region.
877  percent = Math.min(Math.max(percent, 0), 100);
878  this.sliderLevelDiv.style.width = percent + '%';
879  if (this.percent == 0) {
880    this.addClass(this.muteDiv, 'ima-muted');
881    this.removeClass(this.muteDiv, 'ima-non-muted');
882  } else {
883    this.addClass(this.muteDiv, 'ima-non-muted');
884    this.removeClass(this.muteDiv, 'ima-muted');
885  }
886  this.controller.setVolume(percent / 100); // 0-1
887};
888
889/**
890 * Show the ad container.
891 */
892AdUi.prototype.showAdContainer = function () {
893  this.adContainerDiv.style.display = 'block';
894};
895
896/**
897 * Handles ad errors.
898 */
899AdUi.prototype.onAdError = function () {
900  this.adContainerDiv.style.display = 'none';
901};
902
903/**
904 * Handles ad break starting.
905 *
906 * @param {Object} adEvent The event fired by the IMA SDK.
907 */
908AdUi.prototype.onAdBreakStart = function (adEvent) {
909  this.adContainerDiv.style.display = 'block';
910
911  var contentType = adEvent.getAd().getContentType();
912  if (contentType === 'application/javascript' && !this.controller.getSettings().showControlsForJSAds) {
913    this.controlsDiv.style.display = 'none';
914  } else {
915    this.controlsDiv.style.display = 'block';
916  }
917  this.onAdsPlaying();
918  // Start with the ad controls minimized.
919  this.hideAdControls();
920};
921
922/**
923 * Handles ad break ending.
924 */
925AdUi.prototype.onAdBreakEnd = function () {
926  var currentAd = this.controller.getCurrentAd();
927  if (currentAd == null || // hide for post-roll only playlist
928  currentAd.isLinear()) {
929    // don't hide for non-linear ads
930    this.adContainerDiv.style.display = 'none';
931  }
932  this.controlsDiv.style.display = 'none';
933  this.countdownDiv.innerHTML = '';
934};
935
936/**
937 * Handles when all ads have finished playing.
938 */
939AdUi.prototype.onAllAdsCompleted = function () {
940  this.adContainerDiv.style.display = 'none';
941};
942
943/**
944 * Handles when a linear ad starts.
945 */
946AdUi.prototype.onLinearAdStart = function () {
947  // Don't bump container when controls are shown
948  this.removeClass(this.adContainerDiv, 'bumpable-ima-ad-container');
949};
950
951/**
952 * Handles when a non-linear ad starts.
953 */
954AdUi.prototype.onNonLinearAdLoad = function () {
955  // For non-linear ads that show after a linear ad. For linear ads, we show the
956  // ad container in onAdBreakStart to prevent blinking in pods.
957  this.adContainerDiv.style.display = 'block';
958  // Bump container when controls are shown
959  this.addClass(this.adContainerDiv, 'bumpable-ima-ad-container');
960};
961
962AdUi.prototype.onPlayerEnterFullscreen = function () {
963  this.addClass(this.fullscreenDiv, 'ima-fullscreen');
964  this.removeClass(this.fullscreenDiv, 'ima-non-fullscreen');
965};
966
967AdUi.prototype.onPlayerExitFullscreen = function () {
968  this.addClass(this.fullscreenDiv, 'ima-non-fullscreen');
969  this.removeClass(this.fullscreenDiv, 'ima-fullscreen');
970};
971
972/**
973 * Called when the player volume changes.
974 *
975 * @param {number} volume The new player volume.
976 */
977AdUi.prototype.onPlayerVolumeChanged = function (volume) {
978  if (volume == 0) {
979    this.addClass(this.muteDiv, 'ima-muted');
980    this.removeClass(this.muteDiv, 'ima-non-muted');
981    this.sliderLevelDiv.style.width = '0%';
982  } else {
983    this.addClass(this.muteDiv, 'ima-non-muted');
984    this.removeClass(this.muteDiv, 'ima-muted');
985    this.sliderLevelDiv.style.width = volume * 100 + '%';
986  }
987};
988
989/**
990 * Shows ad controls on mouseover.
991 */
992AdUi.prototype.showAdControls = function () {
993  this.addClass(this.controlsDiv, 'ima-controls-div-showing');
994  this.playPauseDiv.style.display = 'block';
995  this.muteDiv.style.display = 'block';
996  this.fullscreenDiv.style.display = 'block';
997  // Don't show on iOS.
998  if (!this.controller.getIsIos()) {
999    this.sliderDiv.style.display = 'block';
1000  }
1001};
1002
1003/**
1004 * Hide the ad controls.
1005 */
1006AdUi.prototype.hideAdControls = function () {
1007  this.removeClass(this.controlsDiv, 'ima-controls-div-showing');
1008  this.playPauseDiv.style.display = 'none';
1009  this.muteDiv.style.display = 'none';
1010  this.sliderDiv.style.display = 'none';
1011  this.fullscreenDiv.style.display = 'none';
1012};
1013
1014/**
1015 * Assigns the unique id and class names to the given element as well as the
1016 * style class.
1017 * @param {HTMLElement} element Element that needs the controlName assigned.
1018 * @param {string} controlName Control name to assign.
1019 */
1020AdUi.prototype.assignControlAttributes = function (element, controlName) {
1021  element.id = this.controlPrefix + controlName;
1022  element.className = this.controlPrefix + controlName + ' ' + controlName;
1023};
1024
1025/**
1026 * Returns a regular expression to test a string for the given className.
1027 *
1028 * @param {string} className The name of the class.
1029 * @return {RegExp} The regular expression used to test for that class.
1030 */
1031AdUi.prototype.getClassRegexp = function (className) {
1032  // Matches on
1033  // (beginning of string OR NOT word char)
1034  // classname
1035  // (negative lookahead word char OR end of string)
1036  return new RegExp('(^|[^A-Za-z-])' + className + '((?![A-Za-z-])|$)', 'gi');
1037};
1038
1039/**
1040 * Returns whether or not the provided element has the provied class in its
1041 * className.
1042 * @param {HTMLElement} element Element to tes.t
1043 * @param {string} className Class to look for.
1044 * @return {boolean} True if element has className in class list. False
1045 *     otherwise.
1046 */
1047AdUi.prototype.elementHasClass = function (element, className) {
1048  var classRegexp = this.getClassRegexp(className);
1049  return classRegexp.test(element.className);
1050};
1051
1052/**
1053 * Adds a class to the given element if it doesn't already have the class
1054 * @param {HTMLElement} element Element to which the class will be added.
1055 * @param {string} classToAdd Class to add.
1056 */
1057AdUi.prototype.addClass = function (element, classToAdd) {
1058  element.className = element.className.trim() + ' ' + classToAdd;
1059};
1060
1061/**
1062 * Removes a class from the given element if it has the given class
1063 *
1064 * @param {HTMLElement} element Element from which the class will be removed.
1065 * @param {string} classToRemove Class to remove.
1066 */
1067AdUi.prototype.removeClass = function (element, classToRemove) {
1068  var classRegexp = this.getClassRegexp(classToRemove);
1069  element.className = element.className.trim().replace(classRegexp, '');
1070};
1071
1072/**
1073 * @return {HTMLElement} The div for the ad container.
1074 */
1075AdUi.prototype.getAdContainerDiv = function () {
1076  return this.adContainerDiv;
1077};
1078
1079/**
1080 * Changes the flag to show or hide the ad countdown timer.
1081 *
1082 * @param {boolean} showCountdownIn Show or hide the countdown timer.
1083 */
1084AdUi.prototype.setShowCountdown = function (showCountdownIn) {
1085  this.showCountdown = showCountdownIn;
1086  this.countdownDiv.style.display = this.showCountdown ? 'block' : 'none';
1087};
1088
1089var name = "videojs-ima";
1090var version = "1.5.1";
1091var license = "Apache-2.0";
1092var main = "./dist/videojs.ima.js";
1093var author = { "name": "Google Inc." };
1094var engines = { "node": ">=0.8.0" };
1095var scripts = { "contBuild": "watch 'npm run rollup:max' src", "predevServer": "echo \"Starting up server on localhost:8000.\"", "devServer": "forever start ./node_modules/http-server/bin/http-server -p 8000 && npm run contBuild", "postdevServer": "forever stop ./node_modules/http-server/bin/http-server", "lint": "eslint \"src/*.js\"", "rollup": "npm-run-all rollup:*", "rollup:max": "rollup -c configs/rollup.config.js", "rollup:min": "rollup -c configs/rollup.config.min.js", "pretest": "npm run rollup", "start": "npm run devServer", "test": "npm-run-all test:*", "test:vjs5": "npm install [email protected] --no-save && npm-run-all -p -r testServer webdriver", "test:vjs6": "npm install video.js@6 --no-save && npm-run-all -p -r testServer webdriver", "testServer": "http-server --cors -p 8000 --silent", "preversion": "node scripts/preversion.js && npm run lint && npm test", "version": "node scripts/version.js", "postversion": "node scripts/postversion.js", "webdriver": "mocha test/webdriver/*.js --no-timeouts" };
1096var repository = { "type": "git", "url": "https://github.com/googleads/videojs-ima" };
1097var files = ["CHANGELOG.md", "LICENSE", "README.md", "dist/", "src/"];
1098var dependencies = { "can-autoplay": "^3.0.0", "video.js": "^5.19.2 || ^6", "videojs-contrib-ads": "^6" };
1099var devDependencies = { "babel-core": "^6.26.0", "babel-preset-env": "^1.6.1", "child_process": "^1.0.2", "chromedriver": "^2.35.
vendor: 7,087 bytes, lines 1099-1320
10990", "conventional-changelog-cli": "^1.3.5", "conventional-changelog-videojs": "^3.0.0", "eslint": "^4.11.0", "eslint-config-google": "^0.9.1", "eslint-plugin-jsdoc": "^3.2.0", "forever": "^0.15.3", "geckodriver": "^1.10.0", "http-server": "^0.10.0", "mocha": "^4.0.1", "npm-run-all": "^4.1.2", "path": "^0.12.7", "rimraf": "^2.6.2", "rollup": "^0.51.8", "rollup-plugin-babel": "^3.0.3", "rollup-plugin-copy": "^0.2.3", "rollup-plugin-json": "^2.3.0", "rollup-plugin-uglify": "^2.0.1", "selenium-webdriver": "^3.6.0", "uglify-es": "^3.1.10", "watch": "^1.0.2" };
1100var keywords = ["videojs", "videojs-plugin"];
1101var pkg = {
1102	name: name,
1103	version: version,
1104	license: license,
1105	main: main,
1106	author: author,
1107	engines: engines,
1108	scripts: scripts,
1109	repository: repository,
1110	files: files,
1111	dependencies: dependencies,
1112	devDependencies: devDependencies,
1113	keywords: keywords
1114};
1115
1116/**
1117 * Copyright 2017 Google Inc.
1118 *
1119 * Licensed under the Apache License, Version 2.0 (the "License");
1120 * you may not use this file except in compliance with the License.
1121 * You may obtain a copy of the License at
1122 *
1123 *     http://www.apache.org/licenses/LICENSE-2.0
1124 *
1125 * Unless required by applicable law or agreed to in writing, software
1126 * distributed under the License is distributed on an "AS IS" BASIS,
1127 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1128 * See the License for the specific language governing permissions and
1129 * limitations under the License.
1130 *
1131 * IMA SDK integration plugin for Video.js. For more information see
1132 * https://www.github.com/googleads/videojs-ima
1133 */
1134
1135/**
1136 * Implementation of the IMA SDK for the plugin.
1137 *
1138 * @param {Object} controller Reference to the parent controller.
1139 *
1140 * @constructor
1141 * @struct
1142 * @final
1143 */
1144var SdkImpl = function SdkImpl(controller) {
1145  /**
1146   * Plugin controller.
1147   */
1148  this.controller = controller;
1149
1150  /**
1151   * IMA SDK AdDisplayContainer.
1152   */
1153  this.adDisplayContainer = null;
1154
1155  /**
1156   * True if the AdDisplayContainer has been initialized. False otherwise.
1157   */
1158  this.adDisplayContainerInitialized = false;
1159
1160  /**
1161   * IMA SDK AdsLoader
1162   */
1163  this.adsLoader = null;
1164
1165  /**
1166   * IMA SDK AdsManager
1167   */
1168  this.adsManager = null;
1169
1170  /**
1171   * IMA SDK AdsRenderingSettings.
1172   */
1173  this.adsRenderingSettings = null;
1174
1175  /**
1176   * Ad tag URL. Should return VAST, VMAP, or ad rules.
1177   */
1178  this.adTagUrl = null;
1179
1180  /**
1181   * VAST, VMAP, or ad rules response. Used in lieu of fetching a response
1182   * from an ad tag URL.
1183   */
1184  this.adsResponse = null;
1185
1186  /**
1187   * Current IMA SDK Ad.
1188   */
1189  this.currentAd = null;
1190
1191  /**
1192   * Timer used to track ad progress.
1193   */
1194  this.adTrackingTimer = null;
1195
1196  /**
1197   * True if ALL_ADS_COMPLETED has fired, false until then.
1198   */
1199  this.allAdsCompleted = false;
1200
1201  /**
1202   * True if ads are currently displayed, false otherwise.
1203   * True regardless of ad pause state if an ad is currently being displayed.
1204   */
1205  this.adsActive = false;
1206
1207  /**
1208   * True if ad is currently playing, false if ad is paused or ads are not
1209   * currently displayed.
1210   */
1211  this.adPlaying = false;
1212
1213  /**
1214   * True if the ad is muted, false otherwise.
1215   */
1216  this.adMuted = false;
1217
1218  /**
1219   * Listener to be called to trigger manual ad break playback.
1220   */
1221  this.adBreakReadyListener = undefined;
1222
1223  /**
1224   * Tracks whether or not we have already called adsLoader.contentComplete().
1225   */
1226  this.contentCompleteCalled = false;
1227
1228  /**
1229   * Stores the dimensions for the ads manager.
1230   */
1231  this.adsManagerDimensions = {
1232    width: 0,
1233    height: 0
1234  };
1235
1236  /**
1237   * Boolean flag to enable manual ad break playback.
1238   */
1239  this.autoPlayAdBreaks = true;
1240  if (this.controller.getSettings().autoPlayAdBreaks === false) {
1241    this.autoPlayAdBreaks = false;
1242  }
1243
1244  // Set SDK settings from plugin settings.
1245  if (this.controller.getSettings().locale) {
1246    /* eslint no-undef: 'error' */
1247    /* global google */
1248    google.ima.settings.setLocale(this.controller.getSettings().locale);
1249  }
1250  if (this.controller.getSettings().disableFlashAds) {
1251    google.ima.settings.setDisableFlashAds(this.controller.getSettings().disableFlashAds);
1252  }
1253  if (this.controller.getSettings().disableCustomPlaybackForIOS10Plus) {
1254    google.ima.settings.setDisableCustomPlaybackForIOS10Plus(this.controller.getSettings().disableCustomPlaybackForIOS10Plus);
1255  }
1256};
1257
1258/**
1259 * Creates and initializes the IMA SDK objects.
1260 */
1261SdkImpl.prototype.initAdObjects = function () {
1262  this.adDisplayContainer = new google.ima.AdDisplayContainer(this.controller.getAdContainerDiv(), this.controller.getContentPlayer());
1263
1264  this.adsLoader = new google.ima.AdsLoader(this.adDisplayContainer);
1265
1266  this.adsLoader.getSettings().setVpaidMode(google.ima.ImaSdkSettings.VpaidMode.ENABLED);
1267  if (this.controller.getSettings().vpaidAllowed == false) {
1268    this.adsLoader.getSettings().setVpaidMode(google.ima.ImaSdkSettings.VpaidMode.DISABLED);
1269  }
1270  if (this.controller.getSettings().vpaidMode) {
1271    this.adsLoader.getSettings().setVpaidMode(this.controller.getSettings().vpaidMode);
1272  }
1273
1274  if (this.controller.getSettings().locale) {
1275    this.adsLoader.getSettings().setLocale(this.controller.getSettings().locale);
1276  }
1277
1278  if (this.controller.getSettings().numRedirects) {
1279    this.adsLoader.getSettings().setNumRedirects(this.controller.getSettings().numRedirects);
1280  }
1281
1282  this.adsLoader.getSettings().setPlayerType('videojs-ima');
1283  this.adsLoader.getSettings().setPlayerVersion(pkg.version);
1284  this.adsLoader.getSettings().setAutoPlayAdBreaks(this.autoPlayAdBreaks);
1285
1286  this.adsLoader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, this.onAdsManagerLoaded.bind(this), false);
1287  this.adsLoader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, this.onAdsLoaderError.bind(this), false);
1288};
1289
1290/**
1291 * Creates the AdsRequest and request ads through the AdsLoader.
1292 */
1293SdkImpl.prototype.requestAds = function () {
1294  var adsRequest = new google.ima.AdsRequest();
1295  if (this.controller.getSettings().adTagUrl) {
1296    adsRequest.adTagUrl = this.controller.getSettings().adTagUrl;
1297  } else {
1298    adsRequest.adsResponse = this.controller.getSettings().adsResponse;
1299  }
1300  if (this.controller.getSettings().forceNonLinearFullSlot) {
1301    adsRequest.forceNonLinearFullSlot = true;
1302  }
1303
1304  if (this.controller.getSettings().vastLoadTimeout) {
1305    adsRequest.vastLoadTimeout = this.controller.getSettings().vastLoadTimeout;
1306  }
1307
1308  adsRequest.linearAdSlotWidth = this.controller.getPlayerWidth();
1309  adsRequest.linearAdSlotHeight = this.controller.getPlayerHeight();
1310  adsRequest.nonLinearAdSlotWidth = this.controller.getSettings().nonLinearWidth || this.controller.getPlayerWidth();
1311  adsRequest.nonLinearAdSlotHeight = this.controller.getSettings().nonLinearHeight || this.controller.getPlayerHeight();
1312  adsRequest.setAdWillAutoPlay(this.controller.adsWillAutoplay());
1313  adsRequest.setAdWillPlayMuted(this.controller.adsWillPlayMuted());
1314
1315  this.adsLoader.requestAds(adsRequest);
1316  this.controller.triggerPlayerEvent('ads-request', adsRequest);
1317};
1318
1319/**
1320 * Listener for the ADS_MANAGER_LOADED event. Creates the AdsManager,
1321 * sets up event listeners, and triggers the 'adsready' event for
1322 * videojs-ads-contrib.
1323 *
1324 * @param {google.ima.AdsManagerLoadedEvent} adsManagerLoadedEvent Fired when
1325 *     the AdsManager loads.
1326 */
1327SdkImpl.prototype.onAdsManagerLoaded = function (adsManagerLoadedEvent) {
1328  this.createAdsRenderingSettings();
1329
1330  this.adsManager = adsManagerLoadedEvent.getAdsManager(this.controller.getContentPlayheadTracker(), this.adsRenderingSettings);
1331
1332  this.adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, this.onAdError.bind(this));
1333  this.adsManager.addEventListener(google.ima.AdEvent.Type.AD_BREAK_READY, this.onAdBreakReady.bind(this));
1334  this.adsManager.addEventListener(google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, this.onContentPauseRequested.bind(this));
1335  this.adsManager.addEventListener(google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, this.onContentResumeRequested.bind(this));
1336  this.adsManager.addEventListener(google.ima.AdEvent.Type.ALL_ADS_COMPLETED, this.onAllAdsCompleted.bind(this));
1337
1338  this.adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, this.onAdLoaded.bind(this));
1339  this.adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, this.onAdStarted.bind(this));
1340  this.adsManager.addEventListener(google.ima.AdEvent.Type.CLICK, this.onAdPaused.bind(this));
1341  this.adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, this.onAdComplete.bind(this));
1342  this.adsManager.addEventListener(google.ima.AdEvent.Type.SKIPPED, this.onAdComplete.bind(this));
1343
1344  if (this.controller.getIsMobile()) {
1345    // Show/hide controls on pause and resume (triggered by tap).
1346    this.adsManager.addEventListener(google.ima.AdEvent.Type.PAUSED, this.onAdPaused.bind(this));
1347    this.adsManager.addEventListener(google.ima.AdEvent.Type.RESUMED, this.onAdResumed.bind(this));
1348  }
1349
1350  if (!this.autoPlayAdBreaks) {
1351    this.initAdsManager();
1352  }
1353
1354  this.controller.onAdsReady();
1355
1356  if (this.controller.getSettings().adsManagerLoadedCallback) {
1357    this.controller.getSettings().adsManagerLoadedCallback();
1358  }
1359};
1360
1361/**
1362 * Listener for errors fired by the AdsLoader.
1363 * @param {google.ima.AdErrorEvent} event The error event thrown by the
1364 *     AdsLoader. See
1365 *     https://developers.google.com/interactive-media-ads/docs/sdks/html5/v3/apis#ima.AdError.Type
1366 */
1367SdkImpl.prototype.onAdsLoaderError = function (event) {
1368  window.console.warn('AdsLoader error: ' + event.getError());
1369  this.controller.onErrorLoadingAds(event);
1370  if (this.adsManager) {
1371    this.adsManager.destroy();
1372  }
1373};
1374
1375/**
1376 * Initialize the ads manager.
1377 */
1378SdkImpl.prototype.initAdsManager = function () {
1379  try {
1380    var initWidth = this.controller.getPlayerWidth();
1381    var initHeight = this.controller.getPlayerHeight();
1382    this.adsManagerDimensions.width = initWidth;
1383    this.adsManagerDimensions.height = initHeight;
1384    this.adsManager.init(initWidth, initHeight, google.ima.ViewMode.NORMAL);
1385    this.adsManager.setVolume(this.controller.getPlayerVolume());
1386    if (!this.adDisplayContainerInitialized) {
1387      this.adDisplayContainer.initialize();
1388      this.adDisplayContainer.initialized = true;
1389    }
1390  } catch (adError) {
1391    this.onAdError(adError);
1392  }
1393};
1394
1395/**
1396 * Create AdsRenderingSettings for the IMA SDK.
1397 */
1398SdkImpl.prototype.createAdsRenderingSettings = function () {
1399  this.adsRenderingSettings = new google.ima.AdsRenderingSettings();
1400  this.adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;
1401  if (this.controller.getSettings().adsRenderingSettings) {
1402    for (var setting in this.controller.getSettings().adsRenderingSettings) {
1403      if (setting !== '') {
1404        this.adsRenderingSettings[setting] = this.controller.getSettings().adsRenderingSettings[setting];
1405      }
1406    }
1407  }
1408};
1409
1410/**
1411 * Listener for errors thrown by the AdsManager.
1412 * @param {google.ima.AdErrorEvent} adErrorEvent The error event thrown by
1413 *     the AdsManager.
1414 */
1415SdkImpl.prototype.onAdError = function (adErrorEvent) {
1416  var errorMessage = adErrorEvent.getError !== undefined ? adErrorEvent.getError() : adErrorEvent.stack;
1417  window.console.warn('Ad error: ' + errorMessage);
1418
1419  this.adsManager.destroy();
1420  this.controller.onAdError(adErrorEvent);
1421
1422  // reset these so consumers don't think we are still in an ad break,
1423  // but reset them after any prior cleanup happens
1424  this.adsActive = false;
vendor: 35,251 bytes, lines 1425-2678
1425  this.adPlaying = false;
1426};
1427
1428/**
1429 * Listener for AD_BREAK_READY. Passes event on to publisher's listener.
1430 * @param {google.ima.AdEvent} adEvent AdEvent thrown by the AdsManager.
1431 */
1432SdkImpl.prototype.onAdBreakReady = function (adEvent) {
1433  this.adBreakReadyListener(adEvent);
1434};
1435
1436/**
1437 * Pauses the content video and displays the ad container so ads can play.
1438 * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.
1439 */
1440SdkImpl.prototype.onContentPauseRequested = function (adEvent) {
1441  this.adsActive = true;
1442  this.adPlaying = true;
1443  this.controller.onAdBreakStart(adEvent);
1444};
1445
1446/**
1447 * Resumes content video and hides the ad container.
1448 * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.
1449 */
1450SdkImpl.prototype.onContentResumeRequested = function (adEvent) {
1451  this.adsActive = false;
1452  this.adPlaying = false;
1453  this.controller.onAdBreakEnd();
1454  // Hide controls in case of future non-linear ads. They'll be unhidden in
1455  // content_pause_requested.
1456};
1457
1458/**
1459 * Records that ads have completed and calls contentAndAdsEndedListeners
1460 * if content is also complete.
1461 * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.
1462 */
1463SdkImpl.prototype.onAllAdsCompleted = function (adEvent) {
1464  this.allAdsCompleted = true;
1465  this.controller.onAllAdsCompleted();
1466};
1467
1468/**
1469 * Starts the content video when a non-linear ad is loaded.
1470 * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.
1471 */
1472SdkImpl.prototype.onAdLoaded = function (adEvent) {
1473  if (!adEvent.getAd().isLinear()) {
1474    this.controller.onNonLinearAdLoad();
1475    this.controller.playContent();
1476  }
1477};
1478
1479/**
1480 * Starts the interval timer to check the current ad time when an ad starts
1481 * playing.
1482 * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.
1483 */
1484SdkImpl.prototype.onAdStarted = function (adEvent) {
1485  this.currentAd = adEvent.getAd();
1486  if (this.currentAd.isLinear()) {
1487    this.adTrackingTimer = setInterval(this.onAdPlayheadTrackerInterval.bind(this), 250);
1488    this.controller.onLinearAdStart();
1489  } else {
1490    this.controller.onNonLinearAdStart();
1491  }
1492};
1493
1494/**
1495 * Handles an ad click. Puts the player UI in a paused state.
1496 */
1497SdkImpl.prototype.onAdPaused = function () {
1498  this.controller.onAdsPaused();
1499};
1500
1501/**
1502 * Syncs controls when an ad resumes.
1503 * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.
1504 */
1505SdkImpl.prototype.onAdResumed = function (adEvent) {
1506  this.controller.onAdsResumed();
1507};
1508
1509/**
1510 * Clears the interval timer for current ad time when an ad completes.
1511 */
1512SdkImpl.prototype.onAdComplete = function () {
1513  if (this.currentAd.isLinear()) {
1514    clearInterval(this.adTrackingTimer);
1515  }
1516};
1517
1518/**
1519 * Gets the current time and duration of the ad and calls the method to
1520 * update the ad UI.
1521 */
1522SdkImpl.prototype.onAdPlayheadTrackerInterval = function () {
1523  var remainingTime = this.adsManager.getRemainingTime();
1524  var duration = this.currentAd.getDuration();
1525  var currentTime = duration - remainingTime;
1526  currentTime = currentTime > 0 ? currentTime : 0;
1527  var totalAds = 0;
1528  var adPosition = void 0;
1529  if (this.currentAd.getAdPodInfo()) {
1530    adPosition = this.currentAd.getAdPodInfo().getAdPosition();
1531    totalAds = this.currentAd.getAdPodInfo().getTotalAds();
1532  }
1533
1534  this.controller.onAdPlayheadUpdated(currentTime, remainingTime, duration, adPosition, totalAds);
1535};
1536
1537/**
1538 * Called by the player wrapper when content completes.
1539 */
1540SdkImpl.prototype.onContentComplete = function () {
1541  if (this.adsLoader) {
1542    this.adsLoader.contentComplete();
1543    this.contentCompleteCalled = true;
1544  }
1545
1546  if (this.adsManager && this.adsManager.getCuePoints() && !this.adsManager.getCuePoints().includes(-1)) {
1547    this.controller.onNoPostroll();
1548  }
1549
1550  if (this.allAdsCompleted) {
1551    this.controller.onContentAndAdsCompleted();
1552  }
1553};
1554
1555/**
1556 * Called when the player is disposed.
1557 */
1558SdkImpl.prototype.onPlayerDisposed = function () {
1559  if (this.adTrackingTimer) {
1560    clearInterval(this.adTrackingTimer);
1561  }
1562  if (this.adsManager) {
1563    this.adsManager.destroy();
1564    this.adsManager = null;
1565  }
1566};
1567
1568SdkImpl.prototype.onPlayerReadyForPreroll = function () {
1569  if (this.autoPlayAdBreaks) {
1570    this.initAdsManager();
1571    try {
1572      this.controller.showAdContainer();
1573      // Sync ad volume with content volume.
1574      this.adsManager.setVolume(this.controller.getPlayerVolume());
1575      this.adsManager.start();
1576    } catch (adError) {
1577      this.onAdError(adError);
1578    }
1579  }
1580};
1581
1582SdkImpl.prototype.onPlayerReady = function () {
1583  this.initAdObjects();
1584
1585  if (this.controller.getSettings().adTagUrl || this.controller.getSettings().adsResponse) {
1586    this.requestAds();
1587  }
1588};
1589
1590SdkImpl.prototype.onPlayerEnterFullscreen = function () {
1591  if (this.adsManager) {
1592    this.adsManager.resize(window.screen.width, window.screen.height, google.ima.ViewMode.FULLSCREEN);
1593  }
1594};
1595
1596SdkImpl.prototype.onPlayerExitFullscreen = function () {
1597  if (this.adsManager) {
1598    this.adsManager.resize(this.controller.getPlayerWidth(), this.controller.getPlayerHeight(), google.ima.ViewMode.NORMAL);
1599  }
1600};
1601
1602/**
1603 * Called when the player volume changes.
1604 *
1605 * @param {number} volume The new player volume.
1606 */
1607SdkImpl.prototype.onPlayerVolumeChanged = function (volume) {
1608  if (this.adsManager) {
1609    this.adsManager.setVolume(volume);
1610  }
1611
1612  if (volume == 0) {
1613    this.adMuted = true;
1614  } else {
1615    this.adMuted = false;
1616  }
1617};
1618
1619/**
1620 * Called when the player wrapper detects that the player has been resized.
1621 *
1622 * @param {number} width The post-resize width of the player.
1623 * @param {number} height The post-resize height of the player.
1624 */
1625SdkImpl.prototype.onPlayerResize = function (width, height) {
1626  if (this.adsManager) {
1627    this.adsManagerDimensions.width = width;
1628    this.adsManagerDimensions.height = height;
1629    /* global google */
1630    /* eslint no-undef: 'error' */
1631    this.adsManager.resize(width, height, google.ima.ViewMode.NORMAL);
1632  }
1633};
1634
1635/**
1636 * @return {Object} The current ad.
1637 */
1638SdkImpl.prototype.getCurrentAd = function () {
1639  return this.currentAd;
1640};
1641
1642/**
1643 * Listener JSDoc for ESLint. This listener can be passed to
1644 * setAdBreakReadyListener.
1645 * @callback listener
1646 */
1647
1648/**
1649 * Sets the listener to be called to trigger manual ad break playback.
1650 * @param {listener} listener The listener to be called to trigger manual ad
1651 *     break playback.
1652 */
1653SdkImpl.prototype.setAdBreakReadyListener = function (listener) {
1654  this.adBreakReadyListener = listener;
1655};
1656
1657/**
1658 * @return {boolean} True if an ad is currently playing. False otherwise.
1659 */
1660SdkImpl.prototype.isAdPlaying = function () {
1661  return this.adPlaying;
1662};
1663
1664/**
1665 * @return {boolean} True if an ad is currently playing. False otherwise.
1666 */
1667SdkImpl.prototype.isAdMuted = function () {
1668  return this.adMuted;
1669};
1670
1671/**
1672 * Pause ads.
1673 */
1674SdkImpl.prototype.pauseAds = function () {
1675  this.adsManager.pause();
1676  this.adPlaying = false;
1677};
1678
1679/**
1680 * Resume ads.
1681 */
1682SdkImpl.prototype.resumeAds = function () {
1683  this.adsManager.resume();
1684  this.adPlaying = true;
1685};
1686
1687/**
1688 * Unmute ads.
1689 */
1690SdkImpl.prototype.unmute = function () {
1691  this.adsManager.setVolume(1);
1692  this.adMuted = false;
1693};
1694
1695/**
1696 * Mute ads.
1697 */
1698SdkImpl.prototype.mute = function () {
1699  this.adsManager.setVolume(0);
1700  this.adMuted = true;
1701};
1702
1703/**
1704 * Set the volume of the ads. 0-1.
1705 *
1706 * @param {number} volume The new volume.
1707 */
1708SdkImpl.prototype.setVolume = function (volume) {
1709  this.adsManager.setVolume(volume);
1710  if (volume == 0) {
1711    this.adMuted = true;
1712  } else {
1713    this.adMuted = false;
1714  }
1715};
1716
1717/**
1718 * Initializes the AdDisplayContainer. On mobile, this must be done as a
1719 * result of user action.
1720 */
1721SdkImpl.prototype.initializeAdDisplayContainer = function () {
1722  if (this.adDisplayContainer) {
1723    this.adDisplayContainerInitialized = true;
1724    this.adDisplayContainer.initialize();
1725  }
1726};
1727
1728/**
1729 * Called by publishers in manual ad break playback mode to start an ad
1730 * break.
1731 */
1732SdkImpl.prototype.playAdBreak = function () {
1733  if (!this.autoPlayAdBreaks) {
1734    this.controller.showAdContainer();
1735    // Sync ad volume with content volume.
1736    this.adsManager.setVolume(this.controller.getPlayerVolume());
1737    this.adsManager.start();
1738  }
1739};
1740
1741/**
1742 * Callback JSDoc for ESLint. This callback can be passed to addEventListener.
1743 * @callback callback
1744 */
1745
1746/**
1747 * Ads an EventListener to the AdsManager. For a list of available events,
1748 * see
1749 * https://developers.google.com/interactive-media-ads/docs/sdks/html5/v3/apis#ima.AdEvent.Type
1750 * @param {google.ima.AdEvent.Type} event The AdEvent.Type for which to
1751 *     listen.
1752 * @param {callback} callback The method to call when the event is fired.
1753 */
1754SdkImpl.prototype.addEventListener = function (event, callback) {
1755  if (this.adsManager) {
1756    this.adsManager.addEventListener(event, callback);
1757  }
1758};
1759
1760/**
1761 * Returns the instance of the AdsManager.
1762 * @return {google.ima.AdsManager} The AdsManager being used by the plugin.
1763 */
1764SdkImpl.prototype.getAdsManager = function () {
1765  return this.adsManager;
1766};
1767
1768/**
1769 * Reset the SDK implementation.
1770 */
1771SdkImpl.prototype.reset = function () {
1772  this.adsActive = false;
1773  this.adPlaying = false;
1774  if (this.adTrackingTimer) {
1775    // If this is called while an ad is playing, stop trying to get that
1776    // ad's current time.
1777    clearInterval(this.adTrackingTimer);
1778  }
1779  if (this.adsManager) {
1780    this.adsManager.destroy();
1781    this.adsManager = null;
1782  }
1783  if (this.adsLoader && !this.contentCompleteCalled) {
1784    this.adsLoader.contentComplete();
1785  }
1786  this.contentCompleteCalled = false;
1787  this.allAdsCompleted = false;
1788};
1789
1790/**
1791 * Copyright 2017 Google Inc.
1792 *
1793 * Licensed under the Apache License, Version 2.0 (the "License");
1794 * you may not use this file except in compliance with the License.
1795 * You may obtain a copy of the License at
1796 *
1797 *     http://www.apache.org/licenses/LICENSE-2.0
1798 *
1799 * Unless required by applicable law or agreed to in writing, software
1800 * distributed under the License is distributed on an "AS IS" BASIS,
1801 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1802 * See the License for the specific language governing permissions and
1803 * limitations under the License.
1804 *
1805 * IMA SDK integration plugin for Video.js. For more information see
1806 * https://www.github.com/googleads/videojs-ima
1807 */
1808/**
1809 * The grand coordinator of the plugin. Facilitates communication between all
1810 * other plugin classes.
1811 *
1812 * @param {Object} player Instance of the video.js player.
1813 * @param {Object} options Options provided by the implementation.
1814 * @constructor
1815 * @struct
1816 * @final
1817 */
1818var Controller = function Controller(player, options) {
1819  /**
1820   * Stores user-provided settings.
1821   * @type {Object}
1822   */
1823  this.settings = {};
1824
1825  /**
1826   * Content and ads ended listeners passed by the publisher to the plugin.
1827   * These will be called when the plugin detects that content *and all
1828   * ads* have completed. This differs from the contentEndedListeners in that
1829   * contentEndedListeners will fire between content ending and a post-roll
1830   * playing, whereas the contentAndAdsEndedListeners will fire after the
1831   * post-roll completes.
1832   */
1833  this.contentAndAdsEndedListeners = [];
1834
1835  /**
1836   * Whether or not we are running on a mobile platform.
1837   */
1838  this.isMobile = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/Android/i);
1839
1840  /**
1841   * Whether or not we are running on an iOS platform.
1842   */
1843  this.isIos = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i);
1844
1845  this.initWithSettings(options);
1846
1847  /**
1848   * Stores contrib-ads default settings.
1849   */
1850  var contribAdsDefaults = {
1851    debug: this.settings.debug,
1852    timeout: this.settings.timeout,
1853    prerollTimeout: this.settings.prerollTimeout
1854  };
1855  var adsPluginSettings = this.extend({}, contribAdsDefaults, options.contribAdsSettings || {});
1856
1857  this.playerWrapper = new PlayerWrapper(player, adsPluginSettings, this);
1858  this.adUi = new AdUi(this);
1859  this.sdkImpl = new SdkImpl(this);
1860};
1861
1862Controller.IMA_DEFAULTS = {
1863  debug: false,
1864  timeout: 5000,
1865  prerollTimeout: 1000,
1866  adLabel: 'Advertisement',
1867  adLabelNofN: 'of',
1868  showControlsForJSAds: true
1869};
1870
1871/**
1872 * Extends the settings to include user-provided settings.
1873 *
1874 * @param {Object} options Options to be used in initialization.
1875 */
1876Controller.prototype.initWithSettings = function (options) {
1877  this.settings = this.extend({}, Controller.IMA_DEFAULTS, options || {});
1878
1879  this.warnAboutDeprecatedSettings();
1880
1881  // Default showing countdown timer to true.
1882  this.showCountdown = true;
1883  if (this.settings.showCountdown === false) {
1884    this.showCountdown = false;
1885  }
1886};
1887
1888/**
1889 * Logs console warnings when deprecated settings are used.
1890 */
1891Controller.prototype.warnAboutDeprecatedSettings = function () {
1892  var _this = this;
1893
1894  var deprecatedSettings = ['adWillAutoplay', 'adsWillAutoplay', 'adWillPlayMuted', 'adsWillPlayMuted'];
1895  deprecatedSettings.forEach(function (setting) {
1896    if (_this.settings[setting] !== undefined) {
1897      console.warn('WARNING: videojs.ima setting ' + setting + ' is deprecated');
1898    }
1899  });
1900};
1901
1902/**
1903 * Return the settings object.
1904 *
1905 * @return {Object} The settings object.
1906 */
1907Controller.prototype.getSettings = function () {
1908  return this.settings;
1909};
1910
1911/**
1912 * Return whether or not we're in a mobile environment.
1913 *
1914 * @return {boolean} True if running on mobile, false otherwise.
1915 */
1916Controller.prototype.getIsMobile = function () {
1917  return this.isMobile;
1918};
1919
1920/**
1921 * Return whether or not we're in an iOS environment.
1922 *
1923 * @return {boolean} True if running on iOS, false otherwise.
1924 */
1925Controller.prototype.getIsIos = function () {
1926  return this.isIos;
1927};
1928
1929/**
1930 * Inject the ad container div into the DOM.
1931 *
1932 * @param{HTMLElement} adContainerDiv The ad container div.
1933 */
1934Controller.prototype.injectAdContainerDiv = function (adContainerDiv) {
1935  this.playerWrapper.injectAdContainerDiv(adContainerDiv);
1936};
1937
1938/**
1939 * @return {HTMLElement} The div for the ad container.
1940 */
1941Controller.prototype.getAdContainerDiv = function () {
1942  return this.adUi.getAdContainerDiv();
1943};
1944
1945/**
1946 * @return {Object} The content player.
1947 */
1948Controller.prototype.getContentPlayer = function () {
1949  return this.playerWrapper.getContentPlayer();
1950};
1951
1952/**
1953 * Returns the content playhead tracker.
1954 *
1955 * @return {Object} The content playhead tracker.
1956 */
1957Controller.prototype.getContentPlayheadTracker = function () {
1958  return this.playerWrapper.getContentPlayheadTracker();
1959};
1960
1961/**
1962 * Requests ads.
1963 */
1964Controller.prototype.requestAds = function () {
1965  this.sdkImpl.requestAds();
1966};
1967
1968/**
1969 * Add or modify a setting.
1970 *
1971 * @param {string} key Key to modify
1972 * @param {Object} value Value to set at key.
1973 */
1974Controller.prototype.setSetting = function (key, value) {
1975  this.settings[key] = value;
1976};
1977
1978/**
1979 * Called when there is an error loading ads.
1980 *
1981 * @param {Object} adErrorEvent The ad error event thrown by the IMA SDK.
1982 */
1983Controller.prototype.onErrorLoadingAds = function (adErrorEvent) {
1984  this.adUi.onAdError();
1985  this.playerWrapper.onAdError(adErrorEvent);
1986};
1987
1988/**
1989 * Called by the ad UI when the play/pause button is clicked.
1990 */
1991Controller.prototype.onAdPlayPauseClick = function () {
1992  if (this.sdkImpl.isAdPlaying()) {
1993    this.adUi.onAdsPaused();
1994    this.sdkImpl.pauseAds();
1995  } else {
1996    this.adUi.onAdsPlaying();
1997    this.sdkImpl.resumeAds();
1998  }
1999};
2000
2001/**
2002 * Called by the ad UI when the mute button is clicked.
2003 *
2004 */
2005Controller.prototype.onAdMuteClick = function () {
2006  if (this.sdkImpl.isAdMuted()) {
2007    this.playerWrapper.unmute();
2008    this.adUi.unmute();
2009    this.sdkImpl.unmute();
2010  } else {
2011    this.playerWrapper.mute();
2012    this.adUi.mute();
2013    this.sdkImpl.mute();
2014  }
2015};
2016
2017/**
2018 * Set the volume of the player and ads. 0-1.
2019 *
2020 * @param {number} volume The new volume.
2021 */
2022Controller.prototype.setVolume = function (volume) {
2023  this.playerWrapper.setVolume(volume);
2024  this.sdkImpl.setVolume(volume);
2025};
2026
2027/**
2028 * @return {number} The volume of the content player.
2029 */
2030Controller.prototype.getPlayerVolume = function () {
2031  return this.playerWrapper.getVolume();
2032};
2033
2034/**
2035 * Toggle fullscreen state.
2036 */
2037Controller.prototype.toggleFullscreen = function () {
2038  this.playerWrapper.toggleFullscreen();
2039};
2040
2041/**
2042 * Relays ad errors to the player wrapper.
2043 *
2044 * @param {Object} adErrorEvent The ad error event thrown by the IMA SDK.
2045 */
2046Controller.prototype.onAdError = function (adErrorEvent) {
2047  this.adUi.onAdError();
2048  this.playerWrapper.onAdError(adErrorEvent);
2049};
2050
2051/**
2052 * Handles ad break starting.
2053 *
2054 * @param {Object} adEvent The event fired by the IMA SDK.
2055 */
2056Controller.prototype.onAdBreakStart = function (adEvent) {
2057  this.playerWrapper.onAdBreakStart();
2058  this.adUi.onAdBreakStart(adEvent);
2059};
2060
2061/**
2062 * Show the ad container.
2063 */
2064Controller.prototype.showAdContainer = function () {
2065  this.adUi.showAdContainer();
2066};
2067
2068/**
2069 * Handles ad break ending.
2070 */
2071Controller.prototype.onAdBreakEnd = function () {
2072  this.playerWrapper.onAdBreakEnd();
2073  this.adUi.onAdBreakEnd();
2074};
2075
2076/**
2077 * Handles when all ads have finished playing.
2078 */
2079Controller.prototype.onAllAdsCompleted = function () {
2080  this.adUi.onAllAdsCompleted();
2081  this.playerWrapper.onAllAdsCompleted();
2082};
2083
2084/**
2085 * Handles the SDK firing an ad paused event.
2086 */
2087Controller.prototype.onAdsPaused = function () {
2088  this.adUi.onAdsPaused();
2089};
2090
2091/**
2092 * Handles the SDK firing an ad resumed event.
2093 */
2094Controller.prototype.onAdsResumed = function () {
2095  this.adUi.onAdsResumed();
2096};
2097
2098/**
2099 * Takes data from the sdk impl and passes it to the ad UI to update the UI.
2100 *
2101 * @param {number} currentTime Current time of the ad.
2102 * @param {number} remainingTime Remaining time of the ad.
2103 * @param {number} duration Duration of the ad.
2104 * @param {number} adPosition Index of the ad in the pod.
2105 * @param {number} totalAds Total number of ads in the pod.
2106 */
2107Controller.prototype.onAdPlayheadUpdated = function (currentTime, remainingTime, duration, adPosition, totalAds) {
2108  this.adUi.updateAdUi(currentTime, remainingTime, duration, adPosition, totalAds);
2109};
2110
2111/**
2112 * @return {Object} The current ad.
2113 */
2114Controller.prototype.getCurrentAd = function () {
2115  return this.sdkImpl.getCurrentAd();
2116};
2117
2118/**
2119 * Play content.
2120 */
2121Controller.prototype.playContent = function () {
2122  this.playerWrapper.play();
2123};
2124
2125/**
2126 * Handles when a linear ad starts.
2127 */
2128Controller.prototype.onLinearAdStart = function () {
2129  this.adUi.onLinearAdStart();
2130  this.playerWrapper.onAdStart();
2131};
2132
2133/**
2134 * Handles when a non-linear ad loads.
2135 */
2136Controller.prototype.onNonLinearAdLoad = function () {
2137  this.adUi.onNonLinearAdLoad();
2138};
2139
2140/**
2141 * Handles when a non-linear ad starts.
2142 */
2143Controller.prototype.onNonLinearAdStart = function () {
2144  this.adUi.onNonLinearAdLoad();
2145  this.playerWrapper.onAdStart();
2146};
2147
2148/**
2149 * Get the player width.
2150 *
2151 * @return {number} The width of the player.
2152 */
2153Controller.prototype.getPlayerWidth = function () {
2154  return this.playerWrapper.getPlayerWidth();
2155};
2156
2157/**
2158 * Get the player height.
2159 *
2160 * @return {number} The height of the player.
2161 */
2162Controller.prototype.getPlayerHeight = function () {
2163  return this.playerWrapper.getPlayerHeight();
2164};
2165
2166/**
2167 * Tells the player wrapper that ads are ready.
2168 */
2169Controller.prototype.onAdsReady = function () {
2170  this.playerWrapper.onAdsReady();
2171};
2172
2173/**
2174 * Called when the player wrapper detects that the player has been resized.
2175 *
2176 * @param {number} width The post-resize width of the player.
2177 * @param {number} height The post-resize height of the player.
2178 */
2179Controller.prototype.onPlayerResize = function (width, height) {
2180  this.sdkImpl.onPlayerResize(width, height);
2181};
2182
2183/**
2184 * Called by the player wrapper when content completes.
2185 */
2186Controller.prototype.onContentComplete = function () {
2187  this.sdkImpl.onContentComplete();
2188};
2189
2190/**
2191 * Called by the player wrapper when it's time to play a post-roll but we don't
2192 * have one to play.
2193 */
2194Controller.prototype.onNoPostroll = function () {
2195  this.playerWrapper.onNoPostroll();
2196};
2197
2198/**
2199 * Called when content and all ads have completed.
2200 */
2201Controller.prototype.onContentAndAdsCompleted = function () {
2202  for (var index in this.contentAndAdsEndedListeners) {
2203    if (typeof this.contentAndAdsEndedListeners[index] === 'function') {
2204      this.contentAndAdsEndedListeners[index]();
2205    }
2206  }
2207};
2208
2209/**
2210 * Called when the player is disposed.
2211 */
2212Controller.prototype.onPlayerDisposed = function () {
2213  this.contentAndAdsEndedListeners = [];
2214  this.sdkImpl.onPlayerDisposed();
2215};
2216
2217/**
2218 * Called when the player is ready to play a pre-roll.
2219 */
2220Controller.prototype.onPlayerReadyForPreroll = function () {
2221  this.sdkImpl.onPlayerReadyForPreroll();
2222};
2223
2224/**
2225 * Called when the player is ready.
2226 */
2227Controller.prototype.onPlayerReady = function () {
2228  this.sdkImpl.onPlayerReady();
2229};
2230
2231/**
2232 * Called when the player enters fullscreen.
2233 */
2234Controller.prototype.onPlayerEnterFullscreen = function () {
2235  this.adUi.onPlayerEnterFullscreen();
2236  this.sdkImpl.onPlayerEnterFullscreen();
2237};
2238
2239/**
2240 * Called when the player exits fullscreen.
2241 */
2242Controller.prototype.onPlayerExitFullscreen = function () {
2243  this.adUi.onPlayerExitFullscreen();
2244  this.sdkImpl.onPlayerExitFullscreen();
2245};
2246
2247/**
2248 * Called when the player volume changes.
2249 *
2250 * @param {number} volume The new player volume.
2251 */
2252Controller.prototype.onPlayerVolumeChanged = function (volume) {
2253  this.adUi.onPlayerVolumeChanged(volume);
2254  this.sdkImpl.onPlayerVolumeChanged(volume);
2255};
2256
2257/**
2258 * Sets the content of the video player. You should use this method instead
2259 * of setting the content src directly to ensure the proper ad tag is
2260 * requested when the video content is loaded.
2261 * @param {?string} contentSrc The URI for the content to be played. Leave
2262 *     blank to use the existing content.
2263 * @param {?string} adTag The ad tag to be requested when the content loads.
2264 *     Leave blank to use the existing ad tag.
2265 * @param {?boolean} playOnLoad True to play the content once it has loaded,
2266 *     false to only load the content but not start playback.
2267 */
2268Controller.prototype.setContentWithAdTag = function (contentSrc, adTag, playOnLoad) {
2269  this.reset();
2270  this.settings.adTagUrl = adTag ? adTag : this.settings.adTagUrl;
2271  this.playerWrapper.changeSource(contentSrc, playOnLoad);
2272};
2273
2274/**
2275 * Sets the content of the video player. You should use this method instead
2276 * of setting the content src directly to ensure the proper ads response is
2277 * used when the video content is loaded.
2278 * @param {?string} contentSrc The URI for the content to be played. Leave
2279 *     blank to use the existing content.
2280 * @param {?string} adsResponse The ads response to be requested when the
2281 *     content loads. Leave blank to use the existing ads response.
2282 * @param {?boolean} playOnLoad True to play the content once it has loaded,
2283 *     false to only load the content but not start playback.
2284 */
2285Controller.prototype.setContentWithAdsResponse = function (contentSrc, adsResponse, playOnLoad) {
2286  this.reset();
2287  this.settings.adsResponse = adsResponse ? adsResponse : this.settings.adsResponse;
2288  this.playerWrapper.changeSource(contentSrc, playOnLoad);
2289};
2290
2291/**
2292 * Resets the state of the plugin.
2293 */
2294Controller.prototype.reset = function () {
2295  this.sdkImpl.reset();
2296  this.playerWrapper.reset();
2297};
2298
2299/**
2300 * Listener JSDoc for ESLint. This listener can be passed to
2301 * (add|remove)ContentEndedListener.
2302 * @callback listener
2303 */
2304
2305/**
2306 * Adds a listener for the 'contentended' event of the video player. This should
2307 * be used instead of setting an 'contentended' listener directly to ensure that
2308 * the ima can do proper cleanup of the SDK before other event listeners are
2309 * called.
2310 * @param {listener} listener The listener to be called when content
2311 *     completes.
2312 */
2313Controller.prototype.addContentEndedListener = function (listener) {
2314  this.playerWrapper.addContentEndedListener(listener);
2315};
2316
2317/**
2318 * Adds a listener that will be called when content and all ads have
2319 * finished playing.
2320 * @param {listener} listener The listener to be called when content and ads
2321 *     complete.
2322 */
2323Controller.prototype.addContentAndAdsEndedListener = function (listener) {
2324  this.contentAndAdsEndedListeners.push(listener);
2325};
2326
2327/**
2328 * Sets the listener to be called to trigger manual ad break playback.
2329 * @param {listener} listener The listener to be called to trigger manual ad
2330 *     break playback.
2331 */
2332Controller.prototype.setAdBreakReadyListener = function (listener) {
2333  this.sdkImpl.setAdBreakReadyListener(listener);
2334};
2335
2336/**
2337 * Changes the flag to show or hide the ad countdown timer.
2338 *
2339 * @param {boolean} showCountdownIn Show or hide the countdown timer.
2340 */
2341Controller.prototype.setShowCountdown = function (showCountdownIn) {
2342  this.adUi.setShowCountdown(showCountdownIn);
2343  this.showCountdown = showCountdownIn;
2344  this.countdownDiv.style.display = this.showCountdown ? 'block' : 'none';
2345};
2346
2347/**
2348 * Initializes the AdDisplayContainer. On mobile, this must be done as a
2349 * result of user action.
2350 */
2351Controller.prototype.initializeAdDisplayContainer = function () {
2352  this.sdkImpl.initializeAdDisplayContainer();
2353};
2354
2355/**
2356 * Called by publishers in manual ad break playback mode to start an ad
2357 * break.
2358 */
2359Controller.prototype.playAdBreak = function () {
2360  this.sdkImpl.playAdBreak();
2361};
2362
2363/**
2364 * Callback JSDoc for ESLint. This callback can be passed to addEventListener.
2365 * @callback callback
2366 */
2367
2368/**
2369 * Ads an EventListener to the AdsManager. For a list of available events,
2370 * see
2371 * https://developers.google.com/interactive-media-ads/docs/sdks/html5/v3/apis#ima.AdEvent.Type
2372 * @param {google.ima.AdEvent.Type} event The AdEvent.Type for which to
2373 *     listen.
2374 * @param {callback} callback The method to call when the event is fired.
2375 */
2376Controller.prototype.addEventListener = function (event, callback) {
2377  this.sdkImpl.addEventListener(event, callback);
2378};
2379
2380/**
2381 * Returns the instance of the AdsManager.
2382 * @return {google.ima.AdsManager} The AdsManager being used by the plugin.
2383 */
2384Controller.prototype.getAdsManager = function () {
2385  return this.sdkImpl.getAdsManager();
2386};
2387
2388/**
2389 * Returns the instance of the player id.
2390 * @return {string} The player id.
2391 */
2392Controller.prototype.getPlayerId = function () {
2393  return this.playerWrapper.getPlayerId();
2394};
2395
2396/**
2397 * Changes the ad tag. You will need to call requestAds after this method
2398 * for the new ads to be requested.
2399 * @param {?string} adTag The ad tag to be requested the next time
2400 *     requestAds is called.
2401 */
2402Controller.prototype.changeAdTag = function (adTag) {
2403  this.reset();
2404  this.settings.adTagUrl = adTag;
2405};
2406
2407/**
2408 * Pauses the ad.
2409 */
2410Controller.prototype.pauseAd = function () {
2411  this.adUi.onAdsPaused();
2412  this.sdkImpl.pauseAds();
2413};
2414
2415/**
2416 * Resumes the ad.
2417 */
2418Controller.prototype.resumeAd = function () {
2419  this.adUi.onAdsPlaying();
2420  this.sdkImpl.resumeAds();
2421};
2422
2423/**
2424 * @return {boolean} true if we expect that ads will autoplay. false otherwise.
2425 */
2426Controller.prototype.adsWillAutoplay = function () {
2427  if (this.settings.adsWillAutoplay !== undefined) {
2428    return this.settings.adsWillAutoplay;
2429  } else if (this.settings.adWillAutoplay !== undefined) {
2430    return this.settings.adWillAutoplay;
2431  } else {
2432    return !!this.playerWrapper.getPlayerOptions().autoplay;
2433  }
2434};
2435
2436/**
2437 * @return {boolean} true if we expect that ads will autoplay. false otherwise.
2438 */
2439Controller.prototype.adsWillPlayMuted = function () {
2440  if (this.settings.adsWillPlayMuted !== undefined) {
2441    return this.settings.adsWillPlayMuted;
2442  } else if (this.settings.adWillPlayMuted !== undefined) {
2443    return this.settings.adWillPlayMuted;
2444  } else if (this.playerWrapper.getPlayerOptions().muted !== undefined) {
2445    return this.playerWrapper.getPlayerOptions().muted;
2446  } else {
2447    return this.playerWrapper.getVolume() == 0;
2448  }
2449};
2450
2451/**
2452 * Triggers an event on the VJS player
2453 * @param  {string} name The event name.
2454 * @param  {Object} data The event data.
2455 */
2456Controller.prototype.triggerPlayerEvent = function (name, data) {
2457  this.playerWrapper.triggerPlayerEvent(name, data);
2458};
2459
2460/**
2461 * Extends an object to include the contents of objects at parameters 2 onward.
2462 *
2463 * @param {Object} obj The object onto which the subsequent objects' parameters
2464 *     will be extended. This object will be modified.
2465 * @param {...Object} var_args The objects whose properties are to be extended
2466 *     onto obj.
2467 * @return {Object} The extended object.
2468 */
2469Controller.prototype.extend = function (obj) {
2470  var arg = void 0;
2471  var index = void 0;
2472  var key = void 0;
2473
2474  for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
2475    args[_key - 1] = arguments[_key];
2476  }
2477
2478  for (index = 0; index < args.length; index++) {
2479    arg = args[index];
2480    for (key in arg) {
2481      if (arg.hasOwnProperty(key)) {
2482        obj[key] = arg[key];
2483      }
2484    }
2485  }
2486  return obj;
2487};
2488
2489/**
2490 * Copyright 2017 Google Inc.
2491 *
2492 * Licensed under the Apache License, Version 2.0 (the "License");
2493 * you may not use this file except in compliance with the License.
2494 * You may obtain a copy of the License at
2495 *
2496 *     http://www.apache.org/licenses/LICENSE-2.0
2497 *
2498 * Unless required by applicable law or agreed to in writing, software
2499 * distributed under the License is distributed on an "AS IS" BASIS,
2500 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2501 * See the License for the specific language governing permissions and
2502 * limitations under the License.
2503 *
2504 * IMA SDK integration plugin for Video.js. For more information see
2505 * https://www.github.com/googleads/videojs-ima
2506 */
2507
2508/**
2509 * Exposes the ImaPlugin to a publisher implementation.
2510 *
2511 * @param {Object} player Instance of the video.js player to which this plugin
2512 *     will be added.
2513 * @param {Object} options Options provided by the implementation.
2514 * @constructor
2515 * @struct
2516 * @final
2517 */
2518var ImaPlugin = function ImaPlugin(player, options) {
2519  this.controller = new Controller(player, options);
2520
2521  /**
2522   * Listener JSDoc for ESLint. This listener can be passed to
2523   * addContent(AndAds)EndedListener.
2524   * @callback listener
2525   */
2526
2527  /**
2528   * Adds a listener that will be called when content and all ads have
2529   * finished playing.
2530   * @param {listener} listener The listener to be called when content and ads
2531   *     complete.
2532   */
2533  this.addContentAndAdsEndedListener = function (listener) {
2534    this.controller.addContentAndAdsEndedListener(listener);
2535  }.bind(this);
2536
2537  /**
2538   * Adds a listener for the 'contentended' event of the video player. This
2539   * should be used instead of setting an 'contentended' listener directly to
2540   * ensure that the ima can do proper cleanup of the SDK before other event
2541   * listeners are called.
2542   * @param {listener} listener The listener to be called when content
2543   *     completes.
2544   */
2545  this.addContentEndedListener = function (listener) {
2546    this.controller.addContentEndedListener(listener);
2547  }.bind(this);
2548
2549  /**
2550   * Callback JSDoc for ESLint. This callback can be passed to addEventListener.
2551   * @callback callback
2552   */
2553
2554  /**
2555   * Ads an EventListener to the AdsManager. For a list of available events,
2556   * see
2557   * https://developers.google.com/interactive-media-ads/docs/sdks/html5/v3/apis#ima.AdEvent.Type
2558   * @param {google.ima.AdEvent.Type} event The AdEvent.Type for which to
2559   *     listen.
2560   * @param {callback} callback The method to call when the event is fired.
2561   */
2562  this.addEventListener = function (event, callback) {
2563    this.controller.addEventListener(event, callback);
2564  }.bind(this);
2565
2566  /**
2567   * Changes the ad tag. You will need to call requestAds after this method
2568   * for the new ads to be requested.
2569   * @param {?string} adTag The ad tag to be requested the next time requestAds
2570   *     is called.
2571   */
2572  this.changeAdTag = function (adTag) {
2573    this.controller.changeAdTag(adTag);
2574  }.bind(this);
2575
2576  /**
2577   * Returns the instance of the AdsManager.
2578   * @return {google.ima.AdsManager} The AdsManager being used by the plugin.
2579   */
2580  this.getAdsManager = function () {
2581    return this.controller.getAdsManager();
2582  }.bind(this);
2583
2584  /**
2585   * Initializes the AdDisplayContainer. On mobile, this must be done as a
2586   * result of user action.
2587   */
2588  this.initializeAdDisplayContainer = function () {
2589    this.controller.initializeAdDisplayContainer();
2590  }.bind(this);
2591
2592  /**
2593   * Pauses the ad.
2594   */
2595  this.pauseAd = function () {
2596    this.controller.pauseAd();
2597  }.bind(this);
2598
2599  /**
2600   * Called by publishers in manual ad break playback mode to start an ad
2601   * break.
2602   */
2603  this.playAdBreak = function () {
2604    this.controller.playAdBreak();
2605  }.bind(this);
2606
2607  /**
2608   * Creates the AdsRequest and request ads through the AdsLoader.
2609   */
2610  this.requestAds = function () {
2611    this.controller.requestAds();
2612  }.bind(this);
2613
2614  /**
2615   * Resumes the ad.
2616   */
2617  this.resumeAd = function () {
2618    this.controller.resumeAd();
2619  }.bind(this);
2620
2621  /**
2622   * Sets the listener to be called to trigger manual ad break playback.
2623   * @param {listener} listener The listener to be called to trigger manual ad
2624   *     break playback.
2625   */
2626  this.setAdBreakReadyListener = function (listener) {
2627    this.controller.setAdBreakReadyListener(listener);
2628  }.bind(this);
2629
2630  /**
2631   * Sets the content of the video player. You should use this method instead
2632   * of setting the content src directly to ensure the proper ad tag is
2633   * requested when the video content is loaded.
2634   * @param {?string} contentSrc The URI for the content to be played. Leave
2635   *     blank to use the existing content.
2636   * @param {?string} adTag The ad tag to be requested when the content loads.
2637   *     Leave blank to use the existing ad tag.
2638   * @param {?boolean} playOnLoad True to play the content once it has loaded,
2639   *     false to only load the content but not start playback.
2640   */
2641  this.setContentWithAdTag = function (contentSrc, adTag, playOnLoad) {
2642    this.controller.setContentWithAdTag(contentSrc, adTag, playOnLoad);
2643  }.bind(this);
2644
2645  /**
2646   * Sets the content of the video player. You should use this method instead
2647   * of setting the content src directly to ensure the proper ads response is
2648   * used when the video content is loaded.
2649   * @param {?string} contentSrc The URI for the content to be played. Leave
2650   *     blank to use the existing content.
2651   * @param {?string} adsResponse The ads response to be requested when the
2652   *     content loads. Leave blank to use the existing ads response.
2653   * @param {?boolean} playOnLoad True to play the content once it has loaded,
2654   *     false to only load the content but not start playback.
2655   */
2656  this.setContentWithAdsResponse = function (contentSrc, adsResponse, playOnLoad) {
2657    this.controller.setContentWithAdsResponse(contentSrc, adsResponse, playOnLoad);
2658  }.bind(this);
2659
2660  /**
2661   * Changes the flag to show or hide the ad countdown timer.
2662   *
2663   * @param {boolean} showCountdownIn Show or hide the countdown timer.
2664   */
2665  this.setShowCountdown = function (showCountdownIn) {
2666    this.controller.setShowCountdown(showCountdownIn);
2667  }.bind(this);
2668};
2669
2670var init = function init(options) {
2671  /* eslint no-invalid-this: 'off' */
2672  this.ima = new ImaPlugin(this, options);
2673};
2674
2675var registerPlugin = videojs.registerPlugin || videojs.plugin;
2676registerPlugin('ima', init);
2677
2678})));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.