1- import { exec } from "child_process" ;
2- import { promisify } from "util" ;
31import { field , logger , time , Time } from "@coder/logger" ;
4- import { escapePath } from "@coder/protocol" ;
5- import { retry } from "./retry" ;
2+ import { InitData } from "@coder/protocol" ;
3+ import { retry , Retry } from "./retry" ;
4+ import { client } from "./fill/client" ;
5+ import { Clipboard , clipboard } from "./fill/clipboard" ;
6+
7+ export interface IURI {
8+
9+ readonly path : string ;
10+ readonly fsPath : string ;
11+ readonly scheme : string ;
12+
13+ }
14+
15+ export interface IURIFactory {
16+
17+ /**
18+ * Convert the object to an instance of a real URI.
19+ */
20+ create < T extends IURI > ( uri : IURI ) : T ;
21+ file ( path : string ) : IURI ;
22+ parse ( raw : string ) : IURI ;
623
7- export interface IClientOptions {
8- mkDirs ?: string [ ] ;
924}
1025
1126/**
@@ -14,48 +29,96 @@ export interface IClientOptions {
1429 * Everything the client provides is asynchronous so you can wait on what
1530 * you need from it without blocking anything else.
1631 *
17- * It also provides task management to help asynchronously load and time
18- * external code.
32+ * It also provides task management to help asynchronously load and time code.
1933 */
20- export class Client {
34+ export abstract class Client {
2135
22- public readonly mkDirs : Promise < void > ;
36+ public readonly retry : Retry = retry ;
37+ public readonly clipboard : Clipboard = clipboard ;
38+ public readonly uriFactory : IURIFactory ;
2339 private start : Time | undefined ;
2440 private readonly progressElement : HTMLElement | undefined ;
25- private tasks : string [ ] ;
26- private finishedTaskCount : number ;
41+ private tasks : string [ ] = [ ] ;
42+ private finishedTaskCount = 0 ;
43+ private readonly loadTime : Time ;
44+
45+ public constructor ( ) {
46+ logger . info ( "Loading IDE" ) ;
47+
48+ this . loadTime = time ( 2500 ) ;
49+
50+ const overlay = document . getElementById ( "overlay" ) ;
51+ const logo = document . getElementById ( "logo" ) ;
52+ const msgElement = overlay
53+ ? overlay . querySelector ( ".message" ) as HTMLElement
54+ : undefined ;
55+
56+ if ( overlay && logo ) {
57+ overlay . addEventListener ( "mousemove" , ( event ) => {
58+ const xPos = ( ( event . clientX - logo . offsetLeft ) / 24 ) . toFixed ( 2 ) ;
59+ const yPos = ( ( logo . offsetTop - event . clientY ) / 24 ) . toFixed ( 2 ) ;
60+
61+ logo . style . transform = `perspective(200px) rotateX(${ yPos } deg) rotateY(${ xPos } deg)` ;
62+ } ) ;
63+ }
2764
28- public constructor ( options : IClientOptions ) {
29- this . tasks = [ ] ;
30- this . finishedTaskCount = 0 ;
3165 this . progressElement = typeof document !== "undefined"
3266 ? document . querySelector ( "#fill" ) as HTMLElement
3367 : undefined ;
3468
35- this . mkDirs = this . wrapTask ( "Creating directories" , 100 , async ( ) => {
36- if ( options . mkDirs && options . mkDirs . length > 0 ) {
37- await promisify ( exec ) ( `mkdir -p ${ options . mkDirs . map ( escapePath ) . join ( " " ) } ` ) ;
38- }
69+ require ( "path" ) . posix = require ( "path" ) ;
70+
71+ window . addEventListener ( "contextmenu" , ( event ) => {
72+ event . preventDefault ( ) ;
3973 } ) ;
4074
4175 // Prevent Firefox from trying to reconnect when the page unloads.
4276 window . addEventListener ( "unload" , ( ) => {
43- retry . block ( ) ;
77+ this . retry . block ( ) ;
78+ logger . info ( "Unloaded" ) ;
79+ } ) ;
80+
81+ this . uriFactory = this . createUriFactory ( ) ;
82+
83+ this . initialize ( ) . then ( ( ) => {
84+ if ( overlay ) {
85+ overlay . style . opacity = "0" ;
86+ overlay . addEventListener ( "transitionend" , ( ) => {
87+ overlay . remove ( ) ;
88+ } ) ;
89+ }
90+ logger . info ( "Load completed" , field ( "duration" , this . loadTime ) ) ;
91+ } ) . catch ( ( error ) => {
92+ logger . error ( error . message ) ;
93+ if ( overlay ) {
94+ overlay . classList . add ( "error" ) ;
95+ }
96+ if ( msgElement ) {
97+ const button = document . createElement ( "div" ) ;
98+ button . className = "reload-button" ;
99+ button . innerText = "Reload" ;
100+ button . addEventListener ( "click" , ( ) => {
101+ location . reload ( ) ;
102+ } ) ;
103+ msgElement . innerText = `Failed to load: ${ error . message } .` ;
104+ msgElement . parentElement ! . appendChild ( button ) ;
105+ }
106+ logger . warn ( "Load completed with errors" , field ( "duration" , this . loadTime ) ) ;
44107 } ) ;
45108 }
46109
47110 /**
48111 * Wrap a task in some logging, timing, and progress updates. Can optionally
49112 * wait on other tasks which won't count towards this task's time.
50113 */
51- public async wrapTask < T > ( description : string , duration : number , task : ( ) => Promise < T > ) : Promise < T > ;
52- public async wrapTask < T , V > ( description : string , duration : number , task : ( v : V ) => Promise < T > , t : Promise < V > ) : Promise < T > ;
53- public async wrapTask < T , V1 , V2 > ( description : string , duration : number , task : ( v1 : V1 , v2 : V2 ) => Promise < T > , t1 : Promise < V1 > , t2 : Promise < V2 > ) : Promise < T > ;
54- public async wrapTask < T , V1 , V2 , V3 > ( description : string , duration : number , task : ( v1 : V1 , v2 : V2 , v3 : V3 ) => Promise < T > , t1 : Promise < V1 > , t2 : Promise < V2 > , t3 : Promise < V3 > ) : Promise < T > ;
55- public async wrapTask < T , V1 , V2 , V3 , V4 > ( description : string , duration : number , task : ( v1 : V1 , v2 : V2 , v3 : V3 , v4 : V4 ) => Promise < T > , t1 : Promise < V1 > , t2 : Promise < V2 > , t3 : Promise < V3 > , t4 : Promise < V4 > ) : Promise < T > ;
56- public async wrapTask < T , V1 , V2 , V3 , V4 , V5 > ( description : string , duration : number , task : ( v1 : V1 , v2 : V2 , v3 : V3 , v4 : V4 , v5 : V5 ) => Promise < T > , t1 : Promise < V1 > , t2 : Promise < V2 > , t3 : Promise < V3 > , t4 : Promise < V4 > , t5 : Promise < V5 > ) : Promise < T > ;
57- public async wrapTask < T , V1 , V2 , V3 , V4 , V5 , V6 > ( description : string , duration : number , task : ( v1 : V1 , v2 : V2 , v3 : V3 , v4 : V4 , v5 : V5 , v6 : V6 ) => Promise < T > , t1 : Promise < V1 > , t2 : Promise < V2 > , t3 : Promise < V3 > , t4 : Promise < V4 > , t5 : Promise < V5 > , t6 : Promise < V6 > ) : Promise < T > ;
58- public async wrapTask < T > (
114+ public async task < T > ( description : string , duration : number , task : ( ) => Promise < T > ) : Promise < T > ;
115+ public async task < T , V > ( description : string , duration : number , task : ( v : V ) => Promise < T > , t : Promise < V > ) : Promise < T > ;
116+ public async task < T , V1 , V2 > ( description : string , duration : number , task : ( v1 : V1 , v2 : V2 ) => Promise < T > , t1 : Promise < V1 > , t2 : Promise < V2 > ) : Promise < T > ;
117+ public async task < T , V1 , V2 , V3 > ( description : string , duration : number , task : ( v1 : V1 , v2 : V2 , v3 : V3 ) => Promise < T > , t1 : Promise < V1 > , t2 : Promise < V2 > , t3 : Promise < V3 > ) : Promise < T > ;
118+ public async task < T , V1 , V2 , V3 , V4 > ( description : string , duration : number , task : ( v1 : V1 , v2 : V2 , v3 : V3 , v4 : V4 ) => Promise < T > , t1 : Promise < V1 > , t2 : Promise < V2 > , t3 : Promise < V3 > , t4 : Promise < V4 > ) : Promise < T > ;
119+ public async task < T , V1 , V2 , V3 , V4 , V5 > ( description : string , duration : number , task : ( v1 : V1 , v2 : V2 , v3 : V3 , v4 : V4 , v5 : V5 ) => Promise < T > , t1 : Promise < V1 > , t2 : Promise < V2 > , t3 : Promise < V3 > , t4 : Promise < V4 > , t5 : Promise < V5 > ) : Promise < T > ;
120+ public async task < T , V1 , V2 , V3 , V4 , V5 , V6 > ( description : string , duration : number , task : ( v1 : V1 , v2 : V2 , v3 : V3 , v4 : V4 , v5 : V5 , v6 : V6 ) => Promise < T > , t1 : Promise < V1 > , t2 : Promise < V2 > , t3 : Promise < V3 > , t4 : Promise < V4 > , t5 : Promise < V5 > , t6 : Promise < V6 > ) : Promise < T > ;
121+ public async task < T > (
59122 description : string , duration : number = 100 , task : ( ...args : any [ ] ) => Promise < T > , ...after : Array < Promise < any > > // tslint:disable-line no-any
60123 ) : Promise < T > {
61124 this . tasks . push ( description ) ;
@@ -97,4 +160,21 @@ export class Client {
97160 }
98161 }
99162
163+ /**
164+ * A promise that resolves with initialization data.
165+ */
166+ public get initData ( ) : Promise < InitData > {
167+ return client . initData ;
168+ }
169+
170+ /**
171+ * Initialize the IDE.
172+ */
173+ protected abstract initialize ( ) : Promise < void > ;
174+
175+ /**
176+ * Create URI factory.
177+ */
178+ protected abstract createUriFactory ( ) : IURIFactory ;
179+
100180}
0 commit comments