-
Notifications
You must be signed in to change notification settings - Fork 7
/
GxExecutor.bbj
409 lines (384 loc) · 15.4 KB
/
GxExecutor.bbj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
rem package BBjGridExWidget
rem /**
rem * This file is part of the BBjGridExWidget plugin.
rem * (c) Basis Europe <[email protected]>
rem *
rem * For the full copyright and license information, please view the LICENSE
rem * file that was distributed with this source code.
rem */
use ::BBjGridExWidget/BBjGridExWidget.bbj::BBjGridExWidget
use org.apache.commons.collections4.map.ListOrderedMap
use ::BBjGridExWidget/GxLogger.bbj::GxLogger
rem /**
rem * The GxExecutor is responsible of Javascript code execution in the HTMLView.
rem * It will also tries to debounce the scripts which are enqueued for execution and send
rem * them in patches at specific rate.
rem *
rem * @author Hyyan Abo Fakher
rem */
class public GxExecutor
rem /**
rem * The number of milliseconds before the executor
rem * tries to flush the enqueued scripts on the client
rem */
field Public BBjNumber Rate! = 200
rem /**
rem * When true then the executor will try to executes the JavaScript in this
rem * BBjHtmlView and returns immediately without waiting for a return value from
rem * the client.
rem *
rem * Enabling this option might boost the performance of the grid.
rem */
field public BBjNumber PreferAsyncExecution! = 1
rem /**
rem * The widget instance
rem */
field public BBjGridExWidget Widget!
rem /**
rem * A map of scripts which must be executed
rem */
field public ListOrderedMap Queue! = new ListOrderedMap()
rem /**
rem * When true then the executor will limit the rate at
rem * which executeScript gets invoked on the HTMLView.
rem *
rem * Setting this to "0" will help to boost up the communication
rem * performance between BBj and the grid which lives inside
rem * the HTMLView in BUI context
rem *
rem * By default this options is set to "0"
rem *
rem * @deprecated This option is no longer used and will be removed in the future.
rem * Use `SuppressWebDebouncing` instead.
rem */
field public BBjNumber SuppressBuiDebouncing! = 0
rem /**
rem * When true then the executor will limit the rate at
rem * which executeScript gets invoked on the HTMLView.
rem *
rem * Setting this to "0" will help to boost up the communication
rem * performance between BBj and the grid which lives inside
rem * the HTMLView in BUI & DWC context
rem *
rem * By default this options is set to "0"
rem */
field public BBjNumber SuppressWebDebouncing! = 0
rem /**
rem * When true then the executor will limit the rate at
rem * which executeScript gets invoked on the HTMLView.
rem *
rem * Setting this to "0" will help to boost up the communication
rem * performance between BBj and the grid which lives inside
rem * the HTMLView in GUI context
rem *
rem * By default this options is set to "1"
rem */
field public BBjNumber SuppressGuiDebouncing! = 1
rem /**
rem * A flag which indicates whether the executor entered
rem * the flushing mode or not.
rem */
field protected BBjNumber IsFlushing! = BBjAPI.FALSE
rem /**
rem * Construct new GxExecutor object
rem *
rem * @param BBjGridExWidget widget! the widget instance
rem * @param BBjNumber rate! The number of milliseconds before the GxExecutor
rem * tries to flush the called scripts on the client
rem */
method public GxExecutor(BBjGridExWidget widget!, BBjNumber rate!)
#setWidget(widget!)
#setRate(rate!)
methodend
rem /**
rem * @deprecated Use `setSuppressWebDebouncing` instead
rem */
method public void setSuppressBuiDebouncing(BBjNumber suppressBuiDebouncing!)
GxLogger.warn("since version 1.9.0, GxExecutor.setSuppressBuiDebouncing(BBjNumber suppressBuiDebouncing!) is deprecated / renamed. Use GxExecutor.setSuppressWebDebouncing(BBjNumber suppressWebDebouncing!) instead.")
#setSuppressWebDebouncing(suppressBuiDebouncing!)
methodend
rem /**
rem * @deprecated Use `getSuppressWebDebouncing` instead
rem */
method public BBjNumber getSuppressBuiDebouncing()
methodret #getSuppressWebDebouncing()
methodend
rem /**
rem * Executes the specified JavaScript in this BBjHtmlView control and returns immediately
rem *
rem * @param BBjString script! The Javascript code
rem */
method public void asyncExecute(BBjString script!)
#executeInHTMLView(script!, 0, 1)
methodend
rem /**
rem * Execute a Javascript code on the client
rem *
rem * @param BBjString key! the script unique id
rem * @param BBjString script! The Javascript code
rem * @param BBjNumber debounced! When true , then the script should be debounced , sent directly to the HTMLView otherwise
rem * @param BBjNumber priority! The script priority
rem *
rem * @return Object the result of the Javascript code execution , if any
rem */
method public Object execute(BBjString key! , BBjString script! , BBjNumber debounced! , BBjNumber priority!)
declare auto BBjGridExWidget widget!
widget! = #getWidget()
isWidgetReady! = widget!.getIsReady()
rem /**
rem * If the script should not be debounced , then this means that the execution might
rem * return a value. in this case we check if the grid is ready
rem * and if it is ready we execute the script directly on the HTMLView and
rem * return the result , otherwise we just continue to the next step
rem *
rem * An example of calls which should not be debounced would be something like:
rem * grid!.getSelectedRow() -> we expect a value
rem * grid!.clearData() -> should be executed without delay
rem * because other calls might depend on it.
rem */
if(!debounced!.booleanValue())
if(isWidgetReady!)
methodret #executeInHTMLView(script!, 0, 0)
fi
fi
rem /**
rem * This point is reached in two scenarios:
rem *
rem * 1. The script SHOULD be debounced
rem * 2. The script SHOULD NOT be debounced but the grid is not ready yet
rem * so debouncing is enforced anyway
rem *
rem * We check if debouncing is enabled for the current platform (Web , GUI) then
rem *
rem * in case it is ENABLED :
rem * 1. If the grid is READY we execute the script directly
rem * 2. If the grid is NOT READY we add the script to the queue for later execution
rem *
rem * In case it is NOT ENABLED :
rem * 1. add the script to the queue for later execution
rem * 2. In case the grid is ready start a count down before executing the code
rem * in the HTMLView. the countdown will be restated if the developer tries
rem * to execute anything new before the counted down reaches 0.
rem *
rem */
shouldSuppress! = iff(#isWeb() = 1 , #getSuppressWebDebouncing() , #getSuppressGuiDebouncing())
if shouldSuppress!
if isWidgetReady!
#executeInHTMLView(script!, 1, #getPreferAsyncExecution())
else
#enqueue(key!,script!,priority!)
fi
else
#enqueue(key!,script!,priority!)
if isWidgetReady!
#endTimer().startTimer()
fi
fi
methodret null()
methodend
rem /**
rem * Execute a Javascript code on the client and use the script itself as a key
rem *
rem * @param BBjString script! The Javascript code
rem * @param BBjNumber debounced! When true , then the script should be debounced , sent directly to the HTMLView otherwise
rem * @param BBjNumber priority! The script priority
rem *
rem * @return Object the result of the Javascript code execution , if any
rem */
method public Object execute(BBjString script! , BBjNumber debounced! , BBjNumber priority!)
methodret #execute(script!,script!, debounced!,priority!)
methodend
rem /**
rem * Execute a Javascript code on the client with an auto calculated priority
rem *
rem * @param BBjString script! The Javascript code
rem * @param BBjNumber debounced! When true , then the script should be debounced , sent directly to the HTMLView otherwise
rem * @param BBjNumber priority! The script priority
rem *
rem * @return Object the result of the Javascript code execution , if any
rem */
method public Object execute(BBjString key! ,BBjString script! , BBjNumber debounced!)
methodret #execute(key!,script!, debounced! , null())
methodend
rem /**
rem * Execute a Javascript code on the client , use the script itself as a key and auto calculate priority
rem *
rem * @param BBjString script! The Javascript code
rem * @param BBjNumber debounced! When true , then the script should be debounced , sent directly to the HTMLView otherwise
rem *
rem * @return Object the result of the Javascript code execution , if any
rem */
method public Object execute(BBjString script! , BBjNumber debounced!)
methodret #execute(script!,script!, debounced!)
methodend
rem /**
rem * Execute and debounce a Javascript code on the client and auto calculate priority
rem *
rem * @param BBjString key! the script unique id
rem * @param BBjString script! The Javascript code
rem *
rem * @return Object the result of the Javascript code execution , if any
rem */
method public Object execute(BBjString key! , BBjString script!)
methodret #execute(key!,script!, 1)
methodend
rem /**
rem * Execute and debounce a Javascript code on the client , use the script itself as a key and auto calculate priority
rem *
rem * @param BBjString key! the script unique id
rem *
rem * @return Object the result of the Javascript code execution , if any
rem */
method public Object execute(BBjString script!)
methodret #execute(script!,script!)
methodend
rem /**
rem * Iterate over the enqueued scripts and execute them on the HTML View.
rem *
rem * The gird should call this method once when it is ready to kick in the execution process.
rem * Normally this done after the `ON_PAGE_LOADED` event is fired.
rem *
rem * The executor then will keep flushing itself whenever it is needed.
rem *
rem * @return GxExecutor the executor instance
rem */
method public GxExecutor flush()
declare auto BBjGridExWidget widget!
declare auto ListOrderedMap queue!
queue! = #getQueue()
widget! = #getWidget()
isDebugging! = widget!.getDebug()
platform! = iff(#isWeb() = 1, "(Web)" , "(GUI)")
id! = widget!.getRootId()
if(queue!.size() > 0)
if(isDebugging!)
GxLogger.log("GxExecutor",String.format("%s Flush (%s)" , platform! , id!))
fi
bundle! = iff(isDebugging! AND #isWeb() , "console.group('BBjGridExWidget::GxExecutor.flush : (" + id! + ")');console.time('patch time');" , "")
#setIsFlushing(1)
it! = queue!.entrySet().iterator()
while it!.hasNext()
next! = it!.next()
script! = cast(String, next!.getValue())
if(isDebugging!)
GxLogger.log("GxExecutor",String.format("%s Script : %s" ,platform! ,script!))
if(#isWeb()) then
script! = "console.log(`" + iff(script!.contains("$gw_wnd.gw_init"), "$gw_wnd.gw_init : " + widget!.getRootId() , script!) + "`);" + script!
fi
fi
if !script!.matches(";$") then script! = script! + ";"
bundle! = bundle! + script!
it!.remove()
wend
if(isDebugging! AND #isWeb()) bundle! = bundle! + "console.timeEnd('patch time');console.groupEnd();"
#executeInHTMLView(bundle!, 1, #getPreferAsyncExecution())
#setIsFlushing(0)
fi
methodret #this!
methodend
rem /**
rem * A BBjTimerEvent listener which will be invoked when the
rem * executor count down reaches 0 to flush the enqueued scripts
rem *
rem * @param BBjTimerEvent event!
rem */
method public void onFlush(BBjTimerEvent event!)
#endTimer().flush()
methodend
rem /**
rem * @return BBjNumber True when the platform is BUI or DWC , false otherwise
rem */
method protected boolean isWeb()
p! = info(3,6)
methodret iff(p! = "5" or p! = "6" , 1 , 0)
methodend
rem /**
rem * Enqueue a script for later execution
rem *
rem * @param BBjString key! the script unique id
rem * @param BBjString script! The Javascript code
rem * @param BBjNumber priority! The script priority
rem *
rem * @return GxExecutor the executor instance
rem */
method protected GxExecutor enqueue(BBjString key! , BBjString script!, BBjNumber priority!)
declare auto ListOrderedMap queue!
queue! = #getQueue()
isPrioritized! = priority! <> null() AND priority! > -1
if(queue!.containsKey(key!))
queue!.remove(key!)
fi
if isPrioritized!
queue!.put(priority!,key!,script!)
else
queue!.put(key!,script!)
fi
methodret #this!
methodend
rem /**
rem * Execute a script directly without enqueuing on the HTML View
rem *
rem * @param BBjString script! The Javascript code
rem * @param BBjString isDebounced! True A flag which defines if the script is coming from the queue or not
rem * @param BBjNumber async! True if the script should be executed asynchronously , false otherwise
rem *
rem * @return Object the result of the Javascript code execution , if any
rem */
method protected Object executeInHTMLView(BBjString script!, BBjNumber isDebounced!, BBjNumber async!)
declare auto BBjGridExWidget widget!
widget! = #getWidget()
isDebugging! = widget!.getDebug()
shouldSuppress! = iff(#isWeb() = 1 , #getSuppressWebDebouncing() , #getSuppressGuiDebouncing())
if(isDebugging! AND (isDebounced! = 0 OR shouldSuppress!))
id! = widget!.getRootId()
platform! = iff(#isWeb() = 1, "(Web)" , "(GUI)")
if shouldSuppress!
GxLogger.log("GxExecutor",String.format("%s Flush (%s) -> Script : %s" , platform! , id! , script!))
else
GxLogger.log("GxExecutor",String.format("%s Flush (%s)" , platform! , id!))
GxLogger.log("GxExecutor","(GUI) Script : " + script!)
fi
if(#isWeb()) then
scriptPreview! = iff(script!.contains("`") , "Flushing Batch" , script!)
script! = ";console.group('BBjGridExWidget::GxExecutor.executeInHTMLView : (" + id! + "), Async = " + str(async!) + "');console.log(`" + scriptPreview! + "`);console.groupEnd();" + script!
fi
fi
result! = null()
if widget!.getHTMLView().isDestroyed() <> BBjAPI.TRUE then
if(async!)
if widget!.isWebGui() then
script! = "whenGridLibLoaded(function() {"+script!+"})"
fi
widget!.getHTMLView().executeAsyncScript(script!, err=browser_err)
else
result! = widget!.getHTMLView().executeScript(script!, err=browser_err)
fi
fi
methodret result!
browser_err:
throw "Error executing script.",60
methodend
rem /**
rem * Start count down timer
rem *
rem * When the timer reaches 0 then the queue will be flushed
rem *
rem * @return GxExecutor the executor instance
rem */
method protected GxExecutor startTimer()
id! = str(#this!) + "onFlush"
BBjAPI().createTimer(id!, (#getRate() / 1000), #this!, "onFlush")
methodret #this!
methodend
rem /**
rem * Stop last created timer if any , preventing the executor from
rem * reaching the point where it needs to flush its content
rem *
rem * @return GxExecutor the executor instance
rem */
method protected GxExecutor endTimer()
id! = str(#this!) + "onFlush"
BBjAPI().removeTimer(id! , err=*next)
methodret #this!
methodend
classend