Added Animation/Events/XHttp
This commit is contained in:
parent
a2152bfec6
commit
7a05d26162
|
@ -0,0 +1,21 @@
|
||||||
|
import { OnAnimationFrame } from './OnAnimationFrame';
|
||||||
|
export class AnimationFrameEvent
|
||||||
|
{
|
||||||
|
onAnimationFrame:OnAnimationFrame;
|
||||||
|
|
||||||
|
_timeMS:number = 0;
|
||||||
|
get timeMS(){ return this._timeMS; }
|
||||||
|
|
||||||
|
_lastTimeMS:number = 0;
|
||||||
|
get lastTimeMS(){ return this._lastTimeMS; }
|
||||||
|
|
||||||
|
_deltaTimeMS:number = 0;
|
||||||
|
get deltaTimeMS(){ return this._deltaTimeMS; }
|
||||||
|
|
||||||
|
update()
|
||||||
|
{
|
||||||
|
this._lastTimeMS = this._timeMS;
|
||||||
|
this._timeMS = Date.now();
|
||||||
|
this._deltaTimeMS = this._timeMS - this._lastTimeMS;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,155 @@
|
||||||
|
import { EventSlot } from '../events/EventSlot';
|
||||||
|
import { AnimationFrameEvent } from './AnimationFrameEvent';
|
||||||
|
import { sleep } from './sleep';
|
||||||
|
|
||||||
|
export type Idle = "Idle";
|
||||||
|
export type Running = "Running";
|
||||||
|
export type Stopping = "Stopping";
|
||||||
|
|
||||||
|
export type OnAnimationFrameStatus = Idle | Running | Stopping;
|
||||||
|
|
||||||
|
|
||||||
|
export class OnAnimationFrame extends EventSlot<AnimationFrameEvent>
|
||||||
|
{
|
||||||
|
static readonly Idle:Idle = "Idle";
|
||||||
|
static readonly Running:Running = "Running";
|
||||||
|
static readonly Stopping:Stopping = "Stopping";
|
||||||
|
|
||||||
|
#status:OnAnimationFrameStatus = OnAnimationFrame.Idle;
|
||||||
|
get status(){ return this.#status; }
|
||||||
|
|
||||||
|
#stopFlag = false;
|
||||||
|
#updater:()=>void = null;
|
||||||
|
#animationFrameEvent = new AnimationFrameEvent();
|
||||||
|
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.#animationFrameEvent.onAnimationFrame = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
doUntil( condition:()=>boolean, callback:( e:AnimationFrameEvent )=>void )
|
||||||
|
{
|
||||||
|
let conditionalCallback = ( e:AnimationFrameEvent )=>
|
||||||
|
{
|
||||||
|
callback( e );
|
||||||
|
|
||||||
|
if ( ! condition() )
|
||||||
|
{
|
||||||
|
this.removeListener( conditionalCallback );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addListener( conditionalCallback );
|
||||||
|
}
|
||||||
|
|
||||||
|
doOnceWhen( condition:()=>boolean, callback:( e:AnimationFrameEvent )=>void )
|
||||||
|
{
|
||||||
|
let conditionalCallback = ( e:AnimationFrameEvent )=>
|
||||||
|
{
|
||||||
|
if ( ! condition() )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback( e );
|
||||||
|
this.removeListener( conditionalCallback );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addListener( conditionalCallback );
|
||||||
|
}
|
||||||
|
|
||||||
|
run()
|
||||||
|
{
|
||||||
|
if ( OnAnimationFrame.Running === this.#status )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._schedulRunning();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _schedulRunning()
|
||||||
|
{
|
||||||
|
if ( ! this.#updater )
|
||||||
|
{
|
||||||
|
this._createUpdaterFunction();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( OnAnimationFrame.Idle === this.#status )
|
||||||
|
{
|
||||||
|
this._startUpdaterLoop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentState = this.#status as OnAnimationFrameStatus;
|
||||||
|
let maxTries = 1000;
|
||||||
|
|
||||||
|
while ( OnAnimationFrame.Idle !== currentState )
|
||||||
|
{
|
||||||
|
maxTries--;
|
||||||
|
|
||||||
|
if ( maxTries <= 0 )
|
||||||
|
{
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
await sleep( 1 );
|
||||||
|
currentState = this.#status as OnAnimationFrameStatus;
|
||||||
|
|
||||||
|
if ( OnAnimationFrame.Idle === currentState )
|
||||||
|
{
|
||||||
|
this._startUpdaterLoop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private _startUpdaterLoop()
|
||||||
|
{
|
||||||
|
this.#stopFlag = false;
|
||||||
|
this.#status = OnAnimationFrame.Running;
|
||||||
|
this.#updater();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createUpdaterFunction()
|
||||||
|
{
|
||||||
|
this.#updater =
|
||||||
|
|
||||||
|
( ) =>
|
||||||
|
{
|
||||||
|
this._update();
|
||||||
|
|
||||||
|
if ( this.#stopFlag )
|
||||||
|
{
|
||||||
|
this.#stopFlag = false;
|
||||||
|
this.#status = OnAnimationFrame.Idle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
requestAnimationFrame( this.#updater );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private _update()
|
||||||
|
{
|
||||||
|
|
||||||
|
this.#animationFrameEvent.update();
|
||||||
|
|
||||||
|
this.dispatch( this.#animationFrameEvent );
|
||||||
|
}
|
||||||
|
|
||||||
|
stop()
|
||||||
|
{
|
||||||
|
this.#stopFlag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { sleep } from "./sleep";
|
||||||
|
|
||||||
|
export class TimePin
|
||||||
|
{
|
||||||
|
protected _timeMS:number;
|
||||||
|
|
||||||
|
now()
|
||||||
|
{
|
||||||
|
this._timeMS = new Date().getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
static create()
|
||||||
|
{
|
||||||
|
let pin = new TimePin();
|
||||||
|
pin._timeMS = new Date().getTime();
|
||||||
|
return pin;
|
||||||
|
}
|
||||||
|
|
||||||
|
async forMS( durationMS:number, sleepStepsMS:number = 15 ):Promise<void>
|
||||||
|
{
|
||||||
|
let endTime = this._timeMS + durationMS;
|
||||||
|
let currentTime = new Date().getTime();
|
||||||
|
|
||||||
|
while ( currentTime < endTime )
|
||||||
|
{
|
||||||
|
await sleep( sleepStepsMS) ;
|
||||||
|
currentTime = new Date().getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
export function nextFrame():Promise<void>
|
||||||
|
{
|
||||||
|
let promise = new Promise<void>(
|
||||||
|
( resolve, reject ) =>
|
||||||
|
{
|
||||||
|
requestAnimationFrame( () => { resolve(); } );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
export function sleep( timeMS:number ):Promise<void>
|
||||||
|
{
|
||||||
|
let promise = new Promise<void>(
|
||||||
|
( resolve, reject ) =>
|
||||||
|
{
|
||||||
|
setTimeout( resolve, timeMS );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
export class ChangeEvent<T>
|
||||||
|
{
|
||||||
|
private _lastValue:T;
|
||||||
|
get lastValue() { return this._lastValue; }
|
||||||
|
private _newValue:T;
|
||||||
|
get newValue(){ return this._newValue; }
|
||||||
|
|
||||||
|
constructor( lastValue:T, newValue:T )
|
||||||
|
{
|
||||||
|
this._lastValue = lastValue;
|
||||||
|
this._newValue = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { Property } from "./Property";
|
||||||
|
|
||||||
|
interface Comparable<T>
|
||||||
|
{
|
||||||
|
equals( other:T ):boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ComparableProperty<T extends Comparable<T> > extends Property<T>
|
||||||
|
{
|
||||||
|
isEqual( a:T, b:T )
|
||||||
|
{
|
||||||
|
let valueA = a === null ? 0 : a === undefined ? 1 : 2;
|
||||||
|
let valueB = b === null ? 0 : b === undefined ? 1 : 2;
|
||||||
|
|
||||||
|
if ( valueA !== valueB )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( valueA !== 2 )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.equals( b );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
export type EventSlotCallback<T> = ( eventData:T ) => void;
|
||||||
|
|
||||||
|
export class EventSlot<T>
|
||||||
|
{
|
||||||
|
private _listeners:EventSlotCallback<T>[] = [];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
addListener( callback:EventSlotCallback<T> )
|
||||||
|
{
|
||||||
|
this._listeners.push( callback );
|
||||||
|
}
|
||||||
|
|
||||||
|
once( callback:EventSlotCallback<T> )
|
||||||
|
{
|
||||||
|
let onceCallback = ( t:T ) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
callback( t );
|
||||||
|
}
|
||||||
|
catch( e )
|
||||||
|
{
|
||||||
|
console.error( "Error on callback", e );
|
||||||
|
}
|
||||||
|
|
||||||
|
this.removeListener( onceCallback );
|
||||||
|
};
|
||||||
|
|
||||||
|
this.addListener( onceCallback );
|
||||||
|
}
|
||||||
|
|
||||||
|
removeListener( callback:EventSlotCallback<T> )
|
||||||
|
{
|
||||||
|
let index = this._listeners.indexOf( callback );
|
||||||
|
|
||||||
|
if ( index === -1 )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._listeners.splice( index, 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
removeAll()
|
||||||
|
{
|
||||||
|
this._listeners = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dispatch( eventData:T )
|
||||||
|
{
|
||||||
|
for ( let listener of this._listeners )
|
||||||
|
{
|
||||||
|
listener( eventData );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,148 @@
|
||||||
|
import { Arrays } from "../tools/Arrays";
|
||||||
|
import { EventSlot } from "./EventSlot";
|
||||||
|
|
||||||
|
export enum ListPropertyEventType
|
||||||
|
{
|
||||||
|
ADDED,
|
||||||
|
REMOVED,
|
||||||
|
CHANGED,
|
||||||
|
SWAPPED
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ListPropertyEvent<T>
|
||||||
|
{
|
||||||
|
type:ListPropertyEventType;
|
||||||
|
indices:number[] = [];
|
||||||
|
elements:T[] = []
|
||||||
|
|
||||||
|
static create<T>( type:ListPropertyEventType, indices:number[], elements:T[] )
|
||||||
|
{
|
||||||
|
let e = new ListPropertyEvent<T>();
|
||||||
|
e.type = type;
|
||||||
|
e.indices = indices;
|
||||||
|
e.elements = elements;
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ListProperty<T> extends EventSlot<ListPropertyEvent<T>>
|
||||||
|
{
|
||||||
|
#list:T[] = [];
|
||||||
|
|
||||||
|
#dispatch( type:ListPropertyEventType, indices:number[], elements:T[] )
|
||||||
|
{
|
||||||
|
this.dispatch( ListPropertyEvent.create( type, indices, elements ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
#dispatchAdded( indices:number[], elements:T[] )
|
||||||
|
{
|
||||||
|
this.#dispatch( ListPropertyEventType.ADDED, indices, elements );
|
||||||
|
}
|
||||||
|
|
||||||
|
#dispatchRemoved( indices:number[], elements:T[] )
|
||||||
|
{
|
||||||
|
this.#dispatch( ListPropertyEventType.REMOVED, indices, elements );
|
||||||
|
}
|
||||||
|
|
||||||
|
#dispatchChanged( indices:number[], elements:T[] )
|
||||||
|
{
|
||||||
|
this.#dispatch( ListPropertyEventType.CHANGED, indices, elements );
|
||||||
|
}
|
||||||
|
|
||||||
|
#dispatchSwapped( indices:number[], elements:T[] )
|
||||||
|
{
|
||||||
|
this.#dispatch( ListPropertyEventType.SWAPPED, indices, elements );
|
||||||
|
}
|
||||||
|
|
||||||
|
get length()
|
||||||
|
{
|
||||||
|
return this.#list.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
indexOf( t:T )
|
||||||
|
{
|
||||||
|
return this.#list.indexOf( t );
|
||||||
|
}
|
||||||
|
|
||||||
|
forAll( callback:( t:T, index:number ) => void )
|
||||||
|
{
|
||||||
|
for ( let i = 0; i < this.#list.length; i++ )
|
||||||
|
{
|
||||||
|
callback( this.#list[ i ], i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add( t:T )
|
||||||
|
{
|
||||||
|
this.#list.push( t );
|
||||||
|
this.#dispatchAdded( [ this.#list.length - 1 ], [ t ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
addAll( all:T[] )
|
||||||
|
{
|
||||||
|
let last = this.#list.length;
|
||||||
|
this.#list = this.#list.concat( all );
|
||||||
|
this.#dispatchAdded( [ last ], all );
|
||||||
|
}
|
||||||
|
|
||||||
|
get( index:number )
|
||||||
|
{
|
||||||
|
return this.#list[ index ];
|
||||||
|
}
|
||||||
|
|
||||||
|
set( index:number, t:T )
|
||||||
|
{
|
||||||
|
let before = this.#list[ index ];
|
||||||
|
this.#list[ index ] = t;
|
||||||
|
this.#dispatchChanged( [ index ], [ before, t ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
remove( index:number )
|
||||||
|
{
|
||||||
|
let removal = this.#list[ index ];
|
||||||
|
Arrays.removeAt( this.#list, index );
|
||||||
|
|
||||||
|
this.#dispatchRemoved( [ index ], [ removal ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
removeFirst()
|
||||||
|
{
|
||||||
|
if ( this.length < 1 )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.remove( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
removeLast()
|
||||||
|
{
|
||||||
|
if ( this.length < 1 )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.remove( this.length - 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
clear()
|
||||||
|
{
|
||||||
|
let all = this.#list;
|
||||||
|
this.#list = [];
|
||||||
|
|
||||||
|
this.#dispatchRemoved( null, all );
|
||||||
|
}
|
||||||
|
|
||||||
|
swap( indexA:number, indexB:number )
|
||||||
|
{
|
||||||
|
let elementA = this.#list[ indexA ];
|
||||||
|
let elementB = this.#list[ indexB ];
|
||||||
|
|
||||||
|
this.#list[ indexA ] = elementB;
|
||||||
|
this.#list[ indexB ] = elementA;
|
||||||
|
|
||||||
|
this.#dispatchSwapped( [ indexA, indexB ], [ elementB, elementA ] );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
import { EventSlot } from './EventSlot';
|
||||||
|
import { ChangeEvent } from './ChangeEvent';
|
||||||
|
import { isClassOf } from '../tools/TypeUtilities';
|
||||||
|
|
||||||
|
export class Property<T> extends EventSlot<ChangeEvent<T>>
|
||||||
|
{
|
||||||
|
protected _value:T;
|
||||||
|
private _silent:boolean = false;
|
||||||
|
|
||||||
|
get isSilent()
|
||||||
|
{
|
||||||
|
return this._silent;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor( initValue:T )
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this._value = initValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString()
|
||||||
|
{
|
||||||
|
return this.value + "";
|
||||||
|
}
|
||||||
|
|
||||||
|
get value(){ return this._value; }
|
||||||
|
|
||||||
|
|
||||||
|
set value( v:T )
|
||||||
|
{
|
||||||
|
if ( this._silent )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( this.isEqual( v, this._value ) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let valueBefore = this._value;
|
||||||
|
this._value = v;
|
||||||
|
|
||||||
|
this.dispatch( new ChangeEvent<T>( valueBefore, v ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
forceDispatch()
|
||||||
|
{
|
||||||
|
this.dispatch( new ChangeEvent<T>( this._value, this._value ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
silent()
|
||||||
|
{
|
||||||
|
this._silent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsilent()
|
||||||
|
{
|
||||||
|
this._silent = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
silentRecursively():boolean
|
||||||
|
{
|
||||||
|
let silent = this._silent;
|
||||||
|
this._silent = true;
|
||||||
|
return silent;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsilentRecursively( valueBefore:boolean )
|
||||||
|
{
|
||||||
|
this._silent = valueBefore;
|
||||||
|
}
|
||||||
|
|
||||||
|
setValueSilently( v:T )
|
||||||
|
{
|
||||||
|
this._value = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
isEqual( a:T, b:T )
|
||||||
|
{
|
||||||
|
return a === b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static resolveValue<T>( value:T|Property<T>, alternative:T = null )
|
||||||
|
{
|
||||||
|
if ( value === null || value === undefined )
|
||||||
|
{
|
||||||
|
return alternative;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isClassOf( value, Property ) )
|
||||||
|
{
|
||||||
|
return ( value as Property<T> ).value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value as T;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,162 @@
|
||||||
|
export type NullType = "null";
|
||||||
|
export type UndefinedType = "undefined";
|
||||||
|
export type PrimitiveType = "string" | "boolean" | "number";
|
||||||
|
export type DataType = PrimitiveType | NullType | UndefinedType | "object" ;
|
||||||
|
|
||||||
|
export type Action<T> = (t:T)=>void;
|
||||||
|
export type Predicate<T> = (t:T)=>boolean;
|
||||||
|
export type Func<R> = ()=>R;
|
||||||
|
export type Func1<I1,R> = ( i1:I1 ) => R;
|
||||||
|
export type Func2<I1,I2,R> = ( i1:I1, i2:I2 ) => R;
|
||||||
|
export type Func3<I1,I2,I3,R> = ( i1:I1, i2:I2, i3:I3 ) => R;
|
||||||
|
|
||||||
|
|
||||||
|
export interface ClassConstructor
|
||||||
|
{
|
||||||
|
prototype:PrototypeFunction
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface PrototypeFunction
|
||||||
|
{
|
||||||
|
isPrototypeOf:( value:any ) => boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ObjectType
|
||||||
|
{
|
||||||
|
constructor:ClassConstructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isClassOf( value:any, classType:ClassConstructor )
|
||||||
|
{
|
||||||
|
return classType.prototype.isPrototypeOf( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
export function castClass<T>( value:any, classType:ClassConstructor, alternativeValue:T = null )
|
||||||
|
{
|
||||||
|
if ( isClassOf( value, classType ) )
|
||||||
|
{
|
||||||
|
return value as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
return alternativeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getClass( value:any ):ClassConstructor
|
||||||
|
{
|
||||||
|
if ( isPrimitive( value ) )
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isNoValue( value ) )
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.constructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasOwnProp( value:any, name:string )
|
||||||
|
{
|
||||||
|
if ( ! value )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.prototype.hasOwnProperty.call( value, name );
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isNoValue( value:any )
|
||||||
|
{
|
||||||
|
if ( value === null )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value === undefined )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isFunction( value:any )
|
||||||
|
{
|
||||||
|
if ( isNoValue( value ) )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( "function" === typeof( value ) )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMemberName( parent:any, member:any )
|
||||||
|
{
|
||||||
|
for ( let it in parent )
|
||||||
|
{
|
||||||
|
if ( parent[ it ] === member )
|
||||||
|
{
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPrimitive( value:any )
|
||||||
|
{
|
||||||
|
if ( isNoValue( value ) )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let type = typeof( value );
|
||||||
|
|
||||||
|
if ( "string" === type )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( "number" === type )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( "boolean" === type )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function className( value:any )
|
||||||
|
{
|
||||||
|
if ( value === null )
|
||||||
|
{
|
||||||
|
return "null";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value === undefined )
|
||||||
|
{
|
||||||
|
return "undefined";
|
||||||
|
}
|
||||||
|
|
||||||
|
let type = typeof value;
|
||||||
|
|
||||||
|
if ( type === "object" )
|
||||||
|
{
|
||||||
|
return value.constructor.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
export function sleep( ms:number ):Promise<void>
|
||||||
|
{
|
||||||
|
let promise = new Promise<void>(
|
||||||
|
( resolve, reject )=>
|
||||||
|
{
|
||||||
|
setTimeout( ()=>{ resolve(); }, ms );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function waitAround( msMin:number, msMax:number ):Promise<void>
|
||||||
|
{
|
||||||
|
let ms = msMin + Math.random() * ( msMax - msMin );
|
||||||
|
|
||||||
|
let promise = new Promise<void>(
|
||||||
|
( resolve, reject )=>
|
||||||
|
{
|
||||||
|
setTimeout( ()=>{ resolve(); }, ms );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
export type GET = "GET";
|
||||||
|
export type HEAD = "HEAD";
|
||||||
|
export type POST = "POST";
|
||||||
|
export type PUT = "PUT";
|
||||||
|
export type DELETE = "DELETE";
|
||||||
|
export type CONNECT = "CONNECT";
|
||||||
|
export type OPTIONS = "OPTIONS";
|
||||||
|
export type TRACE = "TRACE";
|
||||||
|
export type PATCH = "PATCH";
|
||||||
|
|
||||||
|
export type HTTPMethodType =
|
||||||
|
GET | HEAD | POST | PUT | DELETE | CONNECT | OPTIONS | TRACE | PATCH;
|
||||||
|
|
||||||
|
export class HTTPMethodTypes
|
||||||
|
{
|
||||||
|
static readonly GET:GET = "GET";
|
||||||
|
static readonly HEAD:HEAD = "HEAD";
|
||||||
|
static readonly POST:POST = "POST";
|
||||||
|
static readonly PUT:PUT = "PUT";
|
||||||
|
static readonly DELETE:DELETE = "DELETE";
|
||||||
|
static readonly CONNECT:CONNECT = "CONNECT";
|
||||||
|
static readonly OPTIONS:OPTIONS = "OPTIONS";
|
||||||
|
static readonly TRACE:TRACE = "TRACE";
|
||||||
|
static readonly PATCH:PATCH = "PATCH";
|
||||||
|
|
||||||
|
static readonly all:HTTPMethodType[] =
|
||||||
|
[
|
||||||
|
"GET",
|
||||||
|
"HEAD",
|
||||||
|
"POST",
|
||||||
|
"PUT",
|
||||||
|
"DELETE",
|
||||||
|
"CONNECT",
|
||||||
|
"OPTIONS",
|
||||||
|
"TRACE",
|
||||||
|
"PATCH",
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,213 @@
|
||||||
|
import { HTTPMethodType, HTTPMethodTypes } from "./HTTPMethodType";
|
||||||
|
|
||||||
|
export class Loader
|
||||||
|
{
|
||||||
|
static async request<O,T>( url:string, input:T ):Promise<O>
|
||||||
|
{
|
||||||
|
let promise = new Promise<O>
|
||||||
|
(
|
||||||
|
( resolve, reject ) =>
|
||||||
|
{
|
||||||
|
let xhr = new XMLHttpRequest();
|
||||||
|
|
||||||
|
console.log( "loading", url );
|
||||||
|
xhr.open( "POST", url, true );
|
||||||
|
xhr.responseType = "text";
|
||||||
|
xhr.onload=
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
console.log( xhr.responseURL, xhr.responseText );
|
||||||
|
|
||||||
|
if ( xhr.status !== 200 || xhr.responseText.startsWith( "ERROR:" ) )
|
||||||
|
{
|
||||||
|
reject( xhr.responseText )
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resolve( JSON.parse( xhr.responseText ) as O );
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.onerror=(e)=>
|
||||||
|
{
|
||||||
|
reject( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
xhr.send( JSON.stringify( input ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async readDataURL( blob:Blob ):Promise<FileReader>
|
||||||
|
{
|
||||||
|
let promise = new Promise<FileReader>
|
||||||
|
(
|
||||||
|
( resolve, reject ) =>
|
||||||
|
{
|
||||||
|
let fileReader = new FileReader();
|
||||||
|
|
||||||
|
fileReader.onload = ()=>
|
||||||
|
{
|
||||||
|
resolve( fileReader );
|
||||||
|
}
|
||||||
|
|
||||||
|
fileReader.onerror = ()=>
|
||||||
|
{
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
fileReader.onabort = ()=>
|
||||||
|
{
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
fileReader.readAsDataURL( blob );
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async loadJSON<T>( url:string, method:HTTPMethodType = HTTPMethodTypes.GET):Promise<T>
|
||||||
|
{
|
||||||
|
let promise = new Promise<T>
|
||||||
|
(
|
||||||
|
( resolve, reject )=>
|
||||||
|
{
|
||||||
|
let xhr = new XMLHttpRequest();
|
||||||
|
|
||||||
|
xhr.open( method, url, true );
|
||||||
|
xhr.responseType = "json";
|
||||||
|
|
||||||
|
console.log( "xhr", url, method );
|
||||||
|
|
||||||
|
xhr.onload=()=>
|
||||||
|
{
|
||||||
|
console.log( "onload" );
|
||||||
|
let value = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
value = xhr.response;
|
||||||
|
}
|
||||||
|
catch ( e )
|
||||||
|
{
|
||||||
|
reject( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve( value as T );
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.onerror = ( e ) =>
|
||||||
|
{
|
||||||
|
console.log( "onerror", e );
|
||||||
|
reject( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static loadText( url:string, method:"GET"|"POST" = "GET" ):Promise<string>
|
||||||
|
{
|
||||||
|
let promise = new Promise<string>
|
||||||
|
(
|
||||||
|
( resolve, reject ) =>
|
||||||
|
{
|
||||||
|
let xhr = new XMLHttpRequest();
|
||||||
|
xhr.open( method, url, true );
|
||||||
|
|
||||||
|
xhr.responseType = "text";
|
||||||
|
|
||||||
|
xhr.onload = () =>
|
||||||
|
{
|
||||||
|
console.log( "load", url, xhr );
|
||||||
|
|
||||||
|
if ( xhr.status !== 200 )
|
||||||
|
{
|
||||||
|
reject( xhr.response )
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resolve( xhr.responseText );
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.onerror = ( e )=>
|
||||||
|
{
|
||||||
|
console.log( "error", url, xhr );
|
||||||
|
|
||||||
|
reject( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
static loadXML( url:string ):Promise<Document>
|
||||||
|
{
|
||||||
|
let promise = new Promise<Document>
|
||||||
|
(
|
||||||
|
(resolve,reject)=>
|
||||||
|
{
|
||||||
|
let xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("GET",url,true);
|
||||||
|
xhr.responseType = "document";
|
||||||
|
xhr.onload=()=>
|
||||||
|
{
|
||||||
|
resolve(xhr.responseXML);
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.onerror=(e)=>
|
||||||
|
{
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static loadImage( url:string ):Promise<HTMLImageElement>
|
||||||
|
{
|
||||||
|
let promise = new Promise<HTMLImageElement>
|
||||||
|
(
|
||||||
|
(resolve,reject)=>
|
||||||
|
{
|
||||||
|
let img = new Image();
|
||||||
|
|
||||||
|
img.onload = () =>
|
||||||
|
{
|
||||||
|
resolve( img );
|
||||||
|
};
|
||||||
|
|
||||||
|
img.onerror = ( e ) =>
|
||||||
|
{
|
||||||
|
reject( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
img.src = url;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
export class LogColors
|
||||||
|
{
|
||||||
|
static readonly reset = "\x1b[0m";
|
||||||
|
static readonly bright = "\x1b[1m";
|
||||||
|
static readonly dim = "\x1b[2m";
|
||||||
|
static readonly underscore = "\x1b[4m";
|
||||||
|
static readonly blink = "\x1b[5m";
|
||||||
|
static readonly reverse = "\x1b[7m";
|
||||||
|
static readonly hidden = "\x1b[8m";
|
||||||
|
|
||||||
|
static readonly black_Foreground = "\x1b[30m";
|
||||||
|
static readonly red_Foreground = "\x1b[31m";
|
||||||
|
static readonly green_Foreground = "\x1b[32m";
|
||||||
|
static readonly yellow_Foreground = "\x1b[33m";
|
||||||
|
static readonly blue_Foreground = "\x1b[34m";
|
||||||
|
static readonly magenta_Foreground = "\x1b[35m";
|
||||||
|
static readonly cyan_Foreground = "\x1b[36m";
|
||||||
|
static readonly white_Foreground = "\x1b[37m";
|
||||||
|
static readonly gray_Foreground = "\x1b[90m";
|
||||||
|
|
||||||
|
static readonly black_Background = "\x1b[40m";
|
||||||
|
static readonly red_Background = "\x1b[41m";
|
||||||
|
static readonly green_Background = "\x1b[42m";
|
||||||
|
static readonly yellow_Background = "\x1b[43m";
|
||||||
|
static readonly blue_Background = "\x1b[44m";
|
||||||
|
static readonly magenta_Background = "\x1b[45m";
|
||||||
|
static readonly cyan_Background = "\x1b[46m";
|
||||||
|
static readonly white_Background = "\x1b[47m";
|
||||||
|
static readonly gray_Background = "\x1b[100m";
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,135 @@
|
||||||
|
|
||||||
|
import { RegExpUtility } from "../../browser/text/RegExpUtitlity";
|
||||||
|
import { LogColors } from "./LogColors";
|
||||||
|
|
||||||
|
let pr = ( window as any ).process;
|
||||||
|
|
||||||
|
export class RJLog
|
||||||
|
{
|
||||||
|
static readonly errorColor = LogColors.red_Background;
|
||||||
|
static readonly errorMessageColor = LogColors.red_Foreground;
|
||||||
|
static readonly warnColor = LogColors.yellow_Background;
|
||||||
|
static readonly logColor = LogColors.gray_Background
|
||||||
|
static readonly resetColor = LogColors.reset;
|
||||||
|
|
||||||
|
static readonly matcherWithFunction = /^\s+at\s(.+)\s\(.+?:(\d+:\d+)\)/;
|
||||||
|
static readonly matcherFile = /\(.+?\\(\w+)\.js:(\d+:\d+)\)/;
|
||||||
|
static readonly matcherAnonymous = /^\s+at\s(.+)\s\((.+)\)/;
|
||||||
|
|
||||||
|
static readonly logAlwaysLineInfo = true;
|
||||||
|
|
||||||
|
|
||||||
|
static _parseLineResult( line:string ):RegExpExecArray
|
||||||
|
{
|
||||||
|
let result = RJLog.matcherWithFunction.exec( line ) ||
|
||||||
|
RJLog.matcherFile.exec( line ) ||
|
||||||
|
RJLog.matcherAnonymous.exec( line );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static _parseLine( line:string ):string
|
||||||
|
{
|
||||||
|
let result = RJLog._parseLineResult( line );
|
||||||
|
|
||||||
|
if ( result )
|
||||||
|
{
|
||||||
|
return " " + result[ 1 ] + "(" + result[ 2 ] + ") ";
|
||||||
|
}
|
||||||
|
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
static logError( e:Error )
|
||||||
|
{
|
||||||
|
console.log( "\n" + RJLog._formatErrorMessage( e.stack ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static _formatErrorMessage( stackTrace:string, color:string = RJLog.errorMessageColor )
|
||||||
|
{
|
||||||
|
let lines = RegExpUtility.splitLines( stackTrace );
|
||||||
|
let output:string[] = [ color ];
|
||||||
|
|
||||||
|
lines.forEach(
|
||||||
|
( line, index ) =>
|
||||||
|
{
|
||||||
|
let lineInfo = RJLog._parseLine( line );
|
||||||
|
|
||||||
|
output.push( lineInfo );
|
||||||
|
|
||||||
|
if ( index !== lines.length - 1 )
|
||||||
|
{
|
||||||
|
output.push( "\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
output.push( RJLog.resetColor );
|
||||||
|
|
||||||
|
return output.join( "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
static getLineInfo( color:string = RJLog.logColor, stackTrace?:string, lineIndex:number = 3 )
|
||||||
|
{
|
||||||
|
stackTrace = stackTrace || ( new Error().stack + "" );
|
||||||
|
|
||||||
|
let lines = RegExpUtility.splitLines( stackTrace );
|
||||||
|
|
||||||
|
let result:RegExpExecArray = null;
|
||||||
|
|
||||||
|
while ( ! result && lineIndex < lines.length )
|
||||||
|
{
|
||||||
|
let line = lines[ lineIndex ];
|
||||||
|
|
||||||
|
result = RJLog._parseLineResult( line ) ;
|
||||||
|
|
||||||
|
lineIndex ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ( ! result )
|
||||||
|
{
|
||||||
|
console.log( stackTrace );
|
||||||
|
return color + " <Unknown> " + RJLog.resetColor ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return color + " " + result[ 1 ] + "(" + result[ 2 ] + ") " + RJLog.resetColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static error( ...params:any[] )
|
||||||
|
{
|
||||||
|
if ( RJLog.logAlwaysLineInfo || typeof pr === "object" )
|
||||||
|
{
|
||||||
|
let lineInfo = RJLog.getLineInfo( RJLog.errorColor );
|
||||||
|
console.log( "\n" + lineInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error.apply( console, params );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static warn( ...params:any[] )
|
||||||
|
{
|
||||||
|
if ( RJLog.logAlwaysLineInfo || typeof pr === "object" )
|
||||||
|
{
|
||||||
|
let lineInfo = RJLog.getLineInfo( RJLog.warnColor );
|
||||||
|
console.log( "\n" + lineInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
console.warn.apply( console, params );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static log( ...params:any[] )
|
||||||
|
{
|
||||||
|
if ( RJLog.logAlwaysLineInfo || typeof pr === "object" )
|
||||||
|
{
|
||||||
|
let lineInfo = RJLog.getLineInfo();
|
||||||
|
console.log( "\n" + lineInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log.apply( console, params );
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,10 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions":
|
||||||
|
{
|
||||||
"lib": ["ES2020"],
|
"lib": ["ES2020"],
|
||||||
"types": ["node"], // Includes Node.js types
|
"types": ["node"], // Includes Node.js types
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
"include": ["./*"]
|
"include": ["./*"]
|
||||||
}
|
}
|
Loading…
Reference in New Issue