-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathNodeUtils.brs
224 lines (192 loc) · 7.3 KB
/
NodeUtils.brs
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
' @import /components/getProperty.brs
' Node utils.
' @class
function NodeUtils() as Object
prototype = {}
' Checks if nodes are the same by checking their reference.
' @param {Node} node1
' @param {Node} node2
' @returns {Boolean}
prototype.areNodesTheSame = function (node1 as Object, node2 as Object) as Boolean
if (node1 <> Invalid)
return node1.isSameNode(node2)
end if
return (node2 = Invalid)
end function
' Clones given node by creating new node of the same type. All the fields are cloned as well with exception to "change"
' and "focusedChild".
' @param {Node} source
' @returns {Node}
prototype.cloneNode = function (source as Object) as Object
clone = CreateObject("roSGNode", source.subtype())
fields = source.getFields()
fields.delete("change")
fields.delete("focusedChild")
clone.setFields(fields)
return clone
end function
' Gets all the custom node fields excluding "id", "focusedChild", "change", "focusable".
' @param {Node} source
' @returns {Object}
prototype.getCustomFields = function (source as Object) as Object
if (source = Invalid) then return {}
fields = source.getFields()
fields.delete("id")
fields.delete("focusedChild")
fields.delete("focusable")
fields.delete("change")
return fields
end function
' Finds child of a node by id.
' Warning:
' Preferred way of referencing child node is to use native findNode method.
' Unfortunatelly Node and ContentNode can't be referenced by native method (roku bug in RokuOS 9.1 and earlier).
' The only possible way is to iterate through children and find correct node.
' More details https://forums.roku.com/viewtopic.php?f=34&t=104187&sid=c734efdb811d220cd0716ca191f79e35
' @param {Node} node
' @param {String} id
' @returns {Dynamic} - Returns Invalid when node is not found.
prototype.findChildById = function (node as Object, id as String) as Dynamic
return m.findChildByProperty(node, "id", id)
end function
' Finds child node by given property value.
' @example
' ' Given node = <Node><Node user="{ isAdmin: true }"></Node></Node>
' NodeUtils().findChildByProperty(node, "user.isAdmin", true) ' Returns the first child
' @param {Node} node
' @param {String} propertyPath - It can be nested object.
' @param {Dynamic} value - The value that should match the searched value.
' @returns {Dynamic} - Returns Invalid when node is not found.
prototype.findChildByProperty = function (node as Object, propertyPath as String, value as Dynamic) as Dynamic
childIndex = m.findChildIndexByProperty(node, propertyPath, value)
if (childIndex = Invalid)
return Invalid
end if
return node.getChild(childIndex)
end function
' Finds child node index by given property value.
' @example
' ' Given node = <Node><Node user="{ isAdmin: true }"></Node></Node>
' NodeUtils().findChildIndexByProperty(node, "user.isAdmin", true) ' Returns index 0
' @param {Node} node
' @param {String} propertyPath - It can be nested object.
' @param {Dynamic} value - The value that should match the searched value.
' @returns {Dynamic} - Returns Invalid when node is not found.
prototype.findChildIndexByProperty = function (node as Object, propertyPath as String, value as Dynamic) as Dynamic
indexVector = m.findChildIndexVectorByProperty(node, propertyPath, value)
if (indexVector <> Invalid)
return indexVector[0]
end if
return Invalid
end function
' Finds child node vector by given property value.
' @example
' ' Given
' ' <Node>
' ' <Node>
' ' <Node></Node>
' ' <Node user="{ isAdmin: true }"></Node>
' ' </Node>
' ' </Node>
' NodeUtils().findChildIndexVectorByProperty(node, "user.isAdmin", true, 2) ' Returns [0][1]
' @param {Node} node
' @param {String} propertyPath - It can be nested object.
' @param {Dynamic} value - The value that should match the searched value.
' @param {Integer} [depth=1] - How deep the function should search.
' @returns {Dynamic} - Returns Invalid when node is not found.
prototype.findChildIndexVectorByProperty = function (node as Object, propertyPath as String, value as Dynamic, depth = 1 as Integer) as Dynamic
nodeLength = node.getChildCount()
if (nodeLength = 0)
return Invalid
end if
for i = 0 to nodeLength - 1
child = node.getChild(i)
if (depth = 1)
if (getProperty(child, propertyPath) = value)
return [i]
end if
else
deeperIndex = m.findChildIndexVectorByProperty(child, propertyPath, value, depth - 1)
if (deeperIndex <> Invalid)
index = [i]
index.append(deeperIndex)
return index
end if
end if
end for
return Invalid
end function
' Finds all children by given property value.
' @example
' ' Given
' ' <Node>
' ' <Node>
' ' <Node></Node>
' ' <Node user="{ isAdmin: true }"></Node>
' ' <Node user="{ isAdmin: true }"></Node>
' ' </Node>
' ' </Node>
' NodeUtils().findAllByProperty(node, "user.isAdmin", true, 2) ' Returns two nodes where value user.isAdmin is true
' @param {Node} node
' @param {String} propertyPath - It can be nested object.
' @param {Dynamic} value - The value that should match the searched value.
' @param {Integer} [depth=1] - How deep the function should search.
' @returns {Dynamic} - Returns Invalid when node is not found. Otherwise array of nodes.
prototype.findAllByProperty = function (node as Object, propertyPath as String, value as Dynamic, depth = 1 as Integer) as Object
results = []
nodeLength = node.getChildCount()
if (nodeLength = 0)
return results
end if
for i = 0 to nodeLength - 1
child = node.getChild(i)
if (depth = 1)
if (getProperty(child, propertyPath) = value)
results.push(child)
end if
else
deeperResults = m.findAllByProperty(child, propertyPath, value, depth - 1)
results.append(deeperResults)
end if
end for
return results
end function
' Finds a child node by given vector.
' @param {Node} node
' @param {Object} indexVector - Array of indexes to locate the node.
' @returns {Dynamic} - Returns Invalid when node is not found.
prototype.getItemByIndexVector = function (node as Object, indexVector as Object) as Dynamic
if (node = Invalid) then return Invalid
currentLevelNode = node
for each index in indexVector
nextLevelNode = currentLevelNode.getChild(index)
if (nextLevelNode = Invalid)
return Invalid
end if
currentLevelNode = nextLevelNode
end for
return currentLevelNode
end function
' Iterator over children of a node.
' @example
' ' Given nodes = <Node><Node></Node></Node>
' NodeUtils().forEach(nodes, sub (node as Object, index as Integer): ?node end sub)
' @param {Node} node
' @param {Function} action
' @param {Dynamic} [scopedData=Invalid]
prototype.forEachChild = sub (node as Object, action as Function, scopedData = Invalid as Dynamic)
if (node = Invalid)
return
end if
lastChildIndex = node.getChildCount() - 1
for i = 0 to lastChildIndex
child = node.getChild(i)
if (scopedData = Invalid)
action(child, i)
else
action(child, i, scopedData)
end if
end for
end sub
return prototype
end function