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"],
|
||||
"types": ["node"], // Includes Node.js types
|
||||
},
|
||||
|
||||
|
||||
"include": ["./*"]
|
||||
}
|
Loading…
Reference in New Issue