File

src/app/modules/player-helper/components/player/player.component.ts

Implements

OnInit AfterViewInit OnChanges OnDestroy

Metadata

Index

Properties
Methods
Inputs
Outputs
HostListeners

Constructor

constructor(configService: ConfigService, router: Router, toasterService: ToasterService, resourceService: ResourceService, navigationHelperService: NavigationHelperService, deviceDetectorService: DeviceDetectorService, userService: UserService, formService: FormService, contentUtilsServiceService: ContentUtilsServiceService, contentService: ContentService, cdr: ChangeDetectorRef, playerService: PublicPlayerService, utilService: UtilService)
Parameters :
Name Type Optional
configService ConfigService No
router Router No
toasterService ToasterService No
resourceService ResourceService No
navigationHelperService NavigationHelperService No
deviceDetectorService DeviceDetectorService No
userService UserService No
formService FormService No
contentUtilsServiceService ContentUtilsServiceService No
contentService ContentService No
cdr ChangeDetectorRef No
playerService PublicPlayerService No
utilService UtilService No

Inputs

contentData
Type : any
contentProgressEvents$
Type : Subject<any>
isContentDeleted
Type : Subject<any>
isSingleContent
Type : boolean
overlayImagePath
Type : string
pageId
Type : string
playerConfig
Type : PlayerConfig
playerOption
Type : any
telemetryObject
Type : literal type

Outputs

assessmentEvents
Type : EventEmitter
closePlayerEvent
Type : EventEmitter
playerOnDestroyEvent
Type : EventEmitter
questionScoreReviewEvents
Type : EventEmitter
questionScoreSubmitEvents
Type : EventEmitter
ratingPopupClose
Type : EventEmitter
sceneChangeEvent
Type : EventEmitter
selfAssessLastAttempt
Type : EventEmitter

HostListeners

window:orientationchange
Arguments : '$event'
window:orientationchange()
window:popstate
Arguments : '$event'
window:popstate(event)

Methods

Public addUserDataToContext
addUserDataToContext()
Returns : void
adjustPlayerHeight
adjustPlayerHeight()

Adjust player height after load

Returns : void
checkForQumlPlayer
checkForQumlPlayer()
Returns : void
closeContentFullScreen
closeContentFullScreen()
Returns : void
closeFullscreen
closeFullscreen()

when user clicks on close button this method will let the player to exit from fullscreen mode and

  1. video thumbnail will be shown for single content
  2. content-details page will be shown ( for multi-result dial-code search flow)
Returns : void
closeModal
closeModal()
Returns : void
emitSceneChangeEvent
emitSceneChangeEvent(timer: number)
Parameters :
Name Type Optional Default value
timer number No 0
Returns : void
enablePlayer
enablePlayer(mode: boolean)

this method will handle play button click and turn the player into landscape

Parameters :
Name Type Optional
mode boolean No
Returns : void
eventHandler
eventHandler(event)
Parameters :
Name Optional
event No
Returns : void
focusOnReplay
focusOnReplay()
Returns : void
generateContentReadEvent
generateContentReadEvent(event: any, newPlayerEvent?)
Parameters :
Name Type Optional
event any No
newPlayerEvent Yes
Returns : void
generatelimitedAttemptEvent
generatelimitedAttemptEvent(event)
Parameters :
Name Optional
event No
Returns : void
generateScoreSubmitEvent
generateScoreSubmitEvent(event: any)
Parameters :
Name Type Optional
event any No
Returns : void
Public handleOrientationChange
handleOrientationChange()
Decorators :
@HostListener('window:orientationchange', ['$event'])
Returns : void
loadCdnPlayer
loadCdnPlayer()
Returns : void
loadDefaultPlayer
loadDefaultPlayer(url)
Parameters :
Name Optional Default value
url No this.configService.appConfig.PLAYER_CONFIG.baseURL
Returns : void
loadNewPlayer
loadNewPlayer()
Returns : void
loadOldPlayer
loadOldPlayer()
Returns : void
loadPlayer
loadPlayer()
Returns : void
ngAfterViewInit
ngAfterViewInit()

loadPlayer method will be called

Returns : void
ngOnChanges
ngOnChanges(changes)
Parameters :
Name Optional
changes No
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
onPopState
onPopState(event)
Decorators :
@HostListener('window:popstate', ['$event'])
Parameters :
Name Optional
event No
Returns : void
rotatePlayer
rotatePlayer()

this method checks for the browser capability to be fullscreen via if-else ladder if match found, it will turn the player along will be close button into fullscreen and then rotate it to landscape mode

Returns : void
setTelemetryData
setTelemetryData()
Returns : void
showRatingPopup
showRatingPopup(event)
Parameters :
Name Optional
event No
Returns : void
updateMetadataForDesktop
updateMetadataForDesktop()
Returns : void

Properties

buildNumber
Type : string
closeButtonInteractEdata
Type : IInteractEventEdata
collectionId
Type : string
Public configService
Type : ConfigService
CONSTANT
Type : object
Default value : { ACCESSEVENT: 'renderer:question:submitscore', ISLASTATTEMPT: 'renderer:selfassess:lastattempt', MAXATTEMPT: 'renderer:maxLimitExceeded', ACCESSREVIEWEVENT: 'renderer:question:reviewAssessment' }
contentDeleted
Default value : false
contentId
Type : string
contentIframe
Type : ElementRef
Decorators :
@ViewChild('contentIframe')
contentRatingModal
Default value : false
Public contentUtilsServiceService
Type : ContentUtilsServiceService
Public formService
Type : FormService
isCdnWorking
Type : string
isDesktopApp
Default value : false
isFullScreenView
Default value : false
isMobileOrTab
Type : boolean
loadPlayerInteractEdata
Type : IInteractEventEdata
mobileViewDisplay
Type : string
Default value : 'block'
modal
Decorators :
@ViewChild('modal')

Dom element reference of contentRatingModal

Public navigationHelperService
Type : NavigationHelperService
playerLoaded
Default value : false
playerOverlayImage
Type : string
Public playerService
Type : PublicPlayerService
playerType
Type : string
previewCdnUrl
Type : string
Public resourceService
Type : ResourceService
Public router
Type : Router
Public showNewPlayer
Default value : false
showPlayIcon
Default value : true
showQumlPlayer
Default value : false
showRatingModalAfterClose
Default value : false
Public unsubscribe
Default value : new Subject<void>()
import { ConfigService, NavigationHelperService, UtilService } from '@sunbird/shared';
import { Component, AfterViewInit, ViewChild, ElementRef, Input, Output, EventEmitter,
OnChanges, HostListener, OnInit, ChangeDetectorRef } from '@angular/core';
import * as _ from 'lodash-es';
import { PlayerConfig } from '@sunbird/shared';
import { Router } from '@angular/router';
import { ToasterService, ResourceService, ContentUtilsServiceService } from '@sunbird/shared';
const OFFLINE_ARTIFACT_MIME_TYPES = ['application/epub'];
import { Subject } from 'rxjs';
import { DeviceDetectorService } from 'ngx-device-detector';
import { IInteractEventEdata } from '@sunbird/telemetry';
import { UserService, FormService } from '../../../core/services';
import { OnDestroy } from '@angular/core';
import { takeUntil } from 'rxjs/operators';
import { CsContentProgressCalculator } from '@project-sunbird/client-services/services/content/utilities/content-progress-calculator';
import { ContentService } from '@sunbird/core';
import { PublicPlayerService } from '@sunbird/public';

@Component({
  selector: 'app-player',
  templateUrl: './player.component.html',
  styleUrls: ['./player.component.scss']
})
export class PlayerComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy {
  @Input() playerConfig: PlayerConfig;
  @Output() assessmentEvents = new EventEmitter<any>();
  @Output() questionScoreSubmitEvents = new EventEmitter<any>();
  @Output() questionScoreReviewEvents = new EventEmitter<any>();
  @ViewChild('contentIframe') contentIframe: ElementRef;
  @Output() playerOnDestroyEvent = new EventEmitter<any>();
  @Output() sceneChangeEvent = new EventEmitter<any>();
  @Input() contentProgressEvents$: Subject<any>;
  playerLoaded = false;
  buildNumber: string;
  @Input() playerOption: any;
  contentRatingModal = false;
  showRatingModalAfterClose = false;
  previewCdnUrl: string;
  isCdnWorking: string;
  CONSTANT = {
    ACCESSEVENT: 'renderer:question:submitscore',
    ISLASTATTEMPT: 'renderer:selfassess:lastattempt',
    MAXATTEMPT: 'renderer:maxLimitExceeded',
    ACCESSREVIEWEVENT: 'renderer:question:reviewAssessment'
  };
  @Input() overlayImagePath: string;
  @Input() isSingleContent: boolean;
  @Input() telemetryObject: {};
  @Input() pageId: string;
  @Input() contentData;
  @Input() isContentDeleted: Subject<any>;
  @Output() closePlayerEvent = new EventEmitter<any>();
  @Output() ratingPopupClose = new EventEmitter<any>();
  @Output() selfAssessLastAttempt = new EventEmitter<any>();
  contentDeleted = false;
  isMobileOrTab: boolean;
  showPlayIcon = true;
  closeButtonInteractEdata: IInteractEventEdata;
  loadPlayerInteractEdata: IInteractEventEdata;
  playerOverlayImage: string;
  isFullScreenView = false;
  public unsubscribe = new Subject<void>();
  public showNewPlayer = false;
  mobileViewDisplay = 'block';
  playerType: string;
  isDesktopApp = false;
  showQumlPlayer = false;
  contentId: string;
  collectionId:string;

  /**
 * Dom element reference of contentRatingModal
 */
  @ViewChild('modal') modal;

  @HostListener('window:popstate', ['$event'])
  onPopState(event) {
    this.closeContentFullScreen();
  }

  constructor(public configService: ConfigService, public router: Router, private toasterService: ToasterService,
    public resourceService: ResourceService, public navigationHelperService: NavigationHelperService,
    private deviceDetectorService: DeviceDetectorService, private userService: UserService, public formService: FormService
    , public contentUtilsServiceService: ContentUtilsServiceService, private contentService: ContentService,
    private cdr: ChangeDetectorRef, public playerService: PublicPlayerService, private utilService: UtilService) {
    this.buildNumber = (<HTMLInputElement>document.getElementById('buildNumber'))
      ? (<HTMLInputElement>document.getElementById('buildNumber')).value : '1.0';
    this.previewCdnUrl = (<HTMLInputElement>document.getElementById('previewCdnUrl'))
      ? (<HTMLInputElement>document.getElementById('previewCdnUrl')).value : undefined;
    this.isCdnWorking = (<HTMLInputElement>document.getElementById('cdnWorking'))
      ? (<HTMLInputElement>document.getElementById('cdnWorking')).value : 'no';
  }

  @HostListener('window:orientationchange', ['$event'])
  public handleOrientationChange() {
    const screenType = _.get(screen, 'orientation.type');
      if ( screenType === 'portrait-primary' || screenType === 'portrait-secondary' ) {
        this.closeFullscreen();
      }
  }

  ngOnInit() {
    this.checkForQumlPlayer()
    // If `sessionStorage` has UTM data; append the UTM data to context.cdata
    if (this.playerConfig && sessionStorage.getItem('UTM')) {
      let utmData;
      try {
        utmData = JSON.parse(sessionStorage.getItem('UTM'));
      } catch (error) {
        throw new Error('JSON Parse Error => UTM data');
      }
      if (utmData && _.get(this.playerConfig, 'context.cdata')) {
        this.playerConfig.context.cdata = _.union(this.playerConfig.context.cdata, utmData);
      }
      if (utmData && !_.get(this.playerConfig, 'context.cdata')) {
        this.playerConfig.context['cdata'] = [];
        this.playerConfig.context.cdata = _.union(this.playerConfig.context.cdata, utmData);
      }
    }
    this.isDesktopApp = this.utilService.isDesktopApp;
    // Check for loggedIn user; and append user data to context object
    // User data (`firstName` and `lastName`) is used to show at the end of quiz
    if (this.playerConfig) {
        this.addUserDataToContext();
    }
    this.isMobileOrTab = this.deviceDetectorService.isMobile() || this.deviceDetectorService.isTablet();
    if (this.isSingleContent === false) {
      this.showPlayIcon = false;
    }
    this.setTelemetryData();
    this.navigationHelperService.contentFullScreenEvent.
    pipe(takeUntil(this.unsubscribe)).subscribe(isFullScreen => {
      this.isFullScreenView = isFullScreen;
      const root: HTMLElement = document.getElementsByTagName( 'html' )[0];
      if (isFullScreen) {
        root.classList.add('PlayerMediaQueryClass');
        document.body.classList.add('o-y-hidden');
      } else {
        root.classList.remove('PlayerMediaQueryClass');
        document.body.classList.remove('o-y-hidden');
      }
      if (this.isDesktopApp) {
        const hideCM = isFullScreen ? true : false;
        this.navigationHelperService.handleContentManagerOnFullscreen(hideCM);
      }
      this.loadPlayer();
    });

    this.contentUtilsServiceService.contentShareEvent.pipe(takeUntil(this.unsubscribe)).subscribe(data => {
      if (this.isMobileOrTab && data === 'close') {
        this.mobileViewDisplay = 'block';
      }
    });
  }

  /**
   * loadPlayer method will be called
   */
  ngAfterViewInit() {
    if (this.playerConfig) {
      this.loadPlayer();
    }
  }

  ngOnChanges(changes) {
    this.contentRatingModal = false;
    this.showNewPlayer = false;
    this.cdr.detectChanges();
    if (this.playerConfig) {
      this.playerOverlayImage = this.overlayImagePath ? this.overlayImagePath : _.get(this.playerConfig, 'metadata.appIcon');
      this.loadPlayer();
    }
  }
  loadCdnPlayer() {
    const iFrameSrc = this.configService.appConfig.PLAYER_CONFIG.cdnUrl + '&build_number=' + this.buildNumber;
    setTimeout(() => {
      const playerElement = this.contentIframe.nativeElement;
      playerElement.src = iFrameSrc;
      playerElement.onload = (event) => {
        try {
          this.adjustPlayerHeight();
          playerElement.contentWindow.initializePreview(this.playerConfig);
          if (this.playerLoaded) {
            playerElement.removeEventListener('renderer:telemetry:event', telemetryEvent => this.generateContentReadEvent(telemetryEvent));
            window.frames['contentPlayer'].removeEventListener('message', accessEvent => this.generateScoreSubmitEvent(accessEvent), false);
          }
          this.playerLoaded = true;
          playerElement.addEventListener('renderer:telemetry:event', telemetryEvent => this.generateContentReadEvent(telemetryEvent));
          window.frames['contentPlayer'].addEventListener('message', accessEvent => this.generateScoreSubmitEvent(accessEvent), false);
        } catch (err) {
          this.loadDefaultPlayer();
        }
      };
    }, 0);
  }
  loadDefaultPlayer(url = this.configService.appConfig.PLAYER_CONFIG.baseURL) {
    const iFrameSrc = url + '&build_number=' + this.buildNumber;
    setTimeout(() => {
      const playerElement = this.contentIframe.nativeElement;
      playerElement.src = iFrameSrc;
      playerElement.onload = (event) => {
        try {
          this.adjustPlayerHeight();
          playerElement.contentWindow.initializePreview(this.playerConfig);
          if (this.playerLoaded) {
            playerElement.removeEventListener('renderer:telemetry:event', telemetryEvent => this.generateContentReadEvent(telemetryEvent));
            window.frames['contentPlayer'].removeEventListener('message', accessEvent => this.generateScoreSubmitEvent(accessEvent), false);
          }
          this.playerLoaded = true;
          playerElement.addEventListener('renderer:telemetry:event', telemetryEvent => this.generateContentReadEvent(telemetryEvent));
          window.frames['contentPlayer'].addEventListener('message', accessEvent => this.generateScoreSubmitEvent(accessEvent), false);
        } catch (err) {
          const prevUrls = this.navigationHelperService.history;
          if (this.isCdnWorking.toLowerCase() === 'yes' && prevUrls[prevUrls.length - 2]) {
            history.back();
          }
        }
      };
    }, 0);
  }

  loadPlayer() {
    this.checkForQumlPlayer();
    this.playerType = null;
    const formReadInputParams = {
      formType: 'content',
      formAction: 'play',
      contentType: 'player'
    };
    this.formService.getFormConfig(formReadInputParams).subscribe(
      (data: any) => {
        let isNewPlayer = false;
        _.forEach(data, (value) => {
          if (_.includes(_.get(value, 'mimeType'), _.get(this.playerConfig, 'metadata.mimeType')) && _.get(value, 'version') === 2) {
            this.playerConfig.context.threshold = _.get(value, 'threshold');
            this.playerType = _.get(value, 'type');
            isNewPlayer = true;
          }
        });
        if (isNewPlayer) {
          this.playerLoaded = false;
          this.loadNewPlayer();
        } else {
          this.loadOldPlayer();
        }
      },
      (error) => {
        this.loadOldPlayer();
      }
    );
  }

  checkForQumlPlayer() {
    if (_.get(this.playerConfig, 'metadata.mimeType') === this.configService.appConfig.PLAYER_CONFIG.MIME_TYPE.questionset) {
      this.playerConfig.config.sideMenu.showDownload = false;
      if (!_.get(this.playerConfig, 'metadata.instructions')) {
        this.playerService.getQuestionSetRead(_.get(this.playerConfig, 'metadata.identifier')).subscribe((data: any) => {
          this.playerConfig.metadata.instructions = _.get(data, 'result.questionset.instructions');
          this.showQumlPlayer = true;
        }, (error) => {
          this.showQumlPlayer = true;
        });
      } else {
        this.showQumlPlayer = true;
      }
    }
  }

  loadOldPlayer() {
    this.showNewPlayer = false;
    if (this.isDesktopApp) {
      this.updateMetadataForDesktop();
      const downloadStatus = Boolean(_.get(this.playerConfig, 'metadata.desktopAppMetadata.isAvailable'));
      let playerUrl = this.configService.appConfig.PLAYER_CONFIG.localBaseUrl;
      if (!downloadStatus) {
        playerUrl = `${playerUrl}webview=true`;
      }
      this.loadDefaultPlayer(playerUrl);
      return;
    }
    if (this.isMobileOrTab) {
      this.rotatePlayer();
    }
    if (this.previewCdnUrl !== '' && (this.isCdnWorking).toLowerCase() === 'yes') {
      this.loadCdnPlayer();
      return;
    }

    this.loadDefaultPlayer();
  }

  loadNewPlayer() {
    const downloadStatus = Boolean(_.get(this.playerConfig, 'metadata.desktopAppMetadata.isAvailable'));
    const artifactUrl = _.get(this.playerConfig, 'metadata.artifactUrl');
    this.contentId = _.get(this.playerConfig, 'metadata.identifier');
    this.collectionId = _.get(this.playerConfig, 'context.objectRollup.l1');
    if (downloadStatus && artifactUrl && !_.startsWith(artifactUrl, 'http://')) {
      this.playerConfig.metadata.artifactUrl = `${location.origin}/${artifactUrl}`;
    }
    this.addUserDataToContext();
    if (this.isMobileOrTab) {
      this.isFullScreenView = true;
      if (_.get(this.playerConfig, 'metadata.mimeType') !== this.configService.appConfig.PLAYER_CONFIG.MIME_TYPE.questionset) {
        this.rotatePlayer();
      }
    }
    this.showNewPlayer = true;
    if (this.userService.loggedIn) {
      this.userService.userData$.subscribe((user: any) => {
        if (user && !user.err) {
          const userProfile = user.userProfile;
          const userId = userProfile.id;
          const varName = (userId + '_' + (this.collectionId ? this.collectionId : '') + '_' + (this.contentId ? this.contentId : '') + '_config');
          const playerConfig: any = JSON.parse(localStorage.getItem(varName)) || {};
          this.playerConfig['config'] = { ...this.playerConfig['config'], ...playerConfig };
        }
      });
    } else {
      const varName = ('guest' + '_' + (this.collectionId ? this.collectionId : '') + '_' + (this.contentId ? this.contentId : '') + '_config');;
      const playerConfig: any = JSON.parse(localStorage.getItem(varName)) || {};
      this.playerConfig['config'] = { ...this.playerConfig['config'], ...playerConfig };
    }
  }

  // Update ArtifactUrl for old Player
  updateMetadataForDesktop() {
    const downloadStatus = Boolean(_.get(this.playerConfig, 'metadata.desktopAppMetadata.isAvailable'));
    if (downloadStatus) {
      this.playerConfig.data = '';
      if (_.get(this.playerConfig, 'metadata.artifactUrl')
        && _.includes(OFFLINE_ARTIFACT_MIME_TYPES, this.playerConfig.metadata.mimeType)) {
        const artifactFileName = this.playerConfig.metadata.artifactUrl.split('/');
        this.playerConfig.metadata.artifactUrl = artifactFileName[artifactFileName.length - 1];
      }
    }
  }

  /**
   * Adjust player height after load
   */
  adjustPlayerHeight() {
    const playerWidth = $('#contentPlayer').width();
    if (playerWidth) {
      let height = playerWidth * (9 / 16);
      if (_.get(screen, 'orientation.type') === 'landscape-primary' && this.isMobileOrTab) {
        height = window.innerHeight;
      }
      $('#contentPlayer').css('height', height + 'px');
    }
  }

  generateScoreSubmitEvent(event: any) {
    if (event.data.toLowerCase() === (this.CONSTANT.ACCESSEVENT).toLowerCase()) {
      this.questionScoreSubmitEvents.emit(event);
    }
    if (event.data.toLowerCase() === (this.CONSTANT.ISLASTATTEMPT).toLowerCase()) {
      this.selfAssessLastAttempt.emit(event);
    }
    if (event.data.toLowerCase() === (this.CONSTANT.MAXATTEMPT).toLowerCase()) {
      this.selfAssessLastAttempt.emit(event);
    }
    if (event.data.toLowerCase() === (this.CONSTANT.ACCESSREVIEWEVENT).toLowerCase()) {
      this.questionScoreReviewEvents.emit(event);
    }
  }

  generatelimitedAttemptEvent(event) {
    if (_.get(event, 'edata.isLastAttempt')) {
      this.selfAssessLastAttempt.emit(event);
    } else if (_.get(event, 'edata.maxLimitExceeded')) {
      this.selfAssessLastAttempt.emit(event);
    }
  }

  eventHandler(event) {
    if (event.eid === 'END') {
      const metaDataconfig = event.metaData;
      if (this.userService.loggedIn) {
        this.userService.userData$.subscribe((user: any) => {
          if (user && !user.err) {
            const userProfile = user.userProfile;
            const userId = userProfile.id;
            const varName = (userId + '_' + (this.collectionId ? this.collectionId : '') + '_' + (this.contentId ? this.contentId : '') + '_config');
            localStorage.setItem(varName, JSON.stringify(metaDataconfig));
          }
        });
      } else {
        const userId = 'guest';
        const varName = (userId + '_' + (this.collectionId ? this.collectionId : '') + '_' + (this.contentId ? this.contentId : '') + '_config');
        localStorage.setItem(varName, JSON.stringify(metaDataconfig));
      }
    }
    if (event.eid === 'exdata') {
      this.generatelimitedAttemptEvent(event);
      return;
    }
    if (_.get(event, 'edata.type') === 'SHARE') {
      this.contentUtilsServiceService.contentShareEvent.emit('open');
      this.mobileViewDisplay = 'none';
    }
    if (_.get(event, 'edata.type') === 'PRINT') {
      const windowFrame = window.document.querySelector('pdf-viewer iframe');
      if (windowFrame) {
        windowFrame['contentWindow'].print();
      }
      this.mobileViewDisplay = 'none';
    }
  }

  generateContentReadEvent(event: any, newPlayerEvent?) {
    let eventCopy = newPlayerEvent ? _.cloneDeep(event) : event;
    if (!eventCopy) {
      return;
    }
    if (newPlayerEvent) {
      eventCopy = { detail: {telemetryData: eventCopy}};
    }
    const eid = _.get(eventCopy, 'detail.telemetryData.eid');
    const contentId = _.get(eventCopy, 'detail.telemetryData.object.id');
    // this.contentId = contentId;
    if (eid && (eid === 'START' || eid === 'END') && contentId === _.get(this.playerConfig, 'metadata.identifier')) {
      this.showRatingPopup(eventCopy);
      if (this.contentProgressEvents$) {
        this.contentProgressEvents$.next(eventCopy);
      }
    } else if (eid && (eid === 'IMPRESSION')) {
      this.emitSceneChangeEvent();
    }
    if (eid && (eid === 'ASSESS') || eid === 'START' || eid === 'END') {
      this.assessmentEvents.emit(eventCopy);
    }

    if (_.get(this.playerConfig, 'metadata.mimeType') === this.configService.appConfig.PLAYER_CONFIG.MIME_TYPE.questionset && eid === 'END') {
      this.questionScoreSubmitEvents.emit(event);
    }
  }
  emitSceneChangeEvent(timer = 0) {
    setTimeout(() => {
      if (_.get(this, 'contentIframe.nativeElement')) {
        const stageId = this.contentIframe.nativeElement.contentWindow.EkstepRendererAPI.getCurrentStageId();
        const eventData = { stageId };
        this.sceneChangeEvent.emit(eventData);
      }
    }, timer); // waiting for player to load, then fetching stageId (if we dont wait stageId will be undefined)
  }

  showRatingPopup(event) {
    let contentProgress;
    const playerSummary: Array<any> = _.get(event, 'detail.telemetryData.edata.summary');
    if (playerSummary) {
      const contentMimeType = this.playerConfig.metadata.mimeType;
      contentProgress = CsContentProgressCalculator.calculate(playerSummary, contentMimeType);
    }
    if (event.detail.telemetryData.eid === 'END' && contentProgress === 100) {
      this.contentRatingModal = !this.isFullScreenView;
      this.showRatingModalAfterClose = true;
      if (this.modal) {
        this.modal.showContentRatingModal = true;
      }
    }
  }

  /**
   * this method will handle play button click and turn the player into landscape
   */
  enablePlayer(mode: boolean) {
    this.showPlayIcon = mode;
    this.loadPlayer();
  }

  /** this method checks for the browser capability to be fullscreen via if-else ladder
   * if match found, it will turn the player along will be close button into fullscreen and then
   * rotate it to landscape mode
   */
  rotatePlayer() {
    setTimeout(() => {
      const playVideo: any = document.querySelector('#playerFullscreen');
      try {
        if (playVideo.requestFullscreen) {
          playVideo.requestFullscreen();
        } else if (playVideo.mozRequestFullScreen) { /* Firefox */
          playVideo.mozRequestFullScreen();
        } else if (playVideo.webkitRequestFullscreen) { /* Chrome, Safari and Opera */
          playVideo.webkitRequestFullscreen();
        } else if (playVideo.msRequestFullscreen) { /* IE/Edge */
          playVideo.msRequestFullscreen();
        }
        screen.orientation.lock('landscape');
      } catch (error) {}
    });
  }

  /** when user clicks on close button
   * this method will let the player to exit from fullscreen mode and
   * 1. video thumbnail will be shown for single content
   * 2. content-details page will be shown ( for multi-result dial-code search flow)
   */
  closeFullscreen() {
    /** to exit the fullscreen mode */
    if (document['exitFullscreen']) {
      document['exitFullscreen']();
    } else if (document['mozCancelFullScreen']) { /* Firefox */
      document['mozCancelFullScreen']();
    } else if (document['webkitExitFullscreen']) { /* Chrome, Safari and Opera */
      document['webkitExitFullscreen']();
    } else if (document['msExitFullscreen']) { /* IE/Edge */
      document['msExitFullscreen']();
    }

    if (this.showRatingModalAfterClose) {
      this.contentRatingModal = true;
      if (this.modal) {
        this.modal.showContentRatingModal = true;
      }
    }
     /** to change the view of the content-details page */
    this.showPlayIcon = true;
    this.closePlayerEvent.emit();
  }

  setTelemetryData() {
    this.closeButtonInteractEdata = {
      id: 'player-close-button',
      type: 'click',
      pageid: this.pageId
    };

    this.loadPlayerInteractEdata = {
      id: 'play-button',
      type: 'click',
      pageid: this.pageId
    };
  }

  closeContentFullScreen() {
    this.navigationHelperService.emitFullScreenEvent(false);
    this.loadPlayer();
  }

  closeModal() {
    this.focusOnReplay();
    this.ratingPopupClose.emit({});
  }
  
  focusOnReplay() {
    if (this.playerType === 'quml-player') {
      const replayButton: HTMLElement = document.querySelector('.replay-section');
      if (replayButton) {
        replayButton.focus();
      }
    }
  }
  
  public addUserDataToContext() {
    if (this.userService.loggedIn) {
      this.userService.userData$.subscribe((user: any) => {
        if (user && !user.err) {
          const userProfile = user.userProfile;
          this.playerConfig.context['userData'] = {
            firstName: userProfile.firstName ? userProfile.firstName : 'Guest',
            lastName: userProfile.lastName ? userProfile.lastName : ''
          };
        }
      });
    } else {
      this.playerConfig.context.userData = {
        firstName: this.userService.guestUserProfile.formatedName || 'Guest',
        lastName: ''
      };
    }
  }

  ngOnDestroy() {
    const playerElement = _.get(this.contentIframe, 'nativeElement');
    if (playerElement) {
      if (_.get(playerElement, 'contentWindow.telemetry_web.tList.length')) {
        const request = {
          url: this.configService.urlConFig.URLS.TELEMETRY.SYNC,
          data: {
            'id': 'api.sunbird.telemetry',
            'ver': '3.0',
            'events': playerElement.contentWindow.telemetry_web.tList.map(item => JSON.parse(item))
          }
        };
        this.contentService.post(request).subscribe();
      }
      playerElement.remove();
    }
    this.unsubscribe.next();
    this.unsubscribe.complete();
  }
}
<!-- Mobile browser player-->
<div *ngIf="isMobileOrTab && !showNewPlayer" >
    <div data-ratio="16:9" class="player-thumbnail" appTelemetryInteract [telemetryInteractObject]="telemetryObject" [telemetryInteractEdata]="loadPlayerInteractEdata"
    [ngStyle]="{'background': 'url(' + playerOverlayImage + ') center/cover no-repeat '}" *ngIf="showPlayIcon" id="contentPlayer" tabindex="0" (click)="enablePlayer(false)">
    <img class="play-icon" src="assets/images/play_circle.svg">
  </div>
  <div id="playerFullscreen" *ngIf="!showPlayIcon" > 
    <!-- <img appTelemetryInteract [telemetryInteractObject]="telemetryInteractObject" [telemetryInteractEdata]="closeButtonInteractEdata" (click)="closeFullscreen()" class="close-button" src="assets/images/close-Black.svg" alt=""> -->
    <iframe #contentIframe id="contentPlayer" title="Content Player" aria-label="Content Player" class="contentViewerIframeShadow" name="contentPlayer"></iframe>
  </div>
</div>
<!-- Portal player-->
<div class="h-100" *ngIf="!isMobileOrTab && !showNewPlayer && !isContentDeleted">
    <iframe #contentIframe id="contentPlayer" title="Content Player" aria-label="Content Player" class="contentViewerIframeShadow" [ngClass]="{'player-fullscreen': isFullScreenView}" name="contentPlayer"></iframe>
</div>
<div *ngIf="!isMobileOrTab && showNewPlayer && !isContentDeleted" class="w-100 h-100">
        <div class="contentViewerIframeShadow" [ngClass]="{'player-fullscreen content-full-video': isFullScreenView}">
        <sunbird-pdf-player *ngIf="playerType === 'pdf-player'" [playerConfig]="playerConfig"
          (playerEvent)="eventHandler($event)" (telemetryEvent)="generateContentReadEvent($event, true)">
        </sunbird-pdf-player>

        <sunbird-video-player *ngIf="playerType === 'video-player'" [playerConfig]="playerConfig"
          (playerEvent)="eventHandler($event)" (telemetryEvent)="generateContentReadEvent($event, true)">
        </sunbird-video-player>

        <sunbird-epub-player *ngIf="playerType === 'epub-player'" [playerConfig]="playerConfig" [showFullScreen]="isFullScreenView"
        (playerEvent)="eventHandler($event)" (telemetryEvent)="generateContentReadEvent($event, true)"></sunbird-epub-player>

        <quml-main-player *ngIf="playerType === 'quml-player' && showQumlPlayer" [playerConfig]="playerConfig" (playerEvent)="eventHandler($event)" (telemetryEvent)="generateContentReadEvent($event, true)"></quml-main-player>
      </div>
</div>

<!--If Content is deleted-->
<div class="d-flex flex-dc flex-jc-center text-center flex-ai-center no-content-player" *ngIf="isContentDeleted">
  <div class="no-content-player__text"></div>
  <div>
    <img src="assets/images/shape.svg" width="90px" height="70px">
  </div>
  <div class="fnormal">{{resourceService?.messages?.stmsg?.desktop?.deleteMessage}}</div>
</div>

<div *ngIf="isMobileOrTab && showNewPlayer" class="w-100 h-100">
  <div data-ratio="16:9" class="player-thumbnail" appTelemetryInteract [telemetryInteractObject]="telemetryObject" [telemetryInteractEdata]="loadPlayerInteractEdata"
  [ngStyle]="{'background': 'url(' + playerOverlayImage + ') center/cover no-repeat '}" *ngIf="showPlayIcon" id="contentPlayer" tabindex="0" (click)="enablePlayer(false)">
  <img class="play-icon" src="assets/images/play_circle.svg">
</div>

<div id="playerFullscreen" *ngIf="!showPlayIcon" class="player-fullscreen" [ngStyle]="{'display': mobileViewDisplay}"> 
  <!-- <img *ngIf="playerType !== 'quml-player'" appTelemetryInteract [telemetryInteractObject]="telemetryInteractObject" [telemetryInteractEdata]="closeButtonInteractEdata" (click)="closeFullscreen()" class="close-button" src="assets/images/close-Black.svg" alt=""> -->
  <sunbird-pdf-player *ngIf="playerType === 'pdf-player'" [playerConfig]="playerConfig"
    (playerEvent)="eventHandler($event)" (telemetryEvent)="generateContentReadEvent($event, true)"></sunbird-pdf-player>

  <sunbird-video-player *ngIf="playerType === 'video-player'" [playerConfig]="playerConfig"
    (playerEvent)="eventHandler($event)" (telemetryEvent)="generateContentReadEvent($event, true)">
  </sunbird-video-player>
  <sunbird-epub-player *ngIf="playerType === 'epub-player'" [playerConfig]="playerConfig" [showFullScreen]="isFullScreenView"
    (playerEvent)="eventHandler($event)" (telemetryEvent)="generateContentReadEvent($event, true)"></sunbird-epub-player>

    <quml-main-player *ngIf="playerType === 'quml-player' && showQumlPlayer" [playerConfig]="playerConfig" (playerEvent)="eventHandler($event)" (telemetryEvent)="generateContentReadEvent($event, true)"></quml-main-player>
</div>
</div>

    <!--Rating popup -->
<app-content-rating #modal *ngIf="contentRatingModal && playerConfig"
    [contentData]="playerConfig.metadata" (closeModal)="closeModal()"></app-content-rating>
<button *ngIf="playerType !== 'quml-player'" class="sb-btn sb-btn-primary sb-btn-normal pull-right view-fullscreen"[ngClass]="{'d-none': !viewFullscreenBtn}" tabindex="0" (click)="viewInFullscreen()" appTelemetryInteract [telemetryInteractEdata]="viewFullScreenIntractEdata" [telemetryInteractObject]="viewFullScreenIntractObject"> <i class="expand icon"></i> View Full Screen</button>

./player.component.scss

@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;
@use 'components/video' as *;

.player-thumbnail {
  width: 100%;
  cursor: pointer;
  border-radius: .3125rem;
  position: relative;
  padding-bottom: 56.25%;
  border: calculateRem(1px) solid var(--black);
}

.play-icon {
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  left: 50%;
  height: calculateRem(80px);
  width: calculateRem(80px)
}

.overlay-image {
  width: 100%;
  height: 100%;
}

@media only screen and (max-width: 768px) {
  .play-icon {
    height: auto;
    width: auto;
  }
}


  .content-full-video{
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: calculateRem(50px);
    z-index: 999999;
    align-items: center;
    .video-close-btn{
        position: fixed;
        right: calculateRem(32px);
        left: auto;
        cursor: pointer;
        background: var(--black);
        height: calculateRem(32px);
        width: calculateRem(32px);
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        svg{
            width: calculateRem(16px);
            height: calculateRem(16px);
        }
        html[dir="rtl"] & {
            left: calculateRem(32px);
            right: auto;
        }
    }
}

.player-fullscreen {
    position:fixed !important;
    border:none; 
    margin:0;
    padding:0; 
    overflow:hidden; 
    z-index:9999;
    // height: calc(100% - 4rem) !important;
    background:var(--white);
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    border: none;
} 

.contentViewerIframeShadow {
  width: 100%;
  border: 0;
  height: 100%;
  left:50%;
  top:50%;
  right:50%;
  bottom:50%;
  transform: translate(-50%, -50%);
  position: absolute;
  transition: all ease .3s;
  iframe {
    height: calc(100vh - 4rem) !important;
    border:calculateRem(10px) solid var(--primary-400);
  }
} 

.close-button {
  position: absolute;
  z-index: 100;
  right: calculateRem(8px);
  top: calculateRem(8px);
  cursor: pointer;
}

::ng-deep{
  iframe {
    width: 100%;
    height: 100% !important;
  }
  .video-js{height:100% !important;}

  .video-js {
    padding-top:inherit !important;
  }
}

.no-content-player{
  background: var(--black);
  color: var(--white);
  width: 100%;
  height: 100%;
  &__text{
      max-width: calculateRem(300px);   
  }
}

Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""