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

mobalazs / rotor-framework / 19980247662

06 Dec 2025 12:52AM UTC coverage: 85.611% (-0.6%) from 86.229%
19980247662

Pull #10

github

web-flow
Merge f2448421e into 2846dc2eb
Pull Request #10: Feat/url transfer support

2 of 15 new or added lines in 2 files covered. (13.33%)

2 existing lines in 2 files now uncovered.

1773 of 2071 relevant lines covered (85.61%)

1.16 hits per line

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

93.98
/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
       ' Get isRTL flag
100
        widget.isRtl = function() as boolean
1✔
101
            i18nService = m.getFrameworkInstance().i18nService
102
            return i18nService.getIsRtl()
103
        end function
104

105
        ' Get locale string
106
        widget.getLocale = function() as string
1✔
107
            i18nService = m.getFrameworkInstance().i18nService
108
            return i18nService.getLocale()
109
        end function
110

111
        ' render - Renders widget updates (self, descendants, or children) *'
112
        widget.render = sub(payloads as dynamic, params = {} as object)
1✔
113
            for each payload in Rotor.Utils.ensureArray(payloads)
114
                if payload.DoesExist("id") = false
115
                    ' Self update
116
                    payload.id = m.id
117
                    payload.HID = m.HID
118
                else if payload.id <> m.id
119
                    ' Update descendants starting from this widget
120
                    payload.parentHID = m.HID
121
                else
122
                    ' Update descendants starting from parent widget
123
                    payload.parentHID = m.parentHID
124
                end if
125
            end for
126
            if Rotor.Utils.isValid(params.callback) then params.callbackScope = m
127
            m.getFrameworkInstance().builder.render(payloads, params)
128
        end sub
129

130
        ' erase - Removes widget(s) from tree *'
131
        widget.erase = sub(payloads = invalid as dynamic, shouldSkipNodePool = false as boolean)
1✔
132
            if payloads = invalid
133
                ' Self destroy
134
                payloads = m.HID
135
                parentHID = m.parentHID
136
            else
137
                ' Children destroy
138
                parentHID = m.HID
139
            end if
140
            m.getFrameworkInstance().builder.erase(payloads, shouldSkipNodePool, parentHID)
141
        end sub
142

143
        ' getDispatcher - Gets dispatcher facade by ID *'
144
        widget.getDispatcher = function(dispatcherId as string) as object
1✔
145
            return m.getFrameworkInstance().dispatcherProvider.getFacade(dispatcherId, m)
146
        end function
147

148
        ' Dispatch shortcut - Dispatches an event via specific dispatcher'
149
        widget.dispatchTo = sub(dispatcherId as string, dispatchObject as object)
1✔
150
            dispatcherFaced = m.getDispatcher(dispatcherId)
151
            dispatcherFaced.dispatch(dispatchObject)
152
        end sub
153

154
        ' Listen shortcut - Listen to specific dispatcher'
155
        widget.getStateFrom = function(dispatcherId as string)
1✔
156
            dispatcherFaced = m.getDispatcher(dispatcherId)
157
            return dispatcherFaced.getState()
158
        end function
159

160
        ' animator - Gets animator factory by ID *'
161
        widget.animator = function(animatorId) as object
1✔
162
            return m.getFrameworkInstance().animatorProvider.getFactory(animatorId, m)
163
        end function
164

165
        ' =============================================================
166
        ' VIEWMODEL INITIALIZATION
167
        ' =============================================================
168

169
        if widget.isViewModel = true
2✔
170

171
            ' Merge props from config
172
            if Rotor.Utils.isAssociativeArray(config.props)
3✔
173
                Rotor.Utils.deepExtendAA(widget.props, config.props)
1✔
174
            end if
175

176
            ' Merge viewModelState from config
177
            if Rotor.Utils.isAssociativeArray(config.viewModelState)
3✔
178
                Rotor.Utils.deepExtendAA(widget.viewModelState, config.viewModelState)
1✔
179
            end if
180

181
            ' Setup i18n (l10n)
182
            i18nService = widget.getFrameworkInstance().i18nService
3✔
183
            keysPaths = Rotor.Utils.isString(config.i18n?.path) ? config.i18n.path : Rotor.Utils.isArray(config.i18n?.paths) ? config.i18n.paths : invalid
1✔
184
            widget.viewModelState.l10n = i18nService.getL10n(keysPaths)
1✔
185

186
            ' Call lifecycle hook before template compilation
187
            widget.onCreateView()
1✔
188

189
            ' Generate template
190
            template = widget.template()
1✔
191

192
            ' Optional template post-processing hook
193
            if Rotor.Utils.isFunction(widget.onTemplateCreated)
3✔
194
                widget.onTemplateCreated(template)
1✔
195
            end if
196

197
            ' Merge template into config
198
            if template <> invalid and template.Count() > 0
3✔
199
                templateChildren = template.children
1✔
200
                template.delete("children")
1✔
201
                config = Rotor.Utils.deepExtendAA(config, template)
1✔
202
                config.children = templateChildren
1✔
203
            end if
204

205
        end if
206

207
        ' =============================================================
208
        ' LIFECYCLE HOOK REGISTRATION
209
        ' =============================================================
210

211
        ' Register custom lifecycle hooks from config
212
        if Rotor.Utils.isFunction(config.onMountWidget)
2✔
UNCOV
213
            widget.onMountWidget = config.onMountWidget
×
214
        end if
215

216
        if Rotor.Utils.isFunction(config.onUpdateWidget)
2✔
217
            widget.onUpdateWidget = config.onUpdateWidget
1✔
218
        end if
219

220
        if Rotor.Utils.isFunction(config.onDestroyWidget)
2✔
221
            widget.onDestroyWidget = config.onDestroyWidget
×
222
        end if
223

224
        ' Queue onRenderSettled callback
225
        if Rotor.Utils.isFunction(config.onRenderSettled) = true
2✔
226
            m.frameworkInstance.builder.callbackQueue.push({
×
227
                callback: config.onRenderSettled,
228
                callbackScope: widget
229
            })
230
            config.delete("onRenderSettled")
×
231
        end if
232

233
        ' =============================================================
234
        ' SCENEGRAPH NODE CREATION
235
        ' =============================================================
236

237
        ' Get children for processing
238
        if config.children = invalid then config.children = {}
1✔
239
        children = config.children
1✔
240

241
        ' Create SceneGraph node from node pool
3✔
242
        nodeType = Rotor.Utils.isString(config.nodeType) ? config.nodeType : "Group"
1✔
243
        widget.node = m.frameworkInstance.builder.nodePool.acquireNode(nodeType)
1✔
244
        widget.nodeType = nodeType
1✔
245
        widget.markedToAppend = true
1✔
246

247
        ' Debug: Set node ID for scene graph inspector
248
        #if debug
4✔
249
            Rotor.Utils.setCustomFields(widget.node, {
1✔
250
                id: `${widget.id}-${widget.HID}`
251
            }, true, false)
252
        #end if
253

254
        ' =============================================================
255
        ' PLUGIN INTEGRATION
256
        ' =============================================================
257

258
        ' Process plugins and inject addon methods
259
        widgetAddon = {}
1✔
260
        pluginKeyList = m.frameworkInstance.builder.pluginAdapter.pluginKeyList
1✔
261
        pluginKeyList.ResetIndex()
1✔
262
        pluginKey = pluginKeyList.GetIndex()
1✔
263

264
        while pluginKey <> invalid
1✔
265

266
            if config.doesExist(pluginKey)
2✔
267

268
                ' Register plugin lifecycle hooks (beforeMount, afterMounted)
269
                for each LifeCycleHookType in [Rotor.Const.LifeCycleHookType.BEFORE_MOUNT, Rotor.Const.LifeCycleHookType.AFTER_MOUNTED]
1✔
270
                    if m.frameworkInstance.builder.pluginAdapter.pluginHooks[LifeCycleHookType].DoesExist(pluginKey)
2✔
271
                        widget[pluginKey] = config[pluginKey]
1✔
272
                        postProcessBuffer.add({
1✔
273
                            isPlugin: true,
274
                            widget: widget,
275
                            hookType: LifeCycleHookType,
276
                            pluginKey: pluginKey
277
                        })
278
                    end if
279
                end for
280

281
                ' Inject plugin widget methods
282
                plugin = m.frameworkInstance.plugins[pluginKey]
1✔
283
                if Rotor.Utils.isValid(plugin["widgetMethods"])
2✔
284
                    if widgetAddon.plugins = invalid then widgetAddon.plugins = {}
1✔
285
                    if widgetAddon.plugins[pluginKey] = invalid then widgetAddon.plugins[pluginKey] = {
1✔
286
                        pluginKey: pluginKey,
287
                        id: widget.id,
288
                        HID: widget.HID,
289
                        parentHID: widget.parentHID
290
                    }
291
                    widgetAddon.plugins[pluginKey].append(plugin["widgetMethods"])
1✔
292
                end if
293

294
            end if
295

296
            pluginKey = pluginKeyList.GetIndex()
1✔
297
        end while
298

299
        ' Append all plugin addon methods to widget
300
        if widgetAddon.Count() > 0
2✔
301
            widget.append(widgetAddon)
1✔
302
        end if
303

304
        ' =============================================================
305
        ' POST-PROCESS QUEUE
306
        ' =============================================================
307

308
        ' Queue child append operation
309
        appendChildProcess = {
1✔
310
            hookType: Rotor.Const.LifeCycleHookType.APPEND_CHILD,
311
            widget: widget
312
        }
313
        if config.zIndex <> invalid
2✔
314
            appendChildProcess.zIndex = config.zIndex
×
315
        end if
316
        postProcessBuffer.add(appendChildProcess)
1✔
317

318
        ' Queue mounted lifecycle hook
319
        if Rotor.Utils.isFunction(widget.onMountWidget) or widget?.isViewModel = true
2✔
320
            postProcessBuffer.add({
1✔
321
                hookType: Rotor.Const.LifeCycleHookType.MOUNTED,
322
                widget: widget
323
            })
324
        end if
325

326
        ' Return widget metadata for tree processing
327
        return {
1✔
328
            HID: HID,
329
            children: children,
330
            parentHID: parentHID,
331
            id: widget.id
332
        }
333

334
    end function
335

336
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