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.
- package/LICENSE.md +21 -0
- package/README.md +120 -0
- package/package.json +59 -0
- package/src/source/RotorFramework.bs +654 -0
- package/src/source/RotorFrameworkTask.bs +278 -0
- package/src/source/base/BaseModel.bs +52 -0
- package/src/source/base/BasePlugin.bs +48 -0
- package/src/source/base/BaseReducer.bs +184 -0
- package/src/source/base/BaseStack.bs +92 -0
- package/src/source/base/BaseViewModel.bs +124 -0
- package/src/source/base/BaseWidget.bs +104 -0
- package/src/source/base/DispatcherCreator.bs +193 -0
- package/src/source/base/DispatcherExternal.bs +260 -0
- package/src/source/base/ListenerForDispatchers.bs +246 -0
- package/src/source/engine/Constants.bs +74 -0
- package/src/source/engine/animator/Animator.bs +334 -0
- package/src/source/engine/builder/Builder.bs +213 -0
- package/src/source/engine/builder/NodePool.bs +236 -0
- package/src/source/engine/builder/PluginAdapter.bs +139 -0
- package/src/source/engine/builder/PostProcessor.bs +331 -0
- package/src/source/engine/builder/Processor.bs +156 -0
- package/src/source/engine/builder/Tree.bs +278 -0
- package/src/source/engine/builder/TreeBase.bs +313 -0
- package/src/source/engine/builder/WidgetCreate.bs +322 -0
- package/src/source/engine/builder/WidgetRemove.bs +72 -0
- package/src/source/engine/builder/WidgetUpdate.bs +113 -0
- package/src/source/engine/providers/Dispatcher.bs +72 -0
- package/src/source/engine/providers/DispatcherProvider.bs +95 -0
- package/src/source/engine/services/I18n.bs +169 -0
- package/src/source/libs/animate/Animate.bs +753 -0
- package/src/source/libs/animate/LICENSE.txt +21 -0
- package/src/source/plugins/DispatcherProviderPlugin.bs +127 -0
- package/src/source/plugins/FieldsPlugin.bs +180 -0
- package/src/source/plugins/FocusPlugin.bs +1522 -0
- package/src/source/plugins/FontStylePlugin.bs +159 -0
- package/src/source/plugins/ObserverPlugin.bs +548 -0
- package/src/source/utils/ArrayUtils.bs +495 -0
- package/src/source/utils/GeneralUtils.bs +181 -0
- package/src/source/utils/NodeUtils.bs +180 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import "Processor.bs"
|
|
2
|
+
import "PostProcessor.bs"
|
|
3
|
+
import "NodePool.bs"
|
|
4
|
+
import "Tree.bs"
|
|
5
|
+
import "../../base/BaseWidget.bs"
|
|
6
|
+
import "WidgetCreate.bs"
|
|
7
|
+
import "WidgetUpdate.bs"
|
|
8
|
+
import "WidgetRemove.bs"
|
|
9
|
+
import "PluginAdapter.bs"
|
|
10
|
+
|
|
11
|
+
namespace Rotor.ViewBuilder
|
|
12
|
+
|
|
13
|
+
' =====================================================================
|
|
14
|
+
' Builder - Core ViewBuilder engine that orchestrates widget lifecycle operations
|
|
15
|
+
'
|
|
16
|
+
' Manages widget tree, node pool, plugin adapter, and rendering queue.
|
|
17
|
+
' Handles create, update, and remove operations with post-processing support.
|
|
18
|
+
' =====================================================================
|
|
19
|
+
class Builder
|
|
20
|
+
|
|
21
|
+
widgetTree = new Rotor.ViewBuilder.WidgetTree()
|
|
22
|
+
|
|
23
|
+
pluginAdapter = new Rotor.ViewBuilder.pluginAdapter()
|
|
24
|
+
|
|
25
|
+
processor = new Rotor.ViewBuilder.Processor()
|
|
26
|
+
postProcessor = new Rotor.ViewBuilder.PostProcessor()
|
|
27
|
+
postProcessBuffer = new Rotor.ViewBuilder.postProcessBuffer()
|
|
28
|
+
|
|
29
|
+
nodePool = new Rotor.ViewBuilder.NodePool()
|
|
30
|
+
|
|
31
|
+
frameworkInstance as Rotor.Framework
|
|
32
|
+
|
|
33
|
+
isRenderProcessing = false
|
|
34
|
+
renderQueue = []
|
|
35
|
+
callbackQueue = []
|
|
36
|
+
|
|
37
|
+
' ---------------------------------------------------------------------
|
|
38
|
+
' init - Initializes the builder and all its subsystems
|
|
39
|
+
'
|
|
40
|
+
' @param {object} frameworkInstance - Reference to the framework instance
|
|
41
|
+
'
|
|
42
|
+
sub init(frameworkInstance as object)
|
|
43
|
+
m.frameworkInstance = frameworkInstance
|
|
44
|
+
m.nodePool.init(frameworkInstance)
|
|
45
|
+
m.widgetTree.init()
|
|
46
|
+
m.pluginAdapter.init(frameworkInstance)
|
|
47
|
+
m.processor.init(frameworkInstance)
|
|
48
|
+
m.postProcessor.init(frameworkInstance)
|
|
49
|
+
m.postProcessBuffer.init(frameworkInstance)
|
|
50
|
+
end sub
|
|
51
|
+
|
|
52
|
+
' ---------------------------------------------------------------------
|
|
53
|
+
' destroy - Destroys the builder and cleans up all resources
|
|
54
|
+
'
|
|
55
|
+
sub destroy()
|
|
56
|
+
' remove all widgets
|
|
57
|
+
rootKeys = m.widgetTree.tree.children.Keys()
|
|
58
|
+
m.erase(rootKeys, true)
|
|
59
|
+
' destroy builder engine
|
|
60
|
+
m.pluginAdapter.destroy()
|
|
61
|
+
m.processor.destroy()
|
|
62
|
+
m.postProcessor.destroy()
|
|
63
|
+
m.postProcessBuffer.destroy()
|
|
64
|
+
m.widgetTree.destroy()
|
|
65
|
+
m.nodePool.destroy()
|
|
66
|
+
' remove references
|
|
67
|
+
m.frameworkInstance = invalid
|
|
68
|
+
end sub
|
|
69
|
+
|
|
70
|
+
timer = CreateObject("roTimespan")
|
|
71
|
+
|
|
72
|
+
' ---------------------------------------------------------------------
|
|
73
|
+
' renderQueueFlush - Flushes the render queue and processes next queued render
|
|
74
|
+
'
|
|
75
|
+
sub renderQueueFlush()
|
|
76
|
+
if m.renderQueue.Count() > 0
|
|
77
|
+
nextQueuedConfig = m.renderQueue.shift()
|
|
78
|
+
m.renderProcessor(nextQueuedConfig.payload, nextQueuedConfig.params, true)
|
|
79
|
+
end if
|
|
80
|
+
end sub
|
|
81
|
+
|
|
82
|
+
' ---------------------------------------------------------------------
|
|
83
|
+
' render - Public render method that processes payloads through the render processor
|
|
84
|
+
'
|
|
85
|
+
' @param {dynamic} payloads - Widget configuration payload(s) to render
|
|
86
|
+
' @param {object} params - Optional rendering parameters (default: {})
|
|
87
|
+
'
|
|
88
|
+
sub render(payloads as dynamic, params = {} as object)
|
|
89
|
+
' for each payload in Rotor.Utils.ensureArray(payloads)
|
|
90
|
+
' m.renderProcessor(payload, params)
|
|
91
|
+
m.renderProcessor(payloads, params)
|
|
92
|
+
' end for
|
|
93
|
+
end sub
|
|
94
|
+
|
|
95
|
+
' ---------------------------------------------------------------------
|
|
96
|
+
' renderProcessor - Core rendering processor that handles queuing and execution
|
|
97
|
+
'
|
|
98
|
+
' @param {dynamic} payload - Widget configuration payload to process
|
|
99
|
+
' @param {object} params - Rendering parameters (default: {})
|
|
100
|
+
' @param {boolean} isNextProcess - Whether this is next in queue (default: false)
|
|
101
|
+
'
|
|
102
|
+
sub renderProcessor(payload as dynamic, params = {} as object, isNextProcess = false as boolean)
|
|
103
|
+
' call custom callback
|
|
104
|
+
if Rotor.Utils.isValid(params.callback)
|
|
105
|
+
m.callbackQueue.push({
|
|
106
|
+
callback: params.callback,
|
|
107
|
+
callbackScope: params.callbackScope
|
|
108
|
+
})
|
|
109
|
+
params.delete("callback")
|
|
110
|
+
params.delete("callbackScope")
|
|
111
|
+
end if
|
|
112
|
+
|
|
113
|
+
renderingDisabled = m.frameworkInstance.enableRendering = false and not(params?.enableRenderBeforeReady ?? false)
|
|
114
|
+
if (m.isRenderProcessing = true and isNextProcess = false) or renderingDisabled
|
|
115
|
+
m.renderQueue.push({
|
|
116
|
+
payload: payload,
|
|
117
|
+
params: params
|
|
118
|
+
})
|
|
119
|
+
return
|
|
120
|
+
end if
|
|
121
|
+
m.isRenderProcessing = true
|
|
122
|
+
|
|
123
|
+
m.timer.Mark()
|
|
124
|
+
m.processor.run(m.postProcessBuffer, "0", payload, params)
|
|
125
|
+
m.timer.Mark()
|
|
126
|
+
m.postProcessor.run(m.postProcessBuffer)
|
|
127
|
+
m.postProcessBuffer.clearLifeCycleBuffers()
|
|
128
|
+
|
|
129
|
+
if m.renderQueue.Count() > 0
|
|
130
|
+
nextQueuedConfig = m.renderQueue.shift()
|
|
131
|
+
m.renderProcessor(nextQueuedConfig.payload, nextQueuedConfig.params, true)
|
|
132
|
+
else
|
|
133
|
+
|
|
134
|
+
m.isRenderProcessing = false
|
|
135
|
+
|
|
136
|
+
while m.callbackQueue.Count() > 0
|
|
137
|
+
callbackObj = m.callbackQueue.shift()
|
|
138
|
+
Rotor.Utils.callbackScoped(callbackObj.callback, callbackObj.callbackScope)
|
|
139
|
+
callbackObj.callbackScope = invalid
|
|
140
|
+
end while
|
|
141
|
+
|
|
142
|
+
end if
|
|
143
|
+
|
|
144
|
+
end sub
|
|
145
|
+
|
|
146
|
+
' ---------------------------------------------------------------------
|
|
147
|
+
' erase - Erases widgets from the tree by ID or configuration
|
|
148
|
+
'
|
|
149
|
+
' @param {dynamic} payload - Widget ID(s) or configuration object(s) to erase
|
|
150
|
+
' @param {boolean} shouldSkipNodePool - Whether to skip returning nodes to pool (default: false)
|
|
151
|
+
' @param {string} HID - Hierarchical ID context for search (default: "0")
|
|
152
|
+
'
|
|
153
|
+
sub erase (payload as dynamic, shouldSkipNodePool = false as boolean, HID = "0" as string)
|
|
154
|
+
|
|
155
|
+
' normalize shortcuts
|
|
156
|
+
|
|
157
|
+
identifiersToErase = []
|
|
158
|
+
if Rotor.Utils.isString(payload)
|
|
159
|
+
identifiersToErase.push(payload)
|
|
160
|
+
else if Rotor.Utils.isArray(payload)
|
|
161
|
+
for each item in payload
|
|
162
|
+
if Rotor.Utils.isString(item)
|
|
163
|
+
identifiersToErase.push(item)
|
|
164
|
+
else if Rotor.Utils.isAssociativeArray(item)
|
|
165
|
+
identifiersToErase.push(item?.id)
|
|
166
|
+
end if
|
|
167
|
+
end for
|
|
168
|
+
else if Rotor.Utils.isAssociativeArray(payload)
|
|
169
|
+
for each key in payload
|
|
170
|
+
if key = "id"
|
|
171
|
+
identifiersToErase.push(key)
|
|
172
|
+
else
|
|
173
|
+
identifiersToErase.push(payload[key])
|
|
174
|
+
end if
|
|
175
|
+
end for
|
|
176
|
+
end if
|
|
177
|
+
|
|
178
|
+
widgetsToRemove = []
|
|
179
|
+
|
|
180
|
+
for each id in identifiersToErase
|
|
181
|
+
result = m.widgetTree.find(id, HID)
|
|
182
|
+
if result <> invalid
|
|
183
|
+
widgetsToRemove.append(result)
|
|
184
|
+
end if
|
|
185
|
+
end for
|
|
186
|
+
|
|
187
|
+
if widgetsToRemove.Count() > 0
|
|
188
|
+
|
|
189
|
+
renderObject = []
|
|
190
|
+
|
|
191
|
+
for each widget in widgetsToRemove
|
|
192
|
+
|
|
193
|
+
if m.widgetTree.hasByHID(widget.HID)
|
|
194
|
+
renderObject.push({
|
|
195
|
+
HID: widget.HID,
|
|
196
|
+
parentHID: widget.parentHID,
|
|
197
|
+
id: widget.id,
|
|
198
|
+
markedToRemove: true,
|
|
199
|
+
shouldSkipNodePool: shouldSkipNodePool
|
|
200
|
+
})
|
|
201
|
+
end if
|
|
202
|
+
|
|
203
|
+
end for
|
|
204
|
+
' renderObject.Clear()
|
|
205
|
+
m.render(renderObject)
|
|
206
|
+
|
|
207
|
+
end if
|
|
208
|
+
|
|
209
|
+
end sub
|
|
210
|
+
|
|
211
|
+
end class
|
|
212
|
+
|
|
213
|
+
end namespace
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
' ===== NODE POOL =====
|
|
2
|
+
namespace Rotor.ViewBuilder
|
|
3
|
+
|
|
4
|
+
' =====================================================================
|
|
5
|
+
' NodePool - Manages reusable pools of SceneGraph nodes to improve performance. Optimized for pooling Group nodes and types extending Group (like Poster), as well as other common nodes (e.g., Rectangle, Label). Includes node reset logic upon release.
|
|
6
|
+
' =====================================================================
|
|
7
|
+
class NodePool
|
|
8
|
+
|
|
9
|
+
frameworkInstance as Rotor.Framework
|
|
10
|
+
|
|
11
|
+
config = {
|
|
12
|
+
nodePool: [{
|
|
13
|
+
nodeType: "Group",
|
|
14
|
+
amount: 1
|
|
15
|
+
}, {
|
|
16
|
+
nodeType: "Rectangle",
|
|
17
|
+
amount: 1
|
|
18
|
+
}, {
|
|
19
|
+
nodeType: "Poster",
|
|
20
|
+
amount: 1
|
|
21
|
+
}, {
|
|
22
|
+
nodeType: "Label",
|
|
23
|
+
amount: 1
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
pools = {}
|
|
29
|
+
poolInfo = {
|
|
30
|
+
totalAcquiredNodes: 0, ' Configured and acquired nodes from pools
|
|
31
|
+
totalReleasedNodes: 0, ' Released nodes back to pools
|
|
32
|
+
outOfStockNodes: {}, ' Nodes that out of stock
|
|
33
|
+
poolFulness: {} ' Current amount of nodes in each pool
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
' ---------------------------------------------------------------------
|
|
37
|
+
' new - Initializes the instance
|
|
38
|
+
'
|
|
39
|
+
' @description Initializes the node pool
|
|
40
|
+
' ---------------------------------------------------------------------
|
|
41
|
+
sub new()
|
|
42
|
+
end sub
|
|
43
|
+
|
|
44
|
+
' ---------------------------------------------------------------------
|
|
45
|
+
' init - Initializes the pool with framework instance reference
|
|
46
|
+
'
|
|
47
|
+
|
|
48
|
+
' @param {Rotor.Framework} frameworkInstance - Framework instance reference
|
|
49
|
+
' ---------------------------------------------------------------------
|
|
50
|
+
sub init(frameworkInstance as Rotor.Framework)
|
|
51
|
+
m.frameworkInstance = frameworkInstance
|
|
52
|
+
end sub
|
|
53
|
+
|
|
54
|
+
' ---------------------------------------------------------------------
|
|
55
|
+
' destroy - Cleans up framework instance reference and pools
|
|
56
|
+
' ---------------------------------------------------------------------
|
|
57
|
+
sub destroy()
|
|
58
|
+
m.frameworkInstance = invalid
|
|
59
|
+
m.pools.Clear()
|
|
60
|
+
end sub
|
|
61
|
+
|
|
62
|
+
' ---------------------------------------------------------------------
|
|
63
|
+
'
|
|
64
|
+
|
|
65
|
+
' presetNodePool - Presets node pools with specified amounts of each node type
|
|
66
|
+
'
|
|
67
|
+
' @param {object} config - Configuration with nodePool array
|
|
68
|
+
' ---------------------------------------------------------------------
|
|
69
|
+
sub presetNodePool(config)
|
|
70
|
+
Rotor.Utils.deepExtendAA(m.config, config)
|
|
71
|
+
for each thisPool in m.config.nodePool
|
|
72
|
+
for index = 0 to thisPool.amount - 1
|
|
73
|
+
if not m.pools.doesExist(thisPool.nodeType)
|
|
74
|
+
m.pools[thisPool.nodeType] = []
|
|
75
|
+
#if debug
|
|
76
|
+
m.poolInfo.outOfStockNodes[thisPool.nodeType] = 0
|
|
77
|
+
#end if
|
|
78
|
+
end if
|
|
79
|
+
node = CreateObject("roSGNode", thisPool.nodeType)
|
|
80
|
+
m.pools[thisPool.nodeType].push(node)
|
|
81
|
+
end for
|
|
82
|
+
end for
|
|
83
|
+
end sub
|
|
84
|
+
|
|
85
|
+
' ---------------------------------------------------------------------
|
|
86
|
+
' acquireNode - Acquires a node from the pool or creates a new one
|
|
87
|
+
'
|
|
88
|
+
|
|
89
|
+
' @param {string} nodeType - Type of SceneGraph node to acquire
|
|
90
|
+
' @returns {object} SceneGraph node instance
|
|
91
|
+
' ---------------------------------------------------------------------
|
|
92
|
+
function acquireNode(nodeType)
|
|
93
|
+
if m.pools.doesExist(nodeType) and m.pools[nodeType].Count() > 0
|
|
94
|
+
node = m.pools[nodeType].pop()
|
|
95
|
+
#if debug
|
|
96
|
+
m.poolInfo.totalAcquiredNodes++
|
|
97
|
+
#end if
|
|
98
|
+
else
|
|
99
|
+
node = CreateObject("roSGNode", nodeType)
|
|
100
|
+
#if debug
|
|
101
|
+
if m.pools.doesExist(nodeType)
|
|
102
|
+
m.poolInfo.outOfStockNodes[nodeType]++
|
|
103
|
+
end if
|
|
104
|
+
#end if
|
|
105
|
+
end if
|
|
106
|
+
|
|
107
|
+
return node
|
|
108
|
+
end function
|
|
109
|
+
|
|
110
|
+
' ---------------------------------------------------------------------
|
|
111
|
+
' releaseNodeBranch - Recursively releases a node and its children back to pools
|
|
112
|
+
'
|
|
113
|
+
|
|
114
|
+
' @param {object} node - SceneGraph node to release
|
|
115
|
+
' @param {object} parent - Parent node for removal (default: invalid)
|
|
116
|
+
' ---------------------------------------------------------------------
|
|
117
|
+
sub releaseNodeBranch(node as object, parent = invalid as object)
|
|
118
|
+
|
|
119
|
+
children = node.getChildren(-1, 0)
|
|
120
|
+
|
|
121
|
+
if children <> invalid and children.count() > 0
|
|
122
|
+
for each child in children
|
|
123
|
+
m.releaseNodeBranch(child, node)
|
|
124
|
+
end for
|
|
125
|
+
end if
|
|
126
|
+
|
|
127
|
+
nodeType = node.subtype()
|
|
128
|
+
|
|
129
|
+
if m.pools.doesExist(nodeType)
|
|
130
|
+
if parent <> invalid
|
|
131
|
+
parent.removeChild(node)
|
|
132
|
+
end if
|
|
133
|
+
m.resetNode(node)
|
|
134
|
+
m.pools[nodeType].push(node)
|
|
135
|
+
|
|
136
|
+
#if debug
|
|
137
|
+
m.poolInfo.totalReleasedNodes++
|
|
138
|
+
#end if
|
|
139
|
+
end if
|
|
140
|
+
|
|
141
|
+
end sub
|
|
142
|
+
|
|
143
|
+
' ---------------------------------------------------------------------
|
|
144
|
+
' resetNode - Resets a node's properties to default values before returning to pool
|
|
145
|
+
'
|
|
146
|
+
|
|
147
|
+
' @param {object} node - SceneGraph node to reset
|
|
148
|
+
' @private
|
|
149
|
+
' ---------------------------------------------------------------------
|
|
150
|
+
private sub resetNode(node as object)
|
|
151
|
+
if node = invalid then return
|
|
152
|
+
|
|
153
|
+
nodeType = node.subtype()
|
|
154
|
+
|
|
155
|
+
node.visible = true
|
|
156
|
+
node.opacity = 1.0
|
|
157
|
+
node.translation = [0.0, 0.0]
|
|
158
|
+
node.rotation = 0.0
|
|
159
|
+
node.scale = [1.0, 1.0]
|
|
160
|
+
node.scaleRotateCenter = [0.0, 0.0]
|
|
161
|
+
node.inheritParentTransform = true
|
|
162
|
+
node.inheritParentOpacity = true
|
|
163
|
+
node.muteAudioGuide = false
|
|
164
|
+
node.renderPass = 0
|
|
165
|
+
node.enableRenderTracking = false
|
|
166
|
+
' TODO: test below properties to reset
|
|
167
|
+
' node.childRenderOrder = "renderLast"
|
|
168
|
+
' node.clippingRect = [0.0, 0.0, 0.0, 0.0]
|
|
169
|
+
|
|
170
|
+
if nodeType = "Rectangle"
|
|
171
|
+
node.setFields({
|
|
172
|
+
color: "#FFFFFFFF",
|
|
173
|
+
width: 0,
|
|
174
|
+
height: 0,
|
|
175
|
+
blendingEnabled: true
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
else if nodeType = "Poster"
|
|
179
|
+
node.setFields({
|
|
180
|
+
uri: "",
|
|
181
|
+
width: 0,
|
|
182
|
+
height: 0,
|
|
183
|
+
loadWidth: 0,
|
|
184
|
+
loadHeight: 0,
|
|
185
|
+
blendColor: "#FFFFFFFF",
|
|
186
|
+
loadDisplayMode: "noScale",
|
|
187
|
+
loadSync: false,
|
|
188
|
+
loadingBitmapUri: "",
|
|
189
|
+
failedBitmapUri: "",
|
|
190
|
+
loadingBitmapOpacity: 1.0,
|
|
191
|
+
failedBitmapOpacity: 1.0
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
else if nodeType = "Label"
|
|
195
|
+
node.setFields({
|
|
196
|
+
text: "",
|
|
197
|
+
color: "#FFFFFFFF",
|
|
198
|
+
horizAlign: "left",
|
|
199
|
+
vertAlign: "top",
|
|
200
|
+
width: 0,
|
|
201
|
+
height: 0,
|
|
202
|
+
wrap: false,
|
|
203
|
+
numLines: 0,
|
|
204
|
+
lineSpacing: 0.0,
|
|
205
|
+
maxLines: 0,
|
|
206
|
+
ellipsisText: "",
|
|
207
|
+
font: "font:MediumSystemFont"
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
end if
|
|
211
|
+
end sub
|
|
212
|
+
|
|
213
|
+
' ---------------------------------------------------------------------
|
|
214
|
+
' getNodePoolInfo - Gets node pool statistics (debug mode only)
|
|
215
|
+
'
|
|
216
|
+
|
|
217
|
+
' @returns {object} Pool information with counts and stats
|
|
218
|
+
' ---------------------------------------------------------------------
|
|
219
|
+
function getNodePoolInfo()
|
|
220
|
+
info = {}
|
|
221
|
+
#if debug
|
|
222
|
+
for each nodeType in m.pools
|
|
223
|
+
m.poolInfo.poolFulness[nodeType] = m.pools[nodeType].Count()
|
|
224
|
+
end for
|
|
225
|
+
info = m.poolInfo
|
|
226
|
+
#end if
|
|
227
|
+
return info
|
|
228
|
+
end function
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
end class
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
end namespace
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
namespace Rotor.ViewBuilder
|
|
2
|
+
|
|
3
|
+
' =====================================================================
|
|
4
|
+
' PluginHookClass - Container for plugin hook metadata and handler function
|
|
5
|
+
' =====================================================================
|
|
6
|
+
class PluginHookClass
|
|
7
|
+
|
|
8
|
+
pluginKey as string
|
|
9
|
+
handlerFn as function
|
|
10
|
+
|
|
11
|
+
' ---------------------------------------------------------------------
|
|
12
|
+
' new - Initializes the instance
|
|
13
|
+
'
|
|
14
|
+
' @description Initializes plugin hook with key and handler
|
|
15
|
+
' @param {object} config - Configuration with pluginKey and handlerFn
|
|
16
|
+
' ---------------------------------------------------------------------
|
|
17
|
+
sub new(config)
|
|
18
|
+
m.pluginKey = config.pluginKey
|
|
19
|
+
m.handlerFn = config.handlerFn
|
|
20
|
+
end sub
|
|
21
|
+
|
|
22
|
+
end class
|
|
23
|
+
|
|
24
|
+
' =====================================================================
|
|
25
|
+
' pluginAdapter - Manages plugin registration and lifecycle hook integration. Maintains plugin instances and maps lifecycle hooks to plugin handlers.
|
|
26
|
+
' =====================================================================
|
|
27
|
+
class pluginAdapter
|
|
28
|
+
|
|
29
|
+
plugins as object
|
|
30
|
+
|
|
31
|
+
' ---------------------------------------------------------------------
|
|
32
|
+
' new - Initializes the instance
|
|
33
|
+
'
|
|
34
|
+
' @description Initializes plugin hook storage for all lifecycle types
|
|
35
|
+
' ---------------------------------------------------------------------
|
|
36
|
+
sub new()
|
|
37
|
+
|
|
38
|
+
' dedicated plugin lifecycle hooks
|
|
39
|
+
for each hookType in [
|
|
40
|
+
Rotor.Const.LifeCycleHookType.BEFORE_MOUNT,
|
|
41
|
+
Rotor.Const.LifeCycleHookType.AFTER_MOUNTED,
|
|
42
|
+
Rotor.Const.LifeCycleHookType.BEFORE_UPDATE,
|
|
43
|
+
Rotor.Const.LifeCycleHookType.AFTER_UPDATED,
|
|
44
|
+
Rotor.Const.LifeCycleHookType.BEFORE_DESTROY
|
|
45
|
+
]
|
|
46
|
+
m.pluginHooks[hookType] = {}
|
|
47
|
+
end for
|
|
48
|
+
|
|
49
|
+
end sub
|
|
50
|
+
|
|
51
|
+
' Plugins has limited type of hooks to lifecycle (check the list below)
|
|
52
|
+
pluginHooks = {}
|
|
53
|
+
pluginKeyList = CreateObject("roList")
|
|
54
|
+
|
|
55
|
+
frameworkInstance as Rotor.Framework
|
|
56
|
+
|
|
57
|
+
' ---------------------------------------------------------------------
|
|
58
|
+
' registerPlugins - Registers plugins and their lifecycle hooks with the framework
|
|
59
|
+
'
|
|
60
|
+
|
|
61
|
+
' @param {object} pluginConfig - Plugin configuration object or array
|
|
62
|
+
' ---------------------------------------------------------------------
|
|
63
|
+
sub registerPlugins (pluginConfig as object)
|
|
64
|
+
|
|
65
|
+
plugins = Rotor.Utils.ensureArray(pluginConfig)
|
|
66
|
+
|
|
67
|
+
for each plugin in plugins
|
|
68
|
+
|
|
69
|
+
' Plugin key
|
|
70
|
+
pluginKey = plugin.key
|
|
71
|
+
|
|
72
|
+
' add plugin key to tree viewModelState
|
|
73
|
+
' obj = Rotor.Utils.wrapObject(pluginKey, {})
|
|
74
|
+
|
|
75
|
+
' create workspace for plugin in root of widget tree
|
|
76
|
+
' m.frameworkInstance.builder.widgetTree.tree.extendContext(obj)
|
|
77
|
+
|
|
78
|
+
' Setup hooks
|
|
79
|
+
hooks = plugin.hooks
|
|
80
|
+
if Rotor.Utils.isValid(hooks) and hooks.Count() > 0
|
|
81
|
+
|
|
82
|
+
for each hook in hooks
|
|
83
|
+
pluginHook = new PluginHookClass({
|
|
84
|
+
pluginKey: pluginKey,
|
|
85
|
+
handlerFn: hooks[hook]
|
|
86
|
+
})
|
|
87
|
+
m.pluginHooks[hook][pluginKey] = pluginHook
|
|
88
|
+
end for
|
|
89
|
+
|
|
90
|
+
end if
|
|
91
|
+
|
|
92
|
+
' add plugin instance to viewBuilder
|
|
93
|
+
m.pluginKeyList.AddTail(pluginKey)
|
|
94
|
+
m.frameworkInstance.plugins[pluginKey] = plugin
|
|
95
|
+
m.frameworkInstance.plugins[pluginKey].frameworkInstance = m.frameworkInstance
|
|
96
|
+
if Rotor.Utils.isFunction(m.frameworkInstance.plugins[pluginKey].init)
|
|
97
|
+
m.frameworkInstance.plugins[pluginKey].init()
|
|
98
|
+
end if
|
|
99
|
+
end for
|
|
100
|
+
|
|
101
|
+
end sub
|
|
102
|
+
|
|
103
|
+
' ---------------------------------------------------------------------
|
|
104
|
+
' destroyPlugins - Destroys all registered plugins
|
|
105
|
+
' ---------------------------------------------------------------------
|
|
106
|
+
sub destroyPlugins()
|
|
107
|
+
if m.plugins.Count() > 0
|
|
108
|
+
for each plugin in m.plugins
|
|
109
|
+
plugin.frameworkInstance = invalid
|
|
110
|
+
destroy = plugin.destroy
|
|
111
|
+
if Rotor.Utils.isFunction(plugin.destroy)
|
|
112
|
+
destroy()
|
|
113
|
+
end if
|
|
114
|
+
end for
|
|
115
|
+
end if
|
|
116
|
+
end sub
|
|
117
|
+
|
|
118
|
+
' ---------------------------------------------------------------------
|
|
119
|
+
'
|
|
120
|
+
|
|
121
|
+
' init - Initializes the adapter with framework instance reference
|
|
122
|
+
'
|
|
123
|
+
' @param {object} frameworkInstance - Framework instance reference
|
|
124
|
+
' ---------------------------------------------------------------------
|
|
125
|
+
sub init(frameworkInstance as object)
|
|
126
|
+
m.frameworkInstance = frameworkInstance
|
|
127
|
+
end sub
|
|
128
|
+
|
|
129
|
+
' ---------------------------------------------------------------------
|
|
130
|
+
' destroy - Cleans up framework instance reference
|
|
131
|
+
'
|
|
132
|
+
' ---------------------------------------------------------------------
|
|
133
|
+
sub destroy()
|
|
134
|
+
m.frameworkInstance = invalid
|
|
135
|
+
end sub
|
|
136
|
+
|
|
137
|
+
end class
|
|
138
|
+
|
|
139
|
+
end namespace
|