File

src/app/modules/workspace/components/content-editors/generic-editor/generic-editor.component.ts

Description

Component Launches the Generic Editor in a IFrame Modal

Implements

OnInit OnDestroy

Metadata

Index

Properties
Methods

Constructor

constructor(userService: UserService, _zone: NgZone, activatedRoute: ActivatedRoute, tenantService: TenantService, telemetryService: TelemetryService, router: Router, navigationHelperService: NavigationHelperService, workspaceService: WorkSpaceService, configService: ConfigService, editorService: EditorService, toasterService: ToasterService, resourceService: ResourceService, frameworkService: FrameworkService)
Parameters :
Name Type Optional
userService UserService No
_zone NgZone No
activatedRoute ActivatedRoute No
tenantService TenantService No
telemetryService TelemetryService No
router Router No
navigationHelperService NavigationHelperService No
workspaceService WorkSpaceService No
configService ConfigService No
editorService EditorService No
toasterService ToasterService No
resourceService ResourceService No
frameworkService FrameworkService No

Methods

closeModal
closeModal()

Re directed to the workspace on close of modal

Returns : void
Private disableBrowserBackButton
disableBrowserBackButton()
Returns : void
Private generateInteractEvent
generateInteractEvent(intractEdata)
Parameters :
Name Optional
intractEdata No
Returns : void
Private getContentDetails
getContentDetails()
Returns : any
Private getDetails
getDetails()
Returns : any
Private initEditor
initEditor()

Launch Generic Editor in the modal

Returns : void
Private lockContent
lockContent()
Returns : any
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
redirectToWorkSpace
redirectToWorkSpace()
Returns : void
retireLock
retireLock()
Returns : void
Private setWindowConfig
setWindowConfig()
Returns : void
Private setWindowContext
setWindowContext()
Returns : void
Private validateRequest
validateRequest()

checks the permission using state, status and userId

Returns : boolean

Properties

Public _zone
Type : NgZone
Private browserBackEventSub
Private buildNumber
Type : string
Public contentDetails
Type : any
Public defaultContentFileSize
Type : any
Private deviceId
Type : string
Public extContWhitelistedDomains
Type : string
genericEditorURL
Type : string
Default value : (<HTMLInputElement>document.getElementById('genericEditorURL')) ? (<HTMLInputElement>document.getElementById('genericEditorURL')).value : ''
Public isLargeFileUpload
Default value : false
Public logo
Type : string
Public ownershipType
Type : Array<string>
Private portalVersion
Type : string
Public queryParams
Type : object
Private routeParams
Type : any
Public showLoader
Default value : true
Private userProfile
Type : IUserProfile
Public videoMaxSize
Type : any
Public workspaceService
Type : WorkSpaceService
import { Component, OnInit, NgZone, OnDestroy } from '@angular/core';
import * as  iziModal from 'izimodal/js/iziModal';
import { NavigationHelperService, ResourceService, ToasterService, ConfigService, IUserProfile, ServerResponse } from '@sunbird/shared';
import { TelemetryService, IInteractEventEdata } from '@sunbird/telemetry';
import { combineLatest, of, throwError } from 'rxjs';
import { UserService, TenantService, FrameworkService } from '@sunbird/core';
import { ActivatedRoute, Router } from '@angular/router';
import { environment } from '@sunbird/environment';
import { EditorService, WorkSpaceService } from '../../../services';
import { tap, delay, map, first, mergeMap } from 'rxjs/operators';
import * as _ from 'lodash-es';
jQuery.fn.iziModal = iziModal;

/**
 * Component Launches the Generic Editor in a IFrame Modal
 */@Component({
  selector: 'app-generic-editor',
  templateUrl: './generic-editor.component.html'
})
export class GenericEditorComponent implements OnInit, OnDestroy {

  private userProfile: IUserProfile;
  private routeParams: any;
  private buildNumber: string;
  private deviceId: string;
  private portalVersion: string;
  public logo: string;
  public showLoader = true;
  private browserBackEventSub;
  public extContWhitelistedDomains: string;
  public ownershipType: Array<string>;
  public queryParams: object;
  public contentDetails: any;
  public videoMaxSize: any;
  public defaultContentFileSize: any;
  public isLargeFileUpload = false;
  genericEditorURL: string = (<HTMLInputElement>document.getElementById('genericEditorURL')) ?
  (<HTMLInputElement>document.getElementById('genericEditorURL')).value : '';

  constructor(private userService: UserService, public _zone: NgZone, private activatedRoute: ActivatedRoute,
    private tenantService: TenantService, private telemetryService: TelemetryService, private router: Router,
    private navigationHelperService: NavigationHelperService, public workspaceService: WorkSpaceService,
    private configService: ConfigService, private editorService: EditorService, private toasterService: ToasterService,
    private resourceService: ResourceService, private frameworkService: FrameworkService) {
    const buildNumber = (<HTMLInputElement>document.getElementById('buildNumber'));
    this.buildNumber = buildNumber ? buildNumber.value : '1.0';
    const deviceId = (<HTMLInputElement>document.getElementById('deviceId'));
    this.deviceId = deviceId ? deviceId.value : '';
    this.portalVersion = buildNumber && buildNumber.value ? buildNumber.value.slice(0, buildNumber.value.lastIndexOf('.')) : '1.0';
    this.extContWhitelistedDomains = (<HTMLInputElement>document.getElementById('extContWhitelistedDomains')) ?
      (<HTMLInputElement>document.getElementById('extContWhitelistedDomains')).value : 'youtube.com,youtu.be';
    this.videoMaxSize = (<HTMLInputElement>document.getElementById('videoMaxSize')) ?
      (<HTMLInputElement>document.getElementById('videoMaxSize')).value : '100';
      this.defaultContentFileSize = (<HTMLInputElement>document.getElementById('sunbirdDefaultFileSize')) ?
      (<HTMLInputElement>document.getElementById('sunbirdDefaultFileSize')).value : 150;
  }
  ngOnInit() {
    this.userProfile = this.userService.userProfile;
    this.routeParams = this.activatedRoute.snapshot.params;
    this.queryParams = this.activatedRoute.snapshot.queryParams;
    this.isLargeFileUpload = _.get(this.activatedRoute, 'snapshot.data.isLargeFileUpload');
    this.disableBrowserBackButton();
    this.getDetails().pipe(first(),
      tap(data => {
        if (data.tenantDetails) {
          this.logo = data.tenantDetails.logo;
        }
        this.ownershipType = data.ownershipType;
        this.showLoader = false;
        this.initEditor();
        this.setWindowContext();
        this.setWindowConfig();
      }),
      delay(10)) // wait for iziModal lo load
      .subscribe((data) => {
        jQuery('#genericEditor').iziModal('open');
      },
        (error) => {
          if (error === 'NO_PERMISSION') {
            this.toasterService.error(this.resourceService.messages.emsg.m0013);
          } else if (['RESOURCE_SELF_LOCKED', 'RESOURCE_LOCKED'].includes(_.get(error, 'error.params.err'))) {
            this.toasterService.error(_.replace(error.error.params.errmsg, 'resource', 'content'));
          } else {
            this.toasterService.error(this.resourceService.messages.emsg.m0004);
          }
          this.closeModal();
        }
      );
  }
  private getDetails() {
    const lockInfo = _.pick(this.queryParams, 'lockKey', 'expiresAt', 'expiresIn');
    const allowedEditState = ['draft', 'allcontent', 'collaborating-on', 'uploaded'].includes(this.routeParams.state);
    const allowedEditStatus = this.routeParams.contentStatus ? ['draft'].includes(this.routeParams.contentStatus.toLowerCase()) : false;
    if (_.isEmpty(lockInfo) && allowedEditState && allowedEditStatus) {
      return combineLatest(this.tenantService.tenantData$, this.getContentDetails(),
      this.editorService.getOwnershipType(), this.lockContent(), this.userService.userOrgDetails$).
      pipe(map(data => ({ tenantDetails: data[0].tenantData,
        collectionDetails: data[1], ownershipType: data[2] })));
    } else {
      return combineLatest(this.tenantService.tenantData$, this.getContentDetails(),
      this.editorService.getOwnershipType(), this.userService.userOrgDetails$).
      pipe(map(data => ({ tenantDetails: data[0].tenantData,
        collectionDetails: data[1], ownershipType: data[2] })));
    }
  }
  private lockContent () {
    const contentInfo = {
      contentType: this.routeParams.type,
      framework: this.routeParams.framework,
      identifier: this.routeParams.contentId
    };
    const input = {
      resourceId : contentInfo.identifier,
      resourceType : 'Content',
      resourceInfo : JSON.stringify(contentInfo),
      creatorInfo : JSON.stringify({'name': this.userService.userProfile.firstName, 'id': this.userService.userProfile.id}),
      createdBy : this.userService.userProfile.id
    };
    return this.workspaceService.lockContent(input).pipe(tap((data) => {
      this.queryParams = data.result;
      this.router.navigate([], {relativeTo: this.activatedRoute, queryParams: data.result});
    }));
  }
  private getContentDetails() {
    if (this.routeParams.contentId) {
      const options: any = { params: { mode: 'edit' } };
      return this.editorService.getContent(this.routeParams.contentId, options).
        pipe(mergeMap((data) => {
          this.contentDetails = data.result.content;
          if (this.validateRequest()) {
            return of(data);
          } else {
            return throwError('NO_PERMISSION');
          }
        }));
    } else {
      return of({});
    }
  }

  /**
   * checks the permission using state, status and userId
   */
  private validateRequest() {
    const validStatus = _.indexOf(this.configService.editorConfig.GENERIC_EDITOR.contentStatus, this.contentDetails.status) > -1;
    const validState = _.indexOf(this.configService.editorConfig.GENERIC_EDITOR.contentState, this.routeParams.state) > -1;
    if (_.indexOf(this.configService.appConfig.PLAYER_CONFIG.MIME_TYPE.genericMimeType, this.contentDetails.mimeType) > -1 && validStatus) {
      if (validState && this.contentDetails.createdBy !== this.userService.userid) {
        return true;
      } else if (validState && this.contentDetails.createdBy === this.userService.userid) {
        return true;
      } else if (validState && _.includes(this.contentDetails.collaborators, this.userService.userid)) {
        return true;
      } else if (this.contentDetails.createdBy === this.userService.userid) {
        return true;
      }
      return false;
    }
    return false;
  }

  /**
   *Launch Generic Editor in the modal
   */
  private initEditor() {
    jQuery('#genericEditor').iziModal({
      title: '',
      iframe: true,
      iframeURL: this.genericEditorURL + '?' + this.buildNumber,
      navigateArrows: false,
      fullscreen: true,
      openFullscreen: true,
      closeOnEscape: true,
      overlayClose: false,
      overlay: false,
      overlayColor: '',
      history: false,
      closeButton: true,
      onClosing: () => {
        this._zone.run(() => {
          this.closeModal();
        });
      }
    });
  }
  private setWindowContext() {
    window.context = {
      user: {
        id: this.userService.userid,
        name : !_.isEmpty(this.userProfile.lastName) ? this.userProfile.firstName + ' ' + this.userProfile.lastName :
        this.userProfile.firstName,
        orgIds: this.userProfile.organisationIds,
        organisations: this.userService.orgIdNameMap
      },
      did: this.deviceId,
      sid: this.userService.sessionId,
      contentId: this.routeParams.contentId,
      pdata: {
        id: this.userService.appId,
        ver: this.portalVersion,
        pid: 'sunbird-portal'
      },
      contextRollUp: this.telemetryService.getRollUpData(this.userProfile.organisationIds),
      tags: this.userService.dims,
      channel: this.userService.channel,
      defaultLicense: this.frameworkService.getDefaultLicense(),
      env: 'generic-editor',
      framework: this.routeParams.framework,
      ownershipType: this.ownershipType,
      timeDiff: this.userService.getServerTimeDiff,
      primaryCategories: _.without(this.frameworkService['_channelData'].contentPrimaryCategories, 'Course Assessment')
    };
    if (this.isLargeFileUpload || (_.get(this.contentDetails, 'contentDisposition') === 'online-only')) {
      window.context['uploadInfo'] = {
        isLargeFileUpload: true
      };
    }
  }
  private setWindowConfig() {
    window.config = _.cloneDeep(this.configService.editorConfig.GENERIC_EDITOR.WINDOW_CONFIG); // cloneDeep to preserve default config
    window.config.build_number = this.buildNumber;
    window.config.headerLogo = this.logo;
    window.config.lock = _.pick(this.queryParams, 'lockKey', 'expiresAt', 'expiresIn');
    window.config.extContWhitelistedDomains = this.extContWhitelistedDomains;
    window.config.enableTelemetryValidation = environment.enableTelemetryValidation; // telemetry validation
    window.config.videoMaxSize = this.videoMaxSize;
    window.config.defaultContentFileSize = this.defaultContentFileSize; // making configurable upload limit in workspace for content upload
  }
  /**
  * Re directed to the workspace on close of modal
  */
  closeModal() {
    this.showLoader = true;
    if (document.getElementById('genericEditor')) {
      document.getElementById('genericEditor').remove();
    }
    const isContentStatus = _.get(this.routeParams, 'contentStatus');
    if ((isContentStatus && isContentStatus.toLowerCase() === 'draft') ||
  (window.context && window.context.contentId && !isContentStatus)) {
      this.retireLock();
    } else {
      this.redirectToWorkSpace();
    }
  }

  retireLock () {
    const inputData = {'resourceId': window.context.contentId || this.routeParams.contentId, 'resourceType': 'Content'};
    this.workspaceService.retireLock(inputData).subscribe(
      (data: ServerResponse) => {
        this.redirectToWorkSpace();
      },
      (err: ServerResponse) => {
        this.redirectToWorkSpace();
      }
    );
  }

  redirectToWorkSpace () {
    if (this.routeParams.state === 'collaborating-on') {
      this.navigationHelperService.navigateToWorkSpace('/workspace/content/collaborating-on/1');
    } else {
      this.navigationHelperService.navigateToWorkSpace('/workspace/content/draft/1');
    }
  }

  private disableBrowserBackButton() {
    sessionStorage.setItem('inEditor', 'true');
    window.location.hash = 'no';
    this.workspaceService.toggleWarning(this.routeParams.type);
    this.browserBackEventSub = this.workspaceService.browserBackEvent.subscribe(() => {
      const closeEditorIntractEdata: IInteractEventEdata = {
        id: 'browser-back-button',
        type: 'click',
        pageid: 'generic-editor'
      };
      this.generateInteractEvent(closeEditorIntractEdata);
    });
  }
  private generateInteractEvent(intractEdata) {
    if (intractEdata) {
      const appTelemetryInteractData: any = {
        context: {
          env: 'generic-editor'
        },
        edata: intractEdata
      };
      if (this.routeParams.contentId) {
        appTelemetryInteractData.object = {
          id: this.routeParams.contentId,
          type: 'content',
          ver: '1.0'
        };
      }
      this.telemetryService.interact(appTelemetryInteractData);
    }
  }
  ngOnDestroy() {
    if (document.getElementById('genericEditor')) {
      document.getElementById('genericEditor').remove();
    }
    if (this.browserBackEventSub) {
      this.browserBackEventSub.unsubscribe();
    }
    sessionStorage.setItem('inEditor', 'false');
    this.workspaceService.toggleWarning();
    const removeIzi = document.querySelector('.iziModal-isAttached');
    if (removeIzi) {
      removeIzi.classList.remove('iziModal-isAttached');
    }
  }
}
<div id="genericEditor"></div>
<sui-dimmer class="page" *ngIf="showLoader" [isDimmed]="showLoader">
  <div class="ui text loader"><h2>Loading...</h2></div>
</sui-dimmer>
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""