class Popup { public _debug : boolean = false ; public profiles : NZBUnityProfileDictionary ; public profileCurrent : JQuery < HTMLElement > ; public btnRefresh : JQuery < HTMLElement > ; public btnServer : JQuery < HTMLElement > ; public btnOptions : JQuery < HTMLElement > ; public errorVal : JQuery < HTMLElement > ; public statusVal : JQuery < HTMLElement > ; public speedVal : JQuery < HTMLElement > ; public maxSpeedVal : JQuery < HTMLElement > ; public sizeVal : JQuery < HTMLElement > ; public timeVal : JQuery < HTMLElement > ; public queue : JQuery < HTMLElement > ; public debugContainer : JQuery < HTMLElement > ; public queuePause : JQuery < HTMLElement > ; public overrideCategory : JQuery < HTMLElement > ; public maxSpeed : JQuery < HTMLElement > ; public messages = { queueEmpty : '<div id="queueEmpty" class="empty">Queue empty, add some NZBs!</div>' , noProfiles : '<div id="noProfiles" class="empty">No server profile, click the gear to get started! <i class="fa fa-arrow-down"></i></div>' , } ; constructor ( ) { this . profileCurrent = $ ( '#ProfileCurrent' ) ; this . btnRefresh = $ ( '#btn-refresh' ) ; this . btnServer = $ ( '#btn-server' ) ; this . btnOptions = $ ( '#btn-options' ) ; this . errorVal = $ ( '#errors' ) ; this . statusVal = $ ( '#statusVal' ) ; this . speedVal = $ ( '#speedVal' ) ; this . maxSpeedVal = $ ( '#maxSpeedVal' ) ; this . sizeVal = $ ( '#sizeleftVal' ) ; this . timeVal = $ ( '#timeleftVal' ) ; this . queue = $ ( '#queue' ) ; this . debugContainer = $ ( '#debug' ) ; this . queuePause = $ ( '#QueuePause' ) ; this . overrideCategory = $ ( '#OverrideCategory' ) ; this . maxSpeed = $ ( '#MaxSpeed' ) ; $ ( '#Version' ) . text ( `v${ chrome . runtime . getManifest ( ) . version }` ) ; Util . storage . get ( null ) . then ( ( opts ) => { this . _debug = opts . Debug ; if ( this . _debug ) { this . debugContainer . show ( ) ; this . sendMessage ( 'debug' ) ; } else { this . debugContainer . hide ( ) ; } this . debug ( '[Popup.constructor] Got data!' , opts ) ; this . profiles = opts . Profiles ; if ( Object . keys ( this . profiles ) . length === 0 ) { this . queue . empty ( ) . append ( this . messages . noProfiles ) ; } this . profileCurrent . on ( 'change' , this . handleProfileSelect . bind ( this ) ) ; this . profileSelectUpdate ( ) ; this . setActiveProfile ( ) ; this . setActiveTheme ( opts . UITheme ) ; chrome . storage . onChanged . addListener ( this . handleStorageChanged . bind ( this ) ) ; this . overrideCategory . on ( 'change' , ( e ) => { Util . storage . set ( { OverrideCategory : this . overrideCategory . val ( ) } ) ; } ) ; this . maxSpeed . on ( 'change' , ( ) => { const val = this . maxSpeed . val ( ) as string ; let n = parseFloat ( val ) ; if ( n && n <= 0 ) { n = 0 ; } this . maxSpeed . val ( n || '' ) ; this . sendMessage ( 'setMaxSpeed' , n ? n * Util . Megabyte : null ) ; } ) ; this . queuePause . on ( 'click' , ( e ) => { e . preventDefault ( ) ; if ( this . queuePause . find ( '.icon-glyph' ) . hasClass ( 'fa-pause' ) ) { this . sendMessage ( 'pauseQueue' ) ; } else { this . sendMessage ( 'resumeQueue' ) ; } } ) ; this . btnRefresh . on ( 'click' , ( e ) => { e . preventDefault ( ) ; this . sendMessage ( 'refresh' ) ; } ) ; this . btnServer . on ( 'click' , ( e ) => { e . preventDefault ( ) ; this . sendMessage ( 'openProfilePage' ) ; } ) ; this . btnOptions . on ( 'click' , ( e ) => { e . preventDefault ( ) ; chrome . runtime . openOptionsPage ( ) ; } ) ; this . sendMessage ( 'refresh' ) ; } ) ; chrome . runtime . onMessage . addListener ( this . handleMessage . bind ( this ) ) ; this . sendMessage ( 'onInit' , 'Popup initialized.' ) ; } update ( queue , error = null ) { this . errorVal . empty ( ) ; if ( Object . keys ( this . profiles ) . length === 0 ) { this . queue . empty ( ) . append ( this . messages . noProfiles ) ; } else if ( queue ) { this . debug ( queue ) ; this . maxSpeed . val ( Number ( queue . maxSpeedBytes / Util . Megabyte ) . toFixed ( 1 ) ) ; this . statusVal . text ( queue . status || 'Idle' ) ; this . speedVal . text ( `${ queue . speed || '0 B/s' }` ) ; this . maxSpeedVal . text ( `(${ queue . maxSpeed || '0' })` ) ; this . sizeVal . text ( `${ queue . sizeRemaining || '0 B' } Left` ) ; this . timeVal . text ( `(${ queue . timeRemaining || '∞' })` ) ; if ( queue . status . toLowerCase ( ) === 'paused' ) { this . queuePause . find ( '.icon-glyph' ) . removeClass ( 'fa-pause' ) . addClass ( 'fa-play' ) ; } else { this . queuePause . find ( '.icon-glyph' ) . removeClass ( 'fa-play' ) . addClass ( 'fa-pause' ) ; } this . queue . empty ( ) ; if ( queue . queue . length ) { queue . queue . forEach ( ( item ) => { this . queue . append ( `
            <div class="nzb">
              <span class="name" title="${ item . name }">${ Util . trunc ( item . name , 30 ) }</span>
              <span class="category">${ item . category || '' }</span>
              <span class="size">${ item . size || '' }</span>
              <span class="bar" style="width:${ item . percentage }%;"></span>
            </div>
          ` ) ; } ) ; } else { this . queue . append ( this . messages . queueEmpty ) ; } this . overrideCategory . empty ( ) . append ( `<option val=""></option>` ) ; queue . categories . forEach ( ( k ) => { this . overrideCategory . append ( `<option value="${ k }">${ k }</option>` ) ; } ) ; Util . storage . get ( 'OverrideCategory' ) . then ( ( opts ) => { this . overrideCategory . val ( queue . categories . includes ( opts . OverrideCategory ) ? opts . OverrideCategory : '' ) ; } ) ; } if ( error ) { this . errorVal . text ( error ) ; } } sendMessage ( name , data = null ) { return Util . sendMessage ( { [ `popup.${ name }` ] : data } ) ; } handleMessage ( message , sender , sendResponse ) { if ( this . _debug ) this . debugMessage ( message ) ; for ( const k in message ) { const val = message [ k ] ; switch ( k ) { case 'main.refresh' : this . update ( val as NZBQueueResult ) ; if ( val ) { $ ( '#btn-refresh, #btn-server' ) . removeClass ( 'disabled' ) . prop ( 'disabled' , false ) ; } break ; case 'main.debug' : if ( this . _debug ) { this . debugContainer . empty ( ) ; ( val as string [ ] ) . forEach ( ( msg ) => { this . debugContainer . append ( `<div class="debug-msg">
                ${ msg . replace ( /\n/g , '<br>' ) }
              </div>` ) ; } ) ; this . debugContainer . get ( 0 ) . scrollTop = this . debugContainer . get ( 0 ) . scrollHeight ; } break ; case 'options.profileNameChanged' : if ( val . old = this . profileCurrent . val ( ) ) { this . profileSelectUpdate ( ) ; this . setActiveProfile ( val . new ) ; } break ; case 'options.profilesSaved' : this . profileSelectUpdate ( ) ; break ; } } sendResponse ( undefined ) ; return true ; } handleStorageChanged ( changes , area ) { if ( changes [ 'Profiles' ] ) { this . profiles = changes [ 'Profiles' ] . newValue ; const profilesCount = Object . keys ( this . profiles ) . length ; const oldProfiles = changes [ 'Profiles' ] . oldValue ; const oldProfilesCount = Object . keys ( oldProfiles ) . length ; if ( profilesCount !== oldProfilesCount ) { this . profileSelectUpdate ( ) ; if ( ! profilesCount ) { this . profileCurrent . val ( '' ) ; } } for ( const k in this . profiles ) { if ( this . profiles [ k ] . ProfileName !== k ) { this . profileNameChanged ( k , this . profiles [ k ] . ProfileName ) ; } } } if ( changes [ 'UITheme' ] ) { this . setActiveTheme ( changes [ 'UITheme' ] . newValue ) ; } } handleProfileSelect ( e ) { const el = $ ( e . currentTarget ) ; this . setActiveProfile ( < string > el . val ( ) ) ; } profileNameChanged ( oldName , newName ) { if ( this . profileCurrent . val ( ) === oldName ) { this . profileSelectUpdate ( ) ; this . setActiveProfile ( newName ) ; } } profileSelectUpdate ( ) { this . profileCurrent . empty ( ) ; for ( const k in this . profiles ) { this . profileCurrent . append ( `<option value="${ k }">${ k }</option>` ) ; } } setActiveProfile ( name = undefined ) { if ( name ) { if ( this . profiles [ name ] ) { this . sendMessage ( 'profileSelect' , name ) . then ( this . handleActiveProfileSet . bind ( this ) ) ; } } else { Util . storage . get ( 'ActiveProfile' ) . then ( ( opts ) => { this . sendMessage ( 'profileSelect' , opts . ActiveProfile ) . then ( this . handleActiveProfileSet . bind ( this ) ) ; } ) ; } } handleActiveProfileSet ( r ) { this . debug ( 'activeProfileSet' , r ) ; Util . storage . get ( 'ActiveProfile' ) . then ( ( opts ) => { this . profileCurrent . val ( opts . ActiveProfile ) ; this . sendMessage ( 'refresh' ) ; } ) ; } setActiveTheme ( theme = '' ) { this . debug ( 'setActiveTheme' , theme ) ; if ( theme ) { $ ( 'body' ) . removeClass ( ) . addClass ( `theme-${ theme }` ) ; } } error ( ... args ) { console . error . apply ( this , args ) ; } debug ( ... args ) { if ( this . _debug ) console . debug . apply ( this , args ) ; } debugMessage ( message ) { for ( const k in message ) { console . debug ( '[Popup.debugMessage]' , k , message [ k ] ) ; } } } let popup = new Popup ( ) ;