@@ -8,44 +8,89 @@ import {
8
8
QueueableInterface ,
9
9
ResponseContext ,
10
10
Theme ,
11
- } from './interfaces ' ;
11
+ } from './common ' ;
12
12
13
- import TemplateFactory from './template' ;
14
- import { parseFunction } from './parseFunction' ;
13
+ import FlasherFactory from './flasherFactory' ;
15
14
16
15
export default class Flasher {
17
- private defaultHandler : string = 'template .flasher' ;
16
+ private defaultHandler : string = 'theme .flasher' ;
18
17
19
18
private factories : Map < string , NotificationFactoryInterface > = new Map < string , NotificationFactoryInterface > ( ) ;
20
19
21
20
private themes : Map < string , Theme > = new Map < string , Theme > ( ) ;
22
21
23
- success ( message : string , title ?: string , options ?: FlasherOptions ) : void {
24
- this . flash ( { type : 'success' , message, title, options } ) ;
22
+ success ( message : string | FlasherOptions , title ?: string | FlasherOptions , options ?: FlasherOptions ) : void {
23
+ this . flash ( 'success' , message , title , options ) ;
25
24
}
26
25
27
- info ( message : string , title ?: string , options ?: FlasherOptions ) : void {
28
- this . flash ( { type : 'info' , message, title, options } ) ;
26
+ info ( message : string | FlasherOptions , title ?: string | FlasherOptions , options ?: FlasherOptions ) : void {
27
+ this . flash ( 'info' , message , title , options ) ;
29
28
}
30
29
31
- warning ( message : string , title ?: string , options ?: FlasherOptions ) : void {
32
- this . flash ( { type : 'warning' , message, title, options } ) ;
30
+ warning ( message : string | FlasherOptions , title ?: string | FlasherOptions , options ?: FlasherOptions ) : void {
31
+ this . flash ( 'warning' , message , title , options ) ;
33
32
}
34
33
35
- error ( message : string , title ?: string , options ?: FlasherOptions ) : void {
36
- this . flash ( { type : 'error' , message, title, options } ) ;
34
+ error ( message : string | FlasherOptions , title ?: string | FlasherOptions , options ?: FlasherOptions ) : void {
35
+ this . flash ( 'error' , message , title , options ) ;
37
36
}
38
37
39
- flash ( notification : FlasherNotification ) : void {
38
+ flash ( type : string | FlasherOptions , message : string | FlasherOptions , title ?: string | FlasherOptions , options ?: FlasherOptions ) : void {
39
+ const notification = this . createNotification ( type , message , title , options ) ;
40
40
const factory = this . create ( this . defaultHandler ) ;
41
+
42
+ factory . renderOptions ( { } ) ;
43
+ factory . render ( { notification } ) ;
44
+ }
45
+
46
+ createNotification (
47
+ type : string | FlasherOptions ,
48
+ message ?: string | FlasherOptions ,
49
+ title ?: string | FlasherOptions ,
50
+ options ?: FlasherOptions
51
+ ) : FlasherNotification {
52
+ if ( typeof type === 'object' ) {
53
+ options = type ;
54
+ type = options . type as unknown as string ;
55
+ message = options . message as unknown as string ;
56
+ title = options . title as unknown as string ;
57
+ } else if ( typeof message === 'object' ) {
58
+ options = message ;
59
+ message = options . message as unknown as string ;
60
+ title = options . title as unknown as string ;
61
+ } else if ( typeof title === 'object' ) {
62
+ options = title ;
63
+ title = options . title as unknown as string ;
64
+ }
65
+
66
+ if ( undefined === message ) {
67
+ throw new Error ( 'message option is required' ) ;
68
+ }
69
+
70
+ return {
71
+ type : type || 'info' ,
72
+ message,
73
+ title,
74
+ options
75
+ } ;
76
+ }
77
+
78
+ create ( alias : string ) : NotificationFactoryInterface {
79
+ alias = this . resolveHandler ( alias ) ;
80
+ this . resolveThemeHandler ( alias ) ;
81
+
82
+ let factory = this . factories . get ( alias ) ;
41
83
if ( ! factory ) {
42
- return ;
84
+ throw new Error ( `Unable to resolve " ${ alias } " notification factory, did you forget to register it?` ) ;
43
85
}
44
86
45
- notification . type = notification . type || 'info' ;
87
+ return factory ;
88
+ }
46
89
47
- factory . renderOptions ( { } ) ;
48
- factory . render ( { notification } ) ;
90
+ renderOptions ( options : FlasherResponseOptions ) : void {
91
+ Object . entries ( options ) . forEach ( ( [ handler , option ] ) => {
92
+ this . create ( handler ) . renderOptions ( option ) ;
93
+ } ) ;
49
94
}
50
95
51
96
render ( response : FlasherResponse ) : void {
@@ -67,19 +112,6 @@ export default class Flasher {
67
112
this . themes . set ( name , theme ) ;
68
113
}
69
114
70
- create ( alias : string ) : NotificationFactoryInterface | undefined {
71
- alias = this . resolveHandler ( alias ) ;
72
-
73
- if ( 0 === alias . indexOf ( 'template.' ) && ! this . factories . has ( alias ) ) {
74
- let viewFactory = this . themes . get ( alias . replace ( 'template.' , '' ) ) ;
75
- if ( viewFactory ) {
76
- this . addFactory ( alias , new TemplateFactory ( viewFactory ) ) ;
77
- }
78
- }
79
-
80
- return this . factories . get ( alias ) ;
81
- }
82
-
83
115
using ( name : string ) : Flasher {
84
116
this . defaultHandler = name ;
85
117
@@ -131,38 +163,25 @@ export default class Flasher {
131
163
document . body . appendChild ( tag ) ;
132
164
}
133
165
134
- renderOptions ( options : FlasherResponseOptions ) : void {
135
- Object . entries ( options ) . forEach ( ( [ handler , option ] ) => {
136
- const factory = this . create ( handler ) ;
137
- if ( factory ) {
138
- factory . renderOptions ( option ) ;
139
- }
140
- } ) ;
141
- }
142
-
143
166
renderEnvelopes ( envelopes : Envelope [ ] , context : ResponseContext ) : void {
144
167
const queues = new Map < string , QueueableInterface > ( ) ;
168
+
145
169
envelopes . forEach ( ( envelope ) => {
146
- envelope . context = context ;
170
+ envelope . context = Object . assign ( { } , envelope . context || { } , context ) ;
147
171
envelope . handler = this . resolveHandler ( envelope . handler ) ;
148
172
149
173
const factory = this . create ( envelope . handler ) ;
150
- if ( undefined !== factory ) {
151
- if ( this . isQueueable ( factory ) ) {
152
- if ( ! queues . get ( envelope . handler ) ) {
153
- factory . resetQueue ( ) ;
154
- }
155
- factory . addEnvelope ( envelope ) ;
156
- queues . set ( envelope . handler , factory ) ;
157
- } else {
158
- factory . render ( envelope ) ;
159
- }
174
+ if ( ! this . isQueueable ( factory ) ) {
175
+ factory . render ( envelope ) ;
176
+ return ;
160
177
}
161
- } ) ;
162
178
163
- queues . forEach ( ( factory ) => {
164
- factory . renderQueue ( ) ;
179
+ queues . get ( envelope . handler ) || factory . resetQueue ( ) ;
180
+ factory . addEnvelope ( envelope ) ;
181
+ queues . set ( envelope . handler , factory ) ;
165
182
} ) ;
183
+
184
+ queues . forEach ( factory => factory . renderQueue ( ) ) ;
166
185
}
167
186
168
187
isQueueable ( object : any ) : object is QueueableInterface {
@@ -183,7 +202,6 @@ export default class Flasher {
183
202
184
203
response . envelopes . forEach ( envelope => {
185
204
envelope . handler = this . resolveHandler ( envelope . handler ) ;
186
-
187
205
envelope . notification . options = this . parseOptions ( envelope . notification . options || { } ) ;
188
206
this . pushStyles ( response , envelope . handler ) ;
189
207
} ) ;
@@ -193,14 +211,33 @@ export default class Flasher {
193
211
194
212
parseOptions ( options : FlasherOptions ) : FlasherOptions {
195
213
Object . entries ( options ) . forEach ( ( [ key , value ] ) => {
196
- options [ key ] = parseFunction ( value ) ;
214
+ options [ key ] = this . parseFunction ( value ) ;
197
215
} ) ;
198
216
199
217
return options ;
200
218
}
201
219
220
+ parseFunction ( func : any ) : any {
221
+ if ( typeof func !== 'string' ) {
222
+ return func ;
223
+ }
224
+
225
+ const match = func . match ( / ^ f u n c t i o n (?: .+ ) ? (?: \s + ) ? \( ( .+ ) ? \) (?: \s + | \n + ) ? { (?: \s + | \n + ) ? ( (?: .| \n ) + ) } $ / m) ;
226
+
227
+ if ( ! match ) {
228
+ return func ;
229
+ }
230
+
231
+ const args = match [ 1 ] ?. split ( ',' ) . map ( arg => arg . trim ( ) ) ?? [ ] ;
232
+ const body = match [ 2 ] ;
233
+
234
+ // @ts -ignore
235
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
236
+ return new Function ( ...args , body ) ;
237
+ }
238
+
202
239
pushStyles ( response : FlasherResponse , handler : string ) : void {
203
- handler = handler . replace ( 'template .' , '' ) ;
240
+ handler = handler . replace ( 'theme .' , '' ) ;
204
241
const styles = this . themes . get ( handler ) ?. styles || [ ] ;
205
242
206
243
response . styles = response . styles
@@ -211,10 +248,25 @@ export default class Flasher {
211
248
resolveHandler ( handler ?: string ) : string {
212
249
handler = handler || this . defaultHandler ;
213
250
214
- if ( 'template' === handler ) {
215
- handler = 'template .flasher' ;
251
+ if ( [ 'flasher' , 'theme' , 'template' ] . includes ( handler ) ) {
252
+ handler = 'theme .flasher' ;
216
253
}
217
254
255
+ handler = handler . replace ( 'template.' , 'theme.' ) ;
256
+
218
257
return handler ;
219
258
}
259
+
260
+ resolveThemeHandler ( alias : string ) : void {
261
+ if ( 0 !== alias . indexOf ( 'theme.' ) ) {
262
+ return ;
263
+ }
264
+
265
+ let viewFactory = this . themes . get ( alias . replace ( 'theme.' , '' ) ) ;
266
+ if ( ! viewFactory ) {
267
+ return ;
268
+ }
269
+
270
+ this . addFactory ( alias , new FlasherFactory ( viewFactory ) ) ;
271
+ }
220
272
}
0 commit comments