| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | export class UIEventSource<T>{ | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2020-07-20 21:03:55 +02:00
										 |  |  |     public data: T; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |     private _callbacks = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     constructor(data: T) { | 
					
						
							|  |  |  |         this.data = data; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 03:16:43 +02:00
										 |  |  |     public addCallback(callback: ((latestData: T) => void)): UIEventSource<T> { | 
					
						
							| 
									
										
										
										
											2020-10-06 01:37:02 +02:00
										 |  |  |         if(callback === console.log){ | 
					
						
							|  |  |  |             // This ^^^ actually works!
 | 
					
						
							|  |  |  |             throw "Don't add console.log directly as a callback - you'll won't be able to find it afterwards. Wrap it in a lambda instead." | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         this._callbacks.push(callback); | 
					
						
							|  |  |  |         return this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 03:16:43 +02:00
										 |  |  |     public addCallbackAndRun(callback: ((latestData: T) => void)): UIEventSource<T> { | 
					
						
							|  |  |  |         callback(this.data); | 
					
						
							|  |  |  |         return this.addCallback(callback); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-31 02:59:47 +02:00
										 |  |  |     public setData(t: T): UIEventSource<T> { | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         if (this.data === t) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         this.data = t; | 
					
						
							|  |  |  |         this.ping(); | 
					
						
							| 
									
										
										
										
											2020-08-31 02:59:47 +02:00
										 |  |  |         return this; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public ping(): void { | 
					
						
							| 
									
										
										
										
											2020-07-01 17:38:48 +02:00
										 |  |  |         for (const callback of this._callbacks) { | 
					
						
							|  |  |  |             callback(this.data); | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 13:28:45 +02:00
										 |  |  |     public static flatten<X>(source: UIEventSource<UIEventSource<X>>, possibleSources: UIEventSource<any>[]): UIEventSource<X> { | 
					
						
							|  |  |  |         const sink = new UIEventSource<X>(source.data?.data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         source.addCallback((latestData) => { | 
					
						
							|  |  |  |            sink.setData(latestData?.data); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const possibleSource of possibleSources) { | 
					
						
							| 
									
										
										
										
											2020-09-02 11:37:34 +02:00
										 |  |  |             possibleSource?.addCallback(() => { | 
					
						
							| 
									
										
										
										
											2020-07-20 13:28:45 +02:00
										 |  |  |                 sink.setData(source.data?.data); | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         return sink; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2020-07-08 11:23:36 +02:00
										 |  |  |     public map<J>(f: ((T) => J), | 
					
						
							| 
									
										
										
										
											2020-08-08 02:16:42 +02:00
										 |  |  |                   extraSources: UIEventSource<any>[] = [], | 
					
						
							|  |  |  |                   g: ((J) => T) = undefined ): UIEventSource<J> { | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         const self = this; | 
					
						
							| 
									
										
										
										
											2020-08-08 02:16:42 +02:00
										 |  |  |          | 
					
						
							|  |  |  |         const newSource = new UIEventSource<J>( | 
					
						
							|  |  |  |             f(this.data) | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |          | 
					
						
							| 
									
										
										
										
											2020-07-08 11:23:36 +02:00
										 |  |  |         const update = function () { | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |             newSource.setData(f(self.data)); | 
					
						
							| 
									
										
										
										
											2020-07-08 11:23:36 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-07-20 13:28:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-25 21:58:29 +02:00
										 |  |  |         this.addCallbackAndRun(update); | 
					
						
							| 
									
										
										
										
											2020-07-08 11:23:36 +02:00
										 |  |  |         for (const extraSource of extraSources) { | 
					
						
							| 
									
										
										
										
											2020-08-31 13:25:13 +02:00
										 |  |  |             extraSource?.addCallback(update); | 
					
						
							| 
									
										
										
										
											2020-07-08 11:23:36 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-08-08 02:16:42 +02:00
										 |  |  |        | 
					
						
							|  |  |  |         if(g !== undefined) { | 
					
						
							|  |  |  |             newSource.addCallback((latest) => { | 
					
						
							| 
									
										
										
										
											2020-09-10 19:33:06 +02:00
										 |  |  |                 self.setData(g(latest)); | 
					
						
							| 
									
										
										
										
											2020-08-08 02:16:42 +02:00
										 |  |  |             }) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-07-08 11:23:36 +02:00
										 |  |  |          | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         return newSource; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-21 00:07:04 +02:00
										 |  |  |      | 
					
						
							| 
									
										
										
										
											2020-09-18 12:00:38 +02:00
										 |  |  |     public syncWith(otherSource: UIEventSource<T>, reverseOverride = false): UIEventSource<T> { | 
					
						
							| 
									
										
										
										
											2020-07-21 00:07:04 +02:00
										 |  |  |         this.addCallback((latest) => otherSource.setData(latest)); | 
					
						
							|  |  |  |         const self = this; | 
					
						
							|  |  |  |         otherSource.addCallback((latest) => self.setData(latest)); | 
					
						
							| 
									
										
										
										
											2020-09-18 12:00:38 +02:00
										 |  |  |         if (reverseOverride && otherSource.data !== undefined) { | 
					
						
							|  |  |  |             this.setData(otherSource.data); | 
					
						
							|  |  |  |         } else if (this.data === undefined) { | 
					
						
							|  |  |  |             this.setData(otherSource.data); | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2020-07-21 00:07:04 +02:00
										 |  |  |             otherSource.setData(this.data); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-07-24 17:53:09 +02:00
										 |  |  |         return this; | 
					
						
							| 
									
										
										
										
											2020-07-21 00:07:04 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-09-02 11:37:34 +02:00
										 |  |  |      | 
					
						
							|  |  |  |     public stabilized(millisToStabilize) : UIEventSource<T>{ | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         const newSource = new UIEventSource<T>(this.data); | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         let currentCallback = 0; | 
					
						
							|  |  |  |         this.addCallback(latestData => { | 
					
						
							|  |  |  |             currentCallback++; | 
					
						
							|  |  |  |             const thisCallback = currentCallback; | 
					
						
							|  |  |  |             window.setTimeout(() => { | 
					
						
							|  |  |  |                 if(thisCallback === currentCallback){ | 
					
						
							|  |  |  |                     newSource.setData(latestData); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }, millisToStabilize) | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         return newSource; | 
					
						
							| 
									
										
										
										
											2020-09-03 16:44:48 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2020-10-11 22:44:58 +02:00
										 |  |  |     public static Chronic(millis: number, asLong: () => boolean = undefined): UIEventSource<Date> { | 
					
						
							| 
									
										
										
										
											2020-09-03 16:44:48 +02:00
										 |  |  |         const source = new UIEventSource<Date>(undefined); | 
					
						
							| 
									
										
										
										
											2020-10-11 22:44:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 16:44:48 +02:00
										 |  |  |         function run() { | 
					
						
							|  |  |  |             source.setData(new Date()); | 
					
						
							| 
									
										
										
										
											2020-10-11 22:44:58 +02:00
										 |  |  |             if (asLong === undefined || asLong()) { | 
					
						
							|  |  |  |                 window.setTimeout(run, millis); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-09-03 16:44:48 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-10-11 22:44:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 16:44:48 +02:00
										 |  |  |         run(); | 
					
						
							|  |  |  |         return source; | 
					
						
							| 
									
										
										
										
											2020-09-02 11:37:34 +02:00
										 |  |  |          | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | } |