import { Component , ElementRef , Injectable , NgZone , OnDestroy , OnInit , ViewChild } from '@angular/core' ; import { ActivatedRoute } from '@angular/router' ; import * as CodeMirror from 'codemirror' ; import 'codemirror/mode/gfm/gfm' ; import 'codemirror/mode/javascript/javascript' ; import { Subscription } from 'rxjs' ; import { MediaObserver } from '@angular/flex-layout' ; import { Author } from '../core/Author' ; import { Doc } from '../core/Doc' ; import { UiService } from '../core/ui' ; import { CONTROLS } from './controls/controls' ; import { HistoryService , IDelete , IInsert } from './history.service' ; import { TimelineComponent } from './timeline/timeline.component' ; @ Component ( { selector : 'mute-history' , templateUrl : './history.component.html' , styleUrls : [ './history.component.scss' ] , } ) @ Injectable ( ) export class HistoryComponent implements OnInit , OnDestroy { private operations : ( IDelete | IInsert ) [ ] ; private subscriptions : Subscription [ ] ; public docAuthors : Author [ ] ; @ ViewChild ( 'editorElt' , { static : true } ) editorElt : ElementRef ; @ ViewChild ( TimelineComponent , { static : true } ) timelineComponent : TimelineComponent ; @ ViewChild ( 'sidenavElm' , { static : true } ) sidenavElm ; @ ViewChild ( 'leftSidenavElm' , { static : true } ) leftSidenavElm ; @ ViewChild ( 'rightSidenavElm' , { static : true } ) rightSidenavElm ; public editor : CodeMirror . Editor ; public currentOp : number ; public doc : Doc ; public step : number ; public rightSideNavMode = 'side' ; constructor ( private zone , private route , private history , public ui , public media ) { this . step = 1 ; this . subscriptions = [ ] ; } ngOnInit ( ) { this . subscriptions . push ( this . route . data . subscribe ( ( { doc } ) => { this . doc = doc ; this . history . getAuthors ( this . doc ) . then ( ( docAuths ) => { this . docAuthors = docAuths ; } ) ; this . history . getOperations ( this . doc ) . then ( ( ops ) => { this . operations = ops ; this . showVersion ( this . operations . length ) ; } ) ; this . subscriptions . push ( this . ui . onNavToggle . subscribe ( ( ) => { this . leftSidenavElm . opened = ! this . leftSidenavElm . opened ; } ) ) ; this . subscriptions . push ( this . ui . onDocNavToggle . subscribe ( ( ) => { this . rightSidenavElm . opened = ! this . rightSidenavElm . opened ; } ) ) ; this . currentOp = 0 ; } ) ) ; this . zone . runOutsideAngular ( ( ) => { this . editor = CodeMirror ( this . editorElt . nativeElement , { value : '' , mode : 'gfm' , readOnly : 'true' , lineWrapping : true , } ) ; } ) ; } ngOnDestroy ( ) { this . subscriptions . forEach ( ( sub ) => sub . unsubscribe ( ) ) ; } /**
     * numOperations corresponds to a numero between
     * 1 and countOperation().
     */ showVersion ( numOperation ) { } generateText ( beginOp , endOp ) { const textContent = '' ; return textContent ; } destroyText ( begin , end ) { const doc = this . editor . getDoc ( ) ; const pos1 = doc . posFromIndex ( begin ) ; const pos2 = doc . posFromIndex ( end + 1 ) ; doc . markText ( { line : pos1 . line , ch : pos1 . ch } , { line : pos2 . line , ch : pos2 . ch } , { css : 'background-color: red' } ) ; doc . markText ( { line : pos1 . line , ch : pos1 . ch } , { line : pos2 . line , ch : pos2 . ch } , { css : 'animation-name: slideout;' + 'animation-duration: 0.5s;' , } ) ; } countOperations ( ) { return this . operations ? this . operations . length : 0 ; } countMax ( ) { if ( this . countOperations ( ) === 0 ) { return 0 ; } return Math . floor ( this . countOperations ( ) / 2 ) ; } onInputChange ( event ) { let indexOp = event . target . value ; indexOp = indexOp >= this . countOperations ( ) ? this . countOperations ( ) : indexOp ; indexOp = indexOp <= 0 ? 1 : indexOp ; this . showVersion ( indexOp ) ; } colorizeAuthors ( begin , end ) { const doc = this . editor . getDoc ( ) ; const pos1 = doc . posFromIndex ( begin ) ; const pos2 = doc . posFromIndex ( end ) ; if ( this . docAuthors ) { length = this . docAuthors . length ; } this . animateText ( begin , end ) ; const color = this . docAuthors [ Math . floor ( Math . random ( ) * 10 ) % length ] . getColor ( ) ; doc . markText ( { line : pos1 . line , ch : pos1 . ch } , { line : pos2 . line , ch : pos2 . ch } , { css : 'background-color: ' + color } ) ; } colorizeDifferences ( begin , end , reverse ) { const doc = this . editor . getDoc ( ) ; const pos1 = doc . posFromIndex ( begin ) ; const pos2 = doc . posFromIndex ( end ) ; this . animateText ( begin , end ) ; if ( ! reverse ) { doc . markText ( { line : pos1 . line , ch : pos1 . ch } , { line : pos2 . line , ch : pos2 . ch } , { css : 'background-color: #4CAF50' } ) ; } else { doc . markText ( { line : pos1 . line , ch : pos1 . ch } , { line : pos2 . line , ch : pos2 . ch } , { css : 'background-color: #E57373' } ) ; } } animateText ( begin , end ) { const doc = this . editor . getDoc ( ) ; const pos1 = doc . posFromIndex ( begin ) ; const pos2 = doc . posFromIndex ( end ) ; doc . markText ( { line : pos1 . line , ch : pos1 . ch } , { line : pos2 . line , ch : pos2 . ch } , { css : 'animation-name: slidein;' + 'animation-duration: 0.300s;' , } ) ; } onControlsChange ( controlType ) { switch ( controlType ) { case CONTROLS . PLAY : this . timelineComponent . play ( ) ; break ; case CONTROLS . PAUSE : this . timelineComponent . pause ( ) ; break ; case CONTROLS . FAST_FORWARD : this . timelineComponent . goToEnd ( ) ; break ; case CONTROLS . FAST_REWIND : this . timelineComponent . goToBegin ( ) ; break ; } } onToggle ( ) { this . showVersion ( this . currentOp ) ; } updateStep ( step ) { this . step = step <= 0 ? 1 : step ; } }