import { Observable , EventData } from '../observable' ; import * as types from '../../utils/types' ; export class ChangeType { static Add = 'add' ; static Delete = 'delete' ; static Update = 'update' ; static Splice = 'splice' ; static Change = 'change' ; } /**
 * Event args for "changed" event.
 */ export interface ChangedData < T > extends EventData { /**
     * Change type.
     */ action : string ; /**
     * Start index.
     */ index : number ; /**
     * Removed items.
     */ removed : Array < T > ; /**
     * Number of added items.
     */ addedCount : number ; } const CHANGE = 'change' ; /**
 * Advanced array like class used when you want to be notified when a change occurs.
 */ export class ObservableArray < T > extends Observable { /**
     * String value used when hooking to change event.
     */ public static changeEvent = CHANGE ; private _array : Array < any > ; private _addArgs : ChangedData < T > ; private _deleteArgs : ChangedData < T > ; /**
     * Create ObservableArray<T> from source Array<T>.
     */ constructor ( args ? ) { super ( ) ; if ( arguments . length === 1 && Array . isArray ( arguments [ 0 ] ) ) { this . _array = arguments [ 0 ] . slice ( ) ; } else { this . _array = Array . apply ( null , arguments ) ; } this . _addArgs = { eventName : CHANGE , object : this , action : ChangeType . Add , index : null , removed : [ ] , addedCount : 1 , } ; this . _deleteArgs = { eventName : CHANGE , object : this , action : ChangeType . Delete , index : null , removed : null , addedCount : 0 , } ; } /**
     * Returns item at specified index.
     */ getItem ( index ) { return this . _array [ index ] ; } /**
     * Sets item at specified index.
     */ setItem ( index , value ) { const oldValue = this . _array [ index ] ; this . _array [ index ] = value ; this . notify ( < ChangedData < T > > { eventName : CHANGE , object : this , action : ChangeType . Update , index : index , removed : [ oldValue ] , addedCount : 1 , } ) ; } /**
     * Gets or sets the length of the array. This is a number one higher than the highest element defined in an array.
     */ get length ( ) : number { return this . _array . length ; } set length ( value ) { if ( types . isNumber ( value ) && this . _array && this . _array . length !== value ) { const added = [ ] ; for ( let i = this . _array . length ; i < value ; ++ i ) { added . push ( undefined ) ; } this . splice ( value , this . _array . length - value , ... added ) ; } } /**
     * Returns a string representation of an array.
     */ toString ( ) { return this . _array . toString ( ) ; } toLocaleString ( ) { return this . _array . toLocaleString ( ) ; } param items concat ( ... args ) { this . _addArgs . index = this . _array . length ; const result = this . _array . concat ( ... args ) ; return result ; } param separator join ( separator ? ) { return this . _array . join ( separator ) ; } /**
     * Removes the last element from an array and returns it.
     */ pop ( ) { this . _deleteArgs . index = this . _array . length - 1 ; const result = this . _array . pop ( ) ; this . _deleteArgs . removed = [ result ] ; this . notify ( this . _deleteArgs ) ; this . _notifyLengthChange ( ) ; return result ; } param item push ( ... args ) { this . _addArgs . index = this . _array . length ; if ( arguments . length === 1 && Array . isArray ( arguments [ 0 ] ) ) { const source = < Array < T > > arguments [ 0 ] ; for ( let i = 0 , l = source . length ; i < l ; i ++ ) { this . _array . push ( source [ i ] ) ; } } else { this . _array . push ( ... args ) ; } this . _addArgs . addedCount = this . _array . length - this . _addArgs . index ; this . notify ( this . _addArgs ) ; this . _notifyLengthChange ( ) ; return this . _array . length ; } _notifyLengthChange ( ) { const lengthChangedData = this . _createPropertyChangeData ( 'length' , this . _array . length ) ; this . notify ( lengthChangedData ) ; } /**
     * Reverses the elements in an Array.
     */ reverse ( ) { return this . _array . reverse ( ) ; } /**
     * Removes the first element from an array and returns it.
     */ shift ( ) { const result = this . _array . shift ( ) ; this . _deleteArgs . index = 0 ; this . _deleteArgs . removed = [ result ] ; this . notify ( this . _deleteArgs ) ; this . _notifyLengthChange ( ) ; return result ; } param start param end slice ( start ? , end ? ) { return this . _array . slice ( start , end ) ; } param compareFn sort ( compareFn ? ) { return this . _array . sort ( compareFn ) ; } param start param deleteCount param items splice ( start , deleteCount ? , ... items ) { const length = this . _array . length ; const result = arguments . length === 1 ? this . _array . splice ( start ) : this . _array . splice ( start , deleteCount , ... items ) ; this . notify ( < ChangedData < T > > { eventName : CHANGE , object : this , action : ChangeType . Splice , index : Math . max ( Math . min ( start , length - ( result . length > 0 ? 1 : 0 ) ) , 0 ) , removed : result , addedCount : this . _array . length + result . length - length , } ) ; if ( this . _array . length !== length ) { this . _notifyLengthChange ( ) ; } return result ; } param items unshift ( ... args ) { const length = this . _array . length ; const result = this . _array . unshift ( ... args ) ; this . _addArgs . index = 0 ; this . _addArgs . addedCount = result - length ; this . notify ( this . _addArgs ) ; this . _notifyLengthChange ( ) ; return result ; } param predicate param thisArg findIndex ( predicate , thisArg ? ) { return this . _array . findIndex ( predicate , thisArg ) ; } param searchElement param fromIndex indexOf ( searchElement , fromIndex ? ) { const index = fromIndex ? fromIndex : 0 ; for ( let i = index , l = this . _array . length ; i < l ; i ++ ) { if ( this . _array [ i ] === searchElement ) { return i ; } } return - 1 ; } param searchElement param fromIndex lastIndexOf ( searchElement , fromIndex ? ) { const index = fromIndex ? fromIndex : this . _array . length - 1 ; for ( let i = index ; i >= 0 ; i -- ) { if ( this . _array [ i ] === searchElement ) { return i ; } } return - 1 ; } param callbackfn param thisArg every ( callbackfn , thisArg ? ) { return this . _array . every ( callbackfn , thisArg ) ; } param callbackfn param thisArg some ( callbackfn , thisArg ? ) { return this . _array . some ( callbackfn , thisArg ) ; } param callbackfn param thisArg forEach ( callbackfn , thisArg ? ) { this . _array . forEach ( callbackfn , thisArg ) ; } param callbackfn param thisArg map < U > ( callbackfn , thisArg ? ) { return this . _array . map ( callbackfn , thisArg ) ; } param callbackfn param thisArg filter ( callbackfn , thisArg ? ) { return this . _array . filter ( callbackfn , thisArg ) ; } param callbackfn param initialValue reduce ( callbackfn , initialValue ? ) { return initialValue !== undefined ? this . _array . reduce ( callbackfn , initialValue ) : this . _array . reduce ( callbackfn ) ; } param callbackfn param initialValue reduceRight ( callbackfn , initialValue ? ) { return initialValue !== undefined ? this . _array . reduceRight ( callbackfn , initialValue ) : this . _array . reduceRight ( callbackfn ) ; } } export interface ObservableArray < T > { param eventNames param callback param thisArg on ( eventNames , callback , thisArg ? ) : void ; on ( event , callback , thisArg ? ) : void ; }