• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mobalazs / rotor-framework / 18919729013

29 Oct 2025 07:21PM UTC coverage: 85.379% (-0.1%) from 85.479%
18919729013

push

github

mobalazs
fix: update debug setting in bsconfig to enable debugging

1781 of 2086 relevant lines covered (85.38%)

1.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.36
/src/source/engine/builder/WidgetCreate.bs
1
namespace Rotor.ViewBuilder
2

3
    ' =====================================================================
4
    ' createWidget - Creates and initializes a widget instance. Core widget factory function that handles the complete widget creation lifecycle: 1. Widget tree registration 2. Decorator method injection 3. ViewModel initialization (if applicable) 4. SceneGraph node creation 5. Plugin registration and lifecycle hooks
5
    '
6
    ' @param {object} postProcessBuffer - Buffer for deferred plugin/lifecycle operations
7
    ' @param {object} config - Widget configuration object
8
    ' @param {string} parentHID - Parent's Hierarchical ID (default: "0" for root)
9
    ' @returns {object} Widget metadata { HID, children, parentHID, id }
10
    ' =====================================================================
11
    function createWidget(postProcessBuffer as object, config as object, parentHID = "0" as string) as object
12

13
        ' Extract and remove ViewModel class from config
14
        ViewModelClass = config.viewModel
1✔
15
        config.delete("viewModel")
1✔
16

17
        ' =============================================================
18
        ' WIDGET TREE REGISTRATION
19
        ' =============================================================
20

21
        ' Register widget in tree and get HID
22
        widget = m.frameworkInstance.builder.widgetTree.add({
1✔
23
            id: config.id,
24
            parentHID: parentHID
25
        }, ViewModelClass)
26
        HID = widget.HID
1✔
27

28
        ' =============================================================
29
        ' WIDGET DECORATOR METHODS
30
        ' =============================================================
31
        ' These methods provide widget API for tree navigation,
32
        ' rendering, state management, and framework integration
33

34
        ' getFrameworkInstance - Returns framework instance *'
35
        widget.getFrameworkInstance = function() as object
1✔
36
            return GetGlobalAA().rotor_framework_helper.frameworkInstance
37
        end function
38

39
        ' getInfo - Returns framework info *'
40
        widget.getInfo = function() as object
1✔
41
            return m.getFrameworkInstance().getInfo()
42
        end function
43

44
        ' refresh - Refreshes specific widget properties by key paths *'
45
        widget.refresh = sub(featureKeyPaths as object)
1✔
46
            iterateKeyPaths = Rotor.Utils.ensureArray(featureKeyPaths)
47
            refreshObject = {}
48
            for each keyPath in iterateKeyPaths
49
                refreshObject.append(Rotor.Utils.getCloneByKeyPath(m, keyPath))
50
            end for
51
            m.render(refreshObject)
52
        end sub
53

54
        ' getWidget - Finds widget by search pattern from this widget's context *'
55
        widget.getWidget = function(searchPattern as string) as object
1✔
56
            return m.getFrameworkInstance().builder.widgetTree.get(searchPattern, m.HID)
57
        end function
58

59
        ' getSiblingWidget - Gets sibling widget by ID *'
60
        widget.getSiblingWidget = function(id as string) as object
1✔
61
            return m.parent.children[id]
62
        end function
63

64
        ' getViewModel - Returns owning ViewModel (self if ViewModel, or parent VM) *'
65
        widget.getViewModel = function() as object
1✔
66
            if m.isViewModel = true
67
                return m
68
            else
69
                return m.getFrameworkInstance().builder.widgetTree.getByHID(m.vmHID)
70
            end if
71
        end function
72

73
        ' getParentViewModel - Returns parent's ViewModel *'
74
        widget.getParentViewModel = function() as object
1✔
75
            return m.getViewModel().parent.getViewModel()
76
        end function
77

78
        ' getRootWidget - Returns root widget (HID "0") *'
79
        widget.getRootWidget = function() as object
1✔
80
            return m.getFrameworkInstance().builder.widgetTree.getByHID("0")
81
        end function
82

83
        ' findWidgets - Finds multiple widgets by search pattern *'
84
        widget.findWidgets = function(searchPattern as string) as object
1✔
85
            return m.getFrameworkInstance().builder.widgetTree.find(searchPattern, m.HID)
86
        end function
87

88
        ' getChildrenWidgets - Gets child widgets with optional pattern matching *'
89
        widget.getChildrenWidgets = function(matchingPattern = "" as string) as object
1✔
90
            return m.getFrameworkInstance().builder.widgetTree.getChildrenWidgets(m, matchingPattern)
91
        end function
92

93
        ' getSubtreeClone - Creates a clone of widget subtree *'
94
        widget.getSubtreeClone = function(searchPattern = "" as string, keyPathList = [] as object) as object
1✔
95
            if searchPattern = "" then searchPattern = m.HID
96
            return m.getFrameworkInstance().builder.widgetTree.getSubtreeClone(searchPattern, keyPathList, m.parentHID)
97
        end function
98

99
        ' render - Renders widget updates (self, descendants, or children) *'
100
        widget.render = sub(payloads as dynamic, params = {} as object)
1✔
101
            for each payload in Rotor.Utils.ensureArray(payloads)
102
                if payload.DoesExist("id") = false
103
                    ' Self update
104
                    payload.id = m.id
105
                    payload.HID = m.HID
106
                else if payload.id <> m.id
107
                    ' Update descendants starting from this widget
108
                    payload.parentHID = m.HID
109
                else
110
                    ' Update descendants starting from parent widget
111
                    payload.parentHID = m.parentHID
112
                end if
113
            end for
114
            if Rotor.Utils.isValid(params.callback) then params.callbackScope = m
115
            m.getFrameworkInstance().builder.render(payloads, params)
116
        end sub
117

118
        ' erase - Removes widget(s) from tree *'
119
        widget.erase = sub(payloads = invalid as dynamic, shouldSkipNodePool = false as boolean)
1✔
120
            if payloads = invalid
121
                ' Self destroy
122
                payloads = m.HID
123
                parentHID = m.parentHID
124
            else
125
                ' Children destroy
126
                parentHID = m.HID
127
            end if
128
            m.getFrameworkInstance().builder.erase(payloads, shouldSkipNodePool, parentHID)
129
        end sub
130

131
        ' getDispatcher - Gets dispatcher facade by ID *'
132
        widget.getDispatcher = function(dispatcherId as string) as object
1✔
133
            return m.getFrameworkInstance().dispatcherProvider.getFacade(dispatcherId, m)
134
        end function
135

136
        ' animator - Gets animator factory by ID *'
137
        widget.animator = function(animatorId) as object
1✔
138
            return m.getFrameworkInstance().animatorProvider.getFactory(animatorId, m)
139
        end function
140

141
        ' =============================================================
142
        ' VIEWMODEL INITIALIZATION
143
        ' =============================================================
144

145
        if widget.isViewModel = true
2✔
146

147
            ' Merge props from config
148
            if Rotor.Utils.isAssociativeArray(config.props)
3✔
149
                Rotor.Utils.deepExtendAA(widget.props, config.props)
1✔
150
            end if
151

152
            ' Merge viewModelState from config
153
            if Rotor.Utils.isAssociativeArray(config.viewModelState)
3✔
154
                Rotor.Utils.deepExtendAA(widget.viewModelState, config.viewModelState)
1✔
155
            end if
156

157
            ' Setup i18n (l10n)
158
            i18nService = widget.getFrameworkInstance().i18nService
3✔
159
            keysPaths = Rotor.Utils.isString(config.i18n?.path) ? config.i18n.path : Rotor.Utils.isArray(config.i18n?.paths) ? config.i18n.paths : invalid
1✔
160
            widget.viewModelState.l10n = i18nService.getL10n(keysPaths)
1✔
161

162
            ' Include isRTL flag if requested
163
            if config?.i18n?.includeIsRtl = true
2✔
164
                widget.viewModelState.isRTL = i18nService.getIsRtl()
×
165
            end if
166

167
            ' Include locale string if requested
168
            if config?.i18n?.includeLocale = true
2✔
169
                widget.viewModelState.locale = i18nService.getLocale()
×
170
            end if
171

172
            ' Call lifecycle hook before template compilation
173
            widget.onCreateView()
1✔
174

175
            ' Generate template
176
            template = widget.template()
1✔
177

178
            ' Optional template post-processing hook
179
            if Rotor.Utils.isFunction(widget.onTemplateCreated)
3✔
180
                widget.onTemplateCreated(template)
1✔
181
            end if
182

183
            ' Merge template into config
184
            if template <> invalid and template.Count() > 0
3✔
185
                templateChildren = template.children
1✔
186
                template.delete("children")
1✔
187
                config = Rotor.Utils.deepExtendAA(config, template)
1✔
188
                config.children = templateChildren
1✔
189
            end if
190

191
        end if
192

193
        ' =============================================================
194
        ' LIFECYCLE HOOK REGISTRATION
195
        ' =============================================================
196

197
        ' Register custom lifecycle hooks from config
198
        if Rotor.Utils.isFunction(config.onMountWidget)
2✔
199
            widget.onMountWidget = config.onMountWidget
×
200
        end if
201

202
        if Rotor.Utils.isFunction(config.onUpdateWidget)
2✔
203
            widget.onUpdateWidget = config.onUpdateWidget
×
204
        end if
205

206
        if Rotor.Utils.isFunction(config.onDestroyWidget)
2✔
207
            widget.onDestroyWidget = config.onDestroyWidget
×
208
        end if
209

210
        ' Queue onRenderSettled callback
211
        if Rotor.Utils.isFunction(config.onRenderSettled) = true
2✔
212
            m.frameworkInstance.builder.callbackQueue.push({
×
213
                callback: config.onRenderSettled,
214
                callbackScope: widget
215
            })
216
            config.delete("onRenderSettled")
×
217
        end if
218

219
        ' =============================================================
220
        ' SCENEGRAPH NODE CREATION
221
        ' =============================================================
222

223
        ' Get children for processing
224
        if config.children = invalid then config.children = {}
1✔
225
        children = config.children
1✔
226

227
        ' Create SceneGraph node from node pool
3✔
228
        nodeType = Rotor.Utils.isString(config.nodeType) ? config.nodeType : "Group"
1✔
229
        widget.node = m.frameworkInstance.builder.nodePool.acquireNode(nodeType)
1✔
230
        widget.nodeType = nodeType
1✔
231
        widget.markedToAppend = true
1✔
232

233
        ' Debug: Set node ID for scene graph inspector
234
        #if debug
4✔
235
            Rotor.Utils.setCustomFields(widget.node, {
1✔
236
                id: `${widget.id}-${widget.HID}`
237
            }, true, false)
238
        #end if
239

240
        ' =============================================================
241
        ' PLUGIN INTEGRATION
242
        ' =============================================================
243

244
        ' Process plugins and inject addon methods
245
        widgetAddon = {}
1✔
246
        pluginKeyList = m.frameworkInstance.builder.pluginAdapter.pluginKeyList
1✔
247
        pluginKeyList.ResetIndex()
1✔
248
        pluginKey = pluginKeyList.GetIndex()
1✔
249

250
        while pluginKey <> invalid
1✔
251

252
            if config.doesExist(pluginKey)
2✔
253

254
                ' Register plugin lifecycle hooks (beforeMount, afterMounted)
255
                for each LifeCycleHookType in [Rotor.Const.LifeCycleHookType.BEFORE_MOUNT, Rotor.Const.LifeCycleHookType.AFTER_MOUNTED]
1✔
256
                    if m.frameworkInstance.builder.pluginAdapter.pluginHooks[LifeCycleHookType].DoesExist(pluginKey)
2✔
257
                        widget[pluginKey] = config[pluginKey]
1✔
258
                        postProcessBuffer.add({
1✔
259
                            isPlugin: true,
260
                            widget: widget,
261
                            hookType: LifeCycleHookType,
262
                            pluginKey: pluginKey
263
                        })
264
                    end if
265
                end for
266

267
                ' Inject plugin widget methods
268
                plugin = m.frameworkInstance.plugins[pluginKey]
1✔
269
                if Rotor.Utils.isValid(plugin["widgetMethods"])
2✔
270
                    if widgetAddon.plugins = invalid then widgetAddon.plugins = {}
1✔
271
                    if widgetAddon.plugins[pluginKey] = invalid then widgetAddon.plugins[pluginKey] = {
1✔
272
                        pluginKey: pluginKey,
273
                        id: widget.id,
274
                        HID: widget.HID,
275
                        parentHID: widget.parentHID
276
                    }
277
                    widgetAddon.plugins[pluginKey].append(plugin["widgetMethods"])
1✔
278
                end if
279

280
            end if
281

282
            pluginKey = pluginKeyList.GetIndex()
1✔
283
        end while
284

285
        ' Append all plugin addon methods to widget
286
        if widgetAddon.Count() > 0
2✔
287
            widget.append(widgetAddon)
1✔
288
        end if
289

290
        ' =============================================================
291
        ' POST-PROCESS QUEUE
292
        ' =============================================================
293

294
        ' Queue child append operation
295
        appendChildProcess = {
1✔
296
            hookType: Rotor.Const.LifeCycleHookType.APPEND_CHILD,
297
            widget: widget
298
        }
299
        if config.zIndex <> invalid
2✔
300
            appendChildProcess.zIndex = config.zIndex
×
301
        end if
302
        postProcessBuffer.add(appendChildProcess)
1✔
303

304
        ' Queue mounted lifecycle hook
305
        if Rotor.Utils.isFunction(widget.onMountWidget) or widget?.isViewModel = true
2✔
306
            postProcessBuffer.add({
1✔
307
                hookType: Rotor.Const.LifeCycleHookType.MOUNTED,
308
                widget: widget
309
            })
310
        end if
311

312
        ' Return widget metadata for tree processing
313
        return {
1✔
314
            HID: HID,
315
            children: children,
316
            parentHID: parentHID,
317
            id: widget.id
318
        }
319

320
    end function
321

322
end namespace
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc