rotor-framework 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +120 -0
  3. package/package.json +59 -0
  4. package/src/source/RotorFramework.bs +654 -0
  5. package/src/source/RotorFrameworkTask.bs +278 -0
  6. package/src/source/base/BaseModel.bs +52 -0
  7. package/src/source/base/BasePlugin.bs +48 -0
  8. package/src/source/base/BaseReducer.bs +184 -0
  9. package/src/source/base/BaseStack.bs +92 -0
  10. package/src/source/base/BaseViewModel.bs +124 -0
  11. package/src/source/base/BaseWidget.bs +104 -0
  12. package/src/source/base/DispatcherCreator.bs +193 -0
  13. package/src/source/base/DispatcherExternal.bs +260 -0
  14. package/src/source/base/ListenerForDispatchers.bs +246 -0
  15. package/src/source/engine/Constants.bs +74 -0
  16. package/src/source/engine/animator/Animator.bs +334 -0
  17. package/src/source/engine/builder/Builder.bs +213 -0
  18. package/src/source/engine/builder/NodePool.bs +236 -0
  19. package/src/source/engine/builder/PluginAdapter.bs +139 -0
  20. package/src/source/engine/builder/PostProcessor.bs +331 -0
  21. package/src/source/engine/builder/Processor.bs +156 -0
  22. package/src/source/engine/builder/Tree.bs +278 -0
  23. package/src/source/engine/builder/TreeBase.bs +313 -0
  24. package/src/source/engine/builder/WidgetCreate.bs +322 -0
  25. package/src/source/engine/builder/WidgetRemove.bs +72 -0
  26. package/src/source/engine/builder/WidgetUpdate.bs +113 -0
  27. package/src/source/engine/providers/Dispatcher.bs +72 -0
  28. package/src/source/engine/providers/DispatcherProvider.bs +95 -0
  29. package/src/source/engine/services/I18n.bs +169 -0
  30. package/src/source/libs/animate/Animate.bs +753 -0
  31. package/src/source/libs/animate/LICENSE.txt +21 -0
  32. package/src/source/plugins/DispatcherProviderPlugin.bs +127 -0
  33. package/src/source/plugins/FieldsPlugin.bs +180 -0
  34. package/src/source/plugins/FocusPlugin.bs +1522 -0
  35. package/src/source/plugins/FontStylePlugin.bs +159 -0
  36. package/src/source/plugins/ObserverPlugin.bs +548 -0
  37. package/src/source/utils/ArrayUtils.bs +495 -0
  38. package/src/source/utils/GeneralUtils.bs +181 -0
  39. package/src/source/utils/NodeUtils.bs +180 -0
@@ -0,0 +1,331 @@
1
+ ' ===== POST PROCESSOR =====
2
+ namespace Rotor.ViewBuilder
3
+
4
+ ' =====================================================================
5
+ ' postProcessBuffer - Manages lifecycle hook buffers with priority-based execution ordering. Maintains separate buffers for root and default priority processes, organizing hooks by lifecycle type for sequential execution.
6
+ ' =====================================================================
7
+ class postProcessBuffer
8
+
9
+ frameworkInstance as Rotor.Framework
10
+
11
+ buffers = invalid
12
+
13
+ hookTypeIterationUsageFlags = invalid
14
+
15
+ orderedLifeCycleHookType = invalid
16
+
17
+ orderedHookPriorities = invalid
18
+
19
+ ' ---------------------------------------------------------------------
20
+ ' new - Initializes the instance
21
+ '
22
+ ' @description Initializes buffer structures and lifecycle hook ordering
23
+ ' ---------------------------------------------------------------------
24
+ sub new()
25
+ ' initialize ordered hook collections
26
+ m.buffers = {}
27
+ m.hookTypeIterationUsageFlags = {}
28
+
29
+ m.orderedLifeCycleHookType = []
30
+ m.orderedLifeCycleHookType.push(Rotor.Const.LifeCycleHookType.APPEND_CHILD)
31
+ m.orderedLifeCycleHookType.push(Rotor.Const.LifeCycleHookType.REINDEX_CHILD)
32
+ m.orderedLifeCycleHookType.push(Rotor.Const.LifeCycleHookType.BEFORE_MOUNT)
33
+ m.orderedLifeCycleHookType.push(Rotor.Const.LifeCycleHookType.MOUNTED)
34
+ m.orderedLifeCycleHookType.push(Rotor.Const.LifeCycleHookType.AFTER_MOUNTED)
35
+ m.orderedLifeCycleHookType.push(Rotor.Const.LifeCycleHookType.BEFORE_UPDATE)
36
+ m.orderedLifeCycleHookType.push(Rotor.Const.LifeCycleHookType.UPDATED)
37
+ m.orderedLifeCycleHookType.push(Rotor.Const.LifeCycleHookType.VIEWMODEL_STATE_UPDATE)
38
+ m.orderedLifeCycleHookType.push(Rotor.Const.LifeCycleHookType.AFTER_UPDATED)
39
+ m.orderedLifeCycleHookType.push(Rotor.Const.LifeCycleHookType.BEFORE_DESTROY)
40
+ m.orderedLifeCycleHookType.push(Rotor.Const.LifeCycleHookType.REMOVE_CHILD)
41
+ m.orderedLifeCycleHookType.push(Rotor.Const.LifeCycleHookType.DELETE_WIDGET)
42
+
43
+ m.orderedHookPriorities = []
44
+ m.orderedHookPriorities.push(Rotor.Const.HookPriorityTypes.DEFAULT)
45
+ m.orderedHookPriorities.push(Rotor.Const.HookPriorityTypes.ROOT)
46
+
47
+ ' initialize buffers for prioritized (root) and default (default) items
48
+ m.createLifeCycleBuffers()
49
+ end sub
50
+
51
+ ' ---------------------------------------------------------------------
52
+ ' createLifeCycleBuffers - Creates buffer structures for all priority types
53
+ ' ---------------------------------------------------------------------
54
+ sub createLifeCycleBuffers()
55
+ for each priority in m.orderedHookPriorities
56
+ m.buffers[priority] = m.createBuffers()
57
+ end for
58
+ end sub
59
+
60
+ ' ---------------------------------------------------------------------
61
+ '
62
+
63
+ ' clearLifeCycleBuffers - Clears all lifecycle buffers and iteration flags
64
+ '
65
+ ' ---------------------------------------------------------------------
66
+ sub clearLifeCycleBuffers()
67
+ for each priority in m.orderedHookPriorities
68
+ m.clearBuffers(m.buffers[priority])
69
+ end for
70
+ ' clear iteration cache
71
+ for each hookType in m.hookTypeIterationUsageFlags
72
+ m.hookTypeIterationUsageFlags[hookType] = false
73
+ end for
74
+ end sub
75
+
76
+ ' ---------------------------------------------------------------------
77
+ ' createBuffers - Creates buffers for all lifecycle hook types
78
+ '
79
+
80
+ ' @returns {object} Buffer object with roList for each hook type
81
+ ' ---------------------------------------------------------------------
82
+ function createBuffers() as object
83
+ buffer = {}
84
+ for each hookType in m.orderedLifeCycleHookType
85
+ buffer[hookType] = CreateObject("roList")
86
+ m.hookTypeIterationUsageFlags[hookType] = false
87
+ end for
88
+ return buffer
89
+ end function
90
+
91
+ ' ---------------------------------------------------------------------
92
+ ' clearBuffers - Clears all buffers in a priority container
93
+ '
94
+
95
+ ' @param {object} priorityContainer - Container with lifecycle hook buffers
96
+ ' ---------------------------------------------------------------------
97
+ sub clearBuffers(priorityContainer)
98
+ for each hookType in m.orderedLifeCycleHookType
99
+ priorityContainer[hookType].Clear()
100
+ end for
101
+ end sub
102
+
103
+ ' ---------------------------------------------------------------------
104
+ ' add - Adds processes to appropriate buffers based on priority and type
105
+ '
106
+
107
+ ' @param {object} newProcesses - Process or array of processes to add
108
+ ' @param {boolean} isHandledRootChild - Whether this is a root child (default: false)
109
+ ' ---------------------------------------------------------------------
110
+ sub add (newProcesses as object, isHandledRootChild = false as boolean)
111
+
112
+ processesToAdd = Rotor.Utils.ensureArray(newProcesses)
113
+
114
+ for each process in processesToAdd
115
+ m.hookTypeIterationUsageFlags[process.hookType] = true
116
+
117
+ widget = process.widget
118
+ isProcessRoot = m.frameworkInstance.builder.widgetTree.isBranchOfAppend(widget) or m.frameworkInstance.builder.widgetTree.isBranchOfRemove(widget)
119
+ isPluginProcess = process?.isPlugin = true
120
+ priorityType = isProcessRoot = true and not isPluginProcess ? Rotor.Const.HookPriorityTypes.ROOT : Rotor.Const.HookPriorityTypes.DEFAULT
121
+
122
+ if isPluginProcess
123
+ m.buffers[priorityType][process.hookType].AddTail(process)
124
+ else
125
+ if process.hookType = Rotor.Const.LifeCycleHookType.APPEND_CHILD or process.hookType = Rotor.Const.LifeCycleHookType.REINDEX_CHILD
126
+ m.buffers[priorityType][process.hookType].AddTail(process)
127
+ else
128
+ m.buffers[priorityType][process.hookType].AddHead(process)
129
+ end if
130
+ end if
131
+
132
+ end for
133
+ end sub
134
+
135
+ ' ---------------------------------------------------------------------
136
+ ' init - Initializes the buffer with framework instance reference
137
+ '
138
+
139
+ ' @param {Rotor.Framework} frameworkInstance - Framework instance reference
140
+ ' ---------------------------------------------------------------------
141
+ sub init(frameworkInstance as Rotor.Framework)
142
+ m.frameworkInstance = frameworkInstance
143
+ end sub
144
+
145
+ ' ---------------------------------------------------------------------
146
+ ' destroy - Cleans up framework instance reference
147
+ ' ---------------------------------------------------------------------
148
+ sub destroy()
149
+ m.frameworkInstance = invalid
150
+ end sub
151
+ end class
152
+
153
+ ' =====================================================================
154
+ ' PostProcessor - Executes lifecycle hooks and plugin processes in priority order. Handles widget lifecycle operations like mount, update, destroy, and manages SceneGraph node operations.
155
+ ' =====================================================================
156
+ class PostProcessor
157
+
158
+ frameworkInstance as Rotor.Framework
159
+
160
+ ' ---------------------------------------------------------------------
161
+ '
162
+
163
+ ' run - Executes all processes from the buffer in priority and hook type order
164
+ '
165
+ ' @param {object} postProcessBuffer - Buffer containing processes to execute
166
+ ' ---------------------------------------------------------------------
167
+ sub run(postProcessBuffer as object)
168
+
169
+ for each priorityType in postProcessBuffer.orderedHookPriorities
170
+ for each hookType in postProcessBuffer.orderedLifeCycleHookType
171
+ if postProcessBuffer.hookTypeIterationUsageFlags[hookType] = true
172
+ processList = postProcessBuffer.buffers[priorityType][hookType]
173
+ processList.ResetIndex()
174
+ process = processList.GetIndex()
175
+ while process <> invalid
176
+ m.executeGeneralProcess(process)
177
+ process = processList.GetIndex()
178
+ end while
179
+ end if
180
+ end for
181
+ end for
182
+
183
+ end sub
184
+
185
+ ' ---------------------------------------------------------------------
186
+ ' executeGeneralProcess - Executes a single process based on its hook type
187
+ '
188
+
189
+ ' @param {object} process - Process object with hookType and widget
190
+ ' ---------------------------------------------------------------------
191
+ sub executeGeneralProcess(process as object)
192
+ widget = process.widget
193
+
194
+ if process?.isPlugin = true
195
+ pluginHook = m.frameworkInstance.builder.pluginAdapter.pluginHooks[process.hookType][process.pluginKey] ' array of handlers
196
+ if process.hookType = Rotor.Const.LifeCycleHookType.BEFORE_UPDATE or process.hookType = Rotor.Const.LifeCycleHookType.AFTER_UPDATED
197
+ m.runPluginHookHandler(process.hookType, pluginHook, widget, process.newValue, process.oldValue)
198
+ else
199
+ m.runPluginHookHandler(process.hookType, pluginHook, widget)
200
+ end if
201
+
202
+ else if process.hookType = Rotor.Const.LifeCycleHookType.APPEND_CHILD
203
+ m.appendNodeAtZIndex(process)
204
+ widget.Delete("markedToAppend")
205
+
206
+ else if process.hookType = Rotor.Const.LifeCycleHookType.REINDEX_CHILD
207
+ parentNode = widget.parent.node
208
+ parentNode.removeChild(widget.node)
209
+ m.appendNodeAtZIndex(process)
210
+
211
+ else if process.hookType = Rotor.Const.LifeCycleHookType.REMOVE_CHILD
212
+ parentNode = widget.parent.node
213
+ parentNode.removeChild(widget.node)
214
+ if process?.shouldSkipNodePool = invalid or process.shouldSkipNodePool = false
215
+ widget.node = m.frameworkInstance.builder.nodePool.releaseNodeBranch(widget.node)
216
+ end if
217
+ widget.node = invalid
218
+
219
+ else if process.hookType = Rotor.Const.LifeCycleHookType.MOUNTED
220
+ if widget.onMountWidget <> invalid
221
+ widget.onMountWidget()
222
+ end if
223
+ if widget?.isViewModel = true
224
+ widget.onMountView()
225
+ end if
226
+
227
+ else if process.hookType = Rotor.Const.LifeCycleHookType.UPDATED
228
+ widget.onUpdateWidget()
229
+
230
+ else if process.hookType = Rotor.Const.LifeCycleHookType.VIEWMODEL_STATE_UPDATE
231
+ widget.setProps(process.props)
232
+
233
+ else if process.hookType = Rotor.Const.LifeCycleHookType.DELETE_WIDGET
234
+ if widget.onDestroyWidget <> invalid
235
+ widget.onDestroyWidget()
236
+ end if
237
+ if widget?.isViewModel = true
238
+ widget.onDestroyView()
239
+ end if
240
+ m.frameworkInstance.builder.widgetTree.remove(widget.HID)
241
+
242
+ end if
243
+ end sub
244
+
245
+ ' ---------------------------------------------------------------------
246
+ ' runPluginHookHandler - Executes plugin hook handler with appropriate parameters
247
+ '
248
+
249
+ ' @param {string} LifeCycleHookTypeType - Lifecycle hook type identifier
250
+ ' @param {object} pluginHook - Plugin hook configuration
251
+ ' @param {object} widget - Widget instance (default: invalid)
252
+ ' @param {dynamic} newValue - New value for update hooks (default: invalid)
253
+ ' @param {dynamic} oldValue - Old value for update hooks (default: invalid)
254
+ ' ---------------------------------------------------------------------
255
+ sub runPluginHookHandler(LifeCycleHookTypeType as string, pluginHook as object, widget = invalid as object, newValue = invalid as dynamic, oldValue = invalid as dynamic)
256
+ pluginKey = pluginHook.pluginKey
257
+ scope = m.frameworkInstance.plugins[pluginKey]
258
+ if scope.isEnabled
259
+ if LifeCycleHookTypeType = Rotor.Const.LifeCycleHookType.BEFORE_UPDATE
260
+ pluginHook.handlerFn(scope, widget, newValue, oldValue)
261
+ else
262
+ pluginHook.handlerFn(scope, widget)
263
+ end if
264
+ end if
265
+ end sub
266
+
267
+ ' ---------------------------------------------------------------------
268
+ ' appendNodeAtZIndex - Appends a node to its parent at the correct z-index position
269
+ '
270
+
271
+ ' @param {object} process - Process containing widget and zIndex information
272
+ ' ---------------------------------------------------------------------
273
+ sub appendNodeAtZIndex (process as object)
274
+
275
+ widget = process.widget
276
+ zIndex = process.zIndex
277
+ node = widget.node
278
+ parentNode = widget.parent.node
279
+
280
+ if zIndex = invalid
281
+
282
+ parentNode.appendChild(node)
283
+
284
+ else
285
+
286
+ ' respect zIndex when inserted
287
+ rootChildCount = parentNode.getChildCount()
288
+ siblingNodes = parentNode.getChildren(rootChildCount, 0)
289
+ inserted = false
290
+ index = rootChildCount - 1
291
+
292
+ while index >= 0 and inserted = false
293
+ siblingNodeHID = siblingNodes[index].HID
294
+ siblingWidget = siblingNodeHID <> invalid ? m.frameworkInstance.builder.widgetTree.get(siblingNodeHID) : invalid
295
+ if Rotor.Utils.isInteger(siblingWidget?.zIndex) and siblingWidget?.zIndex <= zIndex
296
+ inserted = true ' loop
297
+ else
298
+ index--
299
+ end if
300
+ end while
301
+ index++
302
+ parentNode.insertChild(node, index) ' insert
303
+ widget.zIndex = zIndex ' store
304
+
305
+ end if
306
+ end sub
307
+
308
+ ' ---------------------------------------------------------------------
309
+ ' init - Initializes the post processor with framework instance reference
310
+ '
311
+
312
+ ' @param {Rotor.Framework} frameworkInstance - Framework instance reference
313
+ ' ---------------------------------------------------------------------
314
+ sub init(frameworkInstance as Rotor.Framework)
315
+ m.frameworkInstance = frameworkInstance
316
+ end sub
317
+
318
+ ' ---------------------------------------------------------------------
319
+ ' destroy - Cleans up framework instance reference
320
+ '
321
+ ' ---------------------------------------------------------------------
322
+ sub destroy()
323
+ m.frameworkInstance = invalid
324
+ end sub
325
+
326
+ end class
327
+
328
+
329
+
330
+
331
+ end namespace
@@ -0,0 +1,156 @@
1
+ namespace Rotor.ViewBuilder
2
+
3
+ ' =====================================================================
4
+ ' Processor - Core processor that orchestrates widget lifecycle operations. Routes widget configurations to appropriate handlers (create, update, remove) and recursively processes widget trees.
5
+ ' =====================================================================
6
+ class Processor
7
+
8
+ createWidget = Rotor.ViewBuilder.CreateWidget
9
+ updateWidget = Rotor.ViewBuilder.UpdateWidget
10
+ removeWidget = Rotor.ViewBuilder.RemoveWidget
11
+
12
+ frameworkInstance as Rotor.Framework
13
+
14
+ ' ---------------------------------------------------------------------
15
+ ' childProcessor - Processes a single widget configuration (create, update, or remove)
16
+ '
17
+
18
+ ' @param {object} postProcessBuffer - Buffer for lifecycle hooks
19
+ ' @param {object} config - Widget configuration object
20
+ ' @param {string} parentHID - Parent's Hierarchical ID (default: "0")
21
+ ' @param {boolean} createFlow - Whether in create-only mode
22
+ ' @param {object} params - Processing parameters (default: {})
23
+ ' @returns {object} Post-process buffer reference
24
+ ' ---------------------------------------------------------------------
25
+ function childProcessor(postProcessBuffer as object, config as object, parentHID = "0" as string, createFlow = false, params = {} as object) as object
26
+
27
+ if config?.parentHID <> invalid and config?.parentHID <> "0" then parentHID = config.parentHID
28
+
29
+ if createFlow = true
30
+ widgets = invalid
31
+ else if config.doesExist("HID")
32
+ widgets = [m.frameworkInstance.builder.widgetTree.getByHID(config.HID)]
33
+ else
34
+ widgets = m.frameworkInstance.builder.widgetTree.find(config.id, parentHID)
35
+ end if
36
+
37
+
38
+ if widgets = invalid
39
+ result = m.createWidget(postProcessBuffer, config, parentHID)
40
+ newParentHID = result.HID
41
+ newChildren = result.children
42
+
43
+ ' Run builder processor
44
+ if newChildren <> invalid and newChildren.Count() > 0
45
+ m.run(postProcessBuffer, newParentHID, newChildren, params, true)
46
+ end if
47
+ else
48
+
49
+ for each widget in widgets
50
+
51
+ if config?.markedToRemove = true
52
+
53
+ result = m.removeWidget(postProcessBuffer, widget, config)
54
+
55
+ else
56
+
57
+ result = m.updateWidget(postProcessBuffer, widget, config)
58
+
59
+ end if
60
+
61
+ newChildren = result.children
62
+ newParentHID = result.HID
63
+
64
+ if newChildren <> invalid
65
+ m.run(postProcessBuffer, newParentHID, newChildren, params, createFlow)
66
+ end if
67
+
68
+ end for
69
+
70
+ end if
71
+
72
+ return postProcessBuffer
73
+
74
+ end function
75
+
76
+ ' ---------------------------------------------------------------------
77
+ ' run - Main entry point for processing widget configurations
78
+ '
79
+
80
+ ' @param {object} postProcessBuffer - Buffer for lifecycle hooks
81
+ ' @param {string} parentHID - Parent's Hierarchical ID
82
+ ' @param {object} children - Child widget configurations
83
+ ' @param {object} params - Processing parameters (default: {})
84
+ ' @param {boolean} createFlow - Whether in create-only mode (default: false)
85
+ ' ---------------------------------------------------------------------
86
+ sub run(postProcessBuffer as object, parentHID as string, children as object, params = {} as object, createFlow = false as boolean)
87
+ if children.Count() = 0 then return
88
+
89
+ parsedConfigArray = Rotor.Utils.ensureArray(children)
90
+
91
+ ' check if should removed
92
+ if params?.allowRemove = true
93
+ parentWidget = m.frameworkInstance.builder.widgetTree.getByHID(parentHID)
94
+ ' if parentWidget <> invalid
95
+ for each existingId in parentWidget.children
96
+ if -1 = Rotor.Utils.findInArrayByKey(parsedConfigArray, "id", existingId)
97
+ parsedConfigArray.push({
98
+ id: existingId,
99
+ HID: parentWidget.children[existingId].HID,
100
+ parentHID: parentWidget.children[existingId].parentHID,
101
+ markedToRemove: true
102
+ })
103
+ end if
104
+ end for
105
+ end if
106
+
107
+ if parsedConfigArray <> invalid and parsedConfigArray.Count() > 0
108
+ for each config in parsedConfigArray
109
+ if config <> invalid
110
+ m.checkIdAutoId(config)
111
+ m.childProcessor(postProcessBuffer, config, parentHID, createFlow, params)
112
+ end if
113
+ end for
114
+
115
+ end if
116
+
117
+ end sub
118
+
119
+ ' ---------------------------------------------------------------------
120
+ ' checkIdAutoId - Ensures widget has an ID, generating one if missing
121
+ '
122
+
123
+ ' @param {object} config - Widget configuration object
124
+ ' @returns {object} Updated configuration with guaranteed ID
125
+ ' ---------------------------------------------------------------------
126
+ function checkIdAutoId(config as object) as object
127
+ hasHID = config.DoesExist("HID")
128
+ if not hasHID and (config.id = invalid or config.id = "")
129
+ id = "ID-" + Rotor.Utils.getUUID() ' generate readable id if missing (This is not the engine's generated HID, this id is the "readable" id)
130
+ config.id = id
131
+ end if
132
+ return config
133
+ end function
134
+
135
+ ' ---------------------------------------------------------------------
136
+ ' init - Initializes the processor with framework instance reference
137
+ '
138
+
139
+ ' @param {Rotor.Framework} frameworkInstance - Framework instance reference
140
+ ' ---------------------------------------------------------------------
141
+ sub init(frameworkInstance as Rotor.Framework)
142
+ m.frameworkInstance = frameworkInstance
143
+ end sub
144
+
145
+ ' ---------------------------------------------------------------------
146
+ ' destroy - Cleans up framework instance reference
147
+ '
148
+ ' ---------------------------------------------------------------------
149
+ sub destroy()
150
+ m.frameworkInstance = invalid
151
+ end sub
152
+
153
+
154
+ end class
155
+
156
+ end namespace