@@ -15,9 +15,6 @@ const adapters = {
15
15
snips : snipsAdapter
16
16
} ;
17
17
18
- declare var CodeFlask ;
19
- let ReactJson : any = null ;
20
-
21
18
interface IEditorState {
22
19
error : null | string ;
23
20
warning : null | string ;
@@ -28,6 +25,17 @@ interface IEditorState {
28
25
currentAdapter : 'default' | 'rasa' | 'snips' ;
29
26
useCustomOptions : boolean ;
30
27
}
28
+
29
+ // NOTE: for SSR, wrap the require in check for window
30
+ let CodeFlask = null ;
31
+ let ReactJson = null ;
32
+ if ( typeof window !== `undefined` ) {
33
+ // tslint:disable-next-line:no-var-requires
34
+ CodeFlask = require ( 'codeflask' ) . default ;
35
+ // tslint:disable-next-line:no-var-requires
36
+ ReactJson = require ( 'react-json-view' ) . default ;
37
+ }
38
+
31
39
export default class Editor extends React . Component < { } , IEditorState > {
32
40
public state : IEditorState = {
33
41
error : null ,
@@ -53,33 +61,40 @@ export default class Editor extends React.Component<{}, IEditorState> {
53
61
return ;
54
62
}
55
63
const validation = this . getDSLValidation ( this . codeInputValue ) ;
64
+ let newState = { } ;
56
65
if ( validation && validation . error ) {
57
- this . setState ( { error : validation . error , warning : null } ) ;
66
+ newState = { error : validation . error , warning : null } ;
58
67
} else if ( validation && validation . warning ) {
59
- this . setState ( { error : null , warning : validation . warning } ) ;
68
+ newState = { error : null , warning : validation . warning } ;
60
69
} else {
61
- this . setState ( { error : null , warning : null } ) ;
70
+ newState = { error : null , warning : null } ;
62
71
}
72
+ this . setState ( newState , ( ) => {
73
+ this . saveToLocalStorage ( true , false , false ) ;
74
+ } ) ;
63
75
} , 300 ) ;
64
76
65
77
public componentDidMount ( ) {
66
- ReactJson = require ( 'react-json-view' ) . default ;
67
- const flask = new CodeFlask ( '#my-code-editor' , {
68
- language : 'chatito' ,
69
- lineNumbers : true
70
- } ) ;
71
- flask . addLanguage ( 'chatito' , chatitoPrism ) ;
72
- flask . onUpdate ( code => {
73
- this . codeInputValue = code ;
74
- this . tabs [ this . state . activeTabIndex ] . value = code ;
75
- // NOTE: ugly hack to know when codeflask is mounted (it makes 2 calls to update on mount)
76
- this . editorUpdatesSetupCount < 2 ? this . editorUpdatesSetupCount ++ : this . setState ( { dataset : null } ) ;
77
- this . debouncedTabDSLValidation ( ) ;
78
+ if ( ! CodeFlask ) {
79
+ return ;
80
+ }
81
+ this . loadFromLocalStorage ( ( ) => {
82
+ const flask = new CodeFlask ( '#my-code-editor' , {
83
+ language : 'chatito' ,
84
+ lineNumbers : true
85
+ } ) ;
86
+ flask . addLanguage ( 'chatito' , chatitoPrism ) ;
87
+ flask . onUpdate ( code => {
88
+ this . codeInputValue = code ;
89
+ this . tabs [ this . state . activeTabIndex ] . value = code ;
90
+ // NOTE: ugly hack to know when codeflask is mounted (it makes 2 calls to update on mount)
91
+ this . editorUpdatesSetupCount < 2 ? this . editorUpdatesSetupCount ++ : this . setState ( { dataset : null } ) ;
92
+ this . debouncedTabDSLValidation ( ) ;
93
+ } ) ;
94
+ flask . updateCode ( this . tabs [ this . state . activeTabIndex ] . value ) ;
95
+ flask . setLineNumber ( ) ;
96
+ this . codeflask = flask ;
78
97
} ) ;
79
- flask . highlight ( ) ;
80
- flask . updateCode ( this . tabs [ this . state . activeTabIndex ] . value ) ;
81
- flask . setLineNumber ( ) ;
82
- this . codeflask = flask ;
83
98
}
84
99
85
100
public render ( ) {
@@ -212,9 +227,9 @@ export default class Editor extends React.Component<{}, IEditorState> {
212
227
</ es . TabButton >
213
228
) ;
214
229
} ;
215
- /* ================== Event Handlers ================== */
216
230
217
- private onCloseDrawer = ( ) => this . setState ( { showDrawer : false } ) ;
231
+ /* ================== Event Handlers ================== */
232
+ private onCloseDrawer = ( ) => this . setState ( { showDrawer : false , dataset : null } ) ;
218
233
219
234
private onCustomOptionsCheckboxChange = e => {
220
235
this . setState ( { useCustomOptions : e . target . checked } ) ;
@@ -227,12 +242,16 @@ export default class Editor extends React.Component<{}, IEditorState> {
227
242
} else if ( e . target . value === 'snips' ) {
228
243
adapterOptions = Object . assign ( { } , snipsDefaultOptions ) ;
229
244
}
230
- this . setState ( { currentAdapter : e . target . value , adapterOptions, dataset : null } ) ;
245
+ this . setState ( { currentAdapter : e . target . value , adapterOptions, dataset : null } , ( ) => {
246
+ this . saveToLocalStorage ( false , true , true ) ;
247
+ } ) ;
231
248
} ;
232
249
233
250
private onEditAdapterOptions = changes => {
234
251
if ( changes && changes . updated_src ) {
235
- this . setState ( { adapterOptions : changes . updated_src } ) ;
252
+ this . setState ( { adapterOptions : changes . updated_src } , ( ) => {
253
+ this . saveToLocalStorage ( false , true , false ) ;
254
+ } ) ;
236
255
return null ;
237
256
}
238
257
return false ;
@@ -272,6 +291,63 @@ export default class Editor extends React.Component<{}, IEditorState> {
272
291
273
292
/* ================== Utils ================== */
274
293
294
+ private saveToLocalStorage = ( saveTabs , saveAdapterOptions , saveCurrentAdapter ) => {
295
+ if ( window && localStorage ) {
296
+ if ( saveTabs ) {
297
+ localStorage . setItem ( 'tabs' , JSON . stringify ( this . tabs ) ) ;
298
+ }
299
+ if ( saveAdapterOptions ) {
300
+ localStorage . setItem ( 'adapterOptions' , this . state . useCustomOptions ? JSON . stringify ( this . state . adapterOptions ) : '' ) ;
301
+ }
302
+ if ( saveCurrentAdapter ) {
303
+ localStorage . setItem ( 'currentAdapter' , this . state . currentAdapter ) ;
304
+ }
305
+ }
306
+ } ;
307
+
308
+ private loadFromLocalIfPresent = ( key : string , parseAsJSON : boolean ) => {
309
+ if ( window && localStorage ) {
310
+ try {
311
+ const item = localStorage . getItem ( key ) ;
312
+ if ( ! parseAsJSON ) {
313
+ return item ;
314
+ }
315
+ if ( item ) {
316
+ try {
317
+ return JSON . parse ( item ) ;
318
+ } catch ( e ) {
319
+ // just catch the error
320
+ }
321
+ }
322
+ } catch ( e ) {
323
+ // tslint:disable-next-line:no-console
324
+ console . error ( e ) ;
325
+ }
326
+ }
327
+ } ;
328
+
329
+ private loadFromLocalStorage = ( cb : ( ) => void ) => {
330
+ if ( window && localStorage ) {
331
+ const newState : any = { } ;
332
+ const localTabs = this . loadFromLocalIfPresent ( 'tabs' , true ) ;
333
+ const localAdapterOptions = this . loadFromLocalIfPresent ( 'adapterOptions' , true ) ;
334
+ const localCurrentAdapter = this . loadFromLocalIfPresent ( 'currentAdapter' , false ) ;
335
+ if ( localTabs ) {
336
+ this . tabs = localTabs ;
337
+ }
338
+ if ( localAdapterOptions ) {
339
+ newState . adapterOptions = localAdapterOptions ;
340
+ newState . useCustomOptions = true ;
341
+ }
342
+ if ( localCurrentAdapter ) {
343
+ newState . currentAdapter = localCurrentAdapter ;
344
+ }
345
+ this . setState ( newState , cb ) ;
346
+ } else {
347
+ cb ( ) ;
348
+ }
349
+ } ;
350
+
275
351
private changeTab = ( i : number , cb ?: ( ) => void ) => {
276
352
this . setState ( { activeTabIndex : i } , ( ) => {
277
353
this . codeflask . updateCode ( this . tabs [ this . state . activeTabIndex ] . value ) ;
0 commit comments