hyalite 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +46 -0
- data/Rakefile +7 -0
- data/client/hyalite.rb +98 -0
- data/client/hyalite/adler32.rb +33 -0
- data/client/hyalite/browser_event.rb +201 -0
- data/client/hyalite/callback_queue.rb +22 -0
- data/client/hyalite/component.rb +77 -0
- data/client/hyalite/composite_component.rb +237 -0
- data/client/hyalite/dom_component.rb +329 -0
- data/client/hyalite/dom_operations.rb +17 -0
- data/client/hyalite/dom_property.rb +218 -0
- data/client/hyalite/dom_property_operations.rb +117 -0
- data/client/hyalite/element.rb +17 -0
- data/client/hyalite/event_dispatcher.rb +99 -0
- data/client/hyalite/event_plugin/change_event_plugin.rb +83 -0
- data/client/hyalite/event_plugin/event_plugin_registry.rb +49 -0
- data/client/hyalite/event_plugin/simple_event_plugin.rb +276 -0
- data/client/hyalite/input_wrapper.rb +94 -0
- data/client/hyalite/instance_handles.rb +78 -0
- data/client/hyalite/internal_component.rb +11 -0
- data/client/hyalite/linked_value_utils.rb +27 -0
- data/client/hyalite/mount.rb +285 -0
- data/client/hyalite/multi_children.rb +272 -0
- data/client/hyalite/reconcile_transaction.rb +41 -0
- data/client/hyalite/reconciler.rb +122 -0
- data/client/hyalite/short_hand.rb +23 -0
- data/client/hyalite/synthetic_event.rb +18 -0
- data/client/hyalite/text_component.rb +42 -0
- data/client/hyalite/transaction.rb +47 -0
- data/client/hyalite/try.rb +7 -0
- data/client/hyalite/update_queue.rb +52 -0
- data/client/hyalite/updates.rb +129 -0
- data/client/hyalite/utils.rb +19 -0
- data/example/Gemfile +5 -0
- data/example/Gemfile.lock +46 -0
- data/example/app/application.rb +27 -0
- data/example/config.ru +12 -0
- data/example/index.html.haml +8 -0
- data/hyalite.gemspec +27 -0
- data/lib/hyalite.rb +6 -0
- data/lib/hyalite/main.rb +5 -0
- data/lib/hyalite/version.rb +3 -0
- metadata +145 -0
@@ -0,0 +1,78 @@
|
|
1
|
+
module Hyalite
|
2
|
+
module InstanceHandles
|
3
|
+
@root_index = 0
|
4
|
+
|
5
|
+
SEPARATOR = '.'
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def root_id_string(index)
|
9
|
+
SEPARATOR + index.to_s(36)
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_root_id
|
13
|
+
root_id_string(root_index);
|
14
|
+
end
|
15
|
+
|
16
|
+
def root_id_from_node_id(id)
|
17
|
+
if id && id.start_with?(SEPARATOR)
|
18
|
+
index = id.index(SEPARATOR, 1)
|
19
|
+
index ? id[0...index] : id
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def root_index
|
24
|
+
index = @root_index
|
25
|
+
@root_index += 1
|
26
|
+
index
|
27
|
+
end
|
28
|
+
|
29
|
+
def traverse_two_phase(target_id, &cb)
|
30
|
+
traverse_parent_path('', target_id, true, false, &cb)
|
31
|
+
traverse_parent_path(target_id, '', false, true, &cb)
|
32
|
+
end
|
33
|
+
|
34
|
+
def traverse_ancestors(target_id, &cb)
|
35
|
+
traverse_parent_path('', target_id, true, false, &cb)
|
36
|
+
end
|
37
|
+
|
38
|
+
def traverse_parent_path(start, stop, skip_first, skip_last, &cb)
|
39
|
+
start = start || ''
|
40
|
+
stop = stop || ''
|
41
|
+
traverse_up = is_ancestor_id_of(stop, start)
|
42
|
+
|
43
|
+
id = start
|
44
|
+
loop do
|
45
|
+
unless (skip_first && id == start) || (skip_last && id == stop)
|
46
|
+
ret = yield(id, traverse_up)
|
47
|
+
end
|
48
|
+
|
49
|
+
if ret == false || id == stop
|
50
|
+
break
|
51
|
+
end
|
52
|
+
|
53
|
+
id = traverse_up ? parent_id(id) : next_descendant_id(id, stop)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def parent_id(id)
|
58
|
+
id.empty? ? '' : id[0, id.rindex(SEPARATOR)]
|
59
|
+
end
|
60
|
+
|
61
|
+
def is_ancestor_id_of(ancestor_id, descendant_id)
|
62
|
+
descendant_id.index(ancestor_id) == 0 && is_boundary(descendant_id, ancestor_id.length)
|
63
|
+
end
|
64
|
+
|
65
|
+
def is_boundary(id, index)
|
66
|
+
id[index] == SEPARATOR || index == id.length
|
67
|
+
end
|
68
|
+
|
69
|
+
def next_descendant_id(ancestor_id, destination_id)
|
70
|
+
return ancestor_id if ancestor_id == destination_id
|
71
|
+
|
72
|
+
start = ancestor_id.length + SEPARATOR.length
|
73
|
+
last = destination_id.index(SEPARATOR, start) || destination_id.length
|
74
|
+
destination_id[0,last]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Hyalite
|
2
|
+
module LinkedValueUtils
|
3
|
+
class << self
|
4
|
+
def value(props)
|
5
|
+
if props.has_key? :valueLink
|
6
|
+
props[:valueLink][:value]
|
7
|
+
else
|
8
|
+
props[:value]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def checked(props)
|
13
|
+
if props.has_key? :checkedLink
|
14
|
+
props[:checkedLink][:value]
|
15
|
+
else
|
16
|
+
props[:checked]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute_on_change(props, event)
|
21
|
+
if props.has_key? :onChange
|
22
|
+
props[:onChange].call(event)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,285 @@
|
|
1
|
+
require 'hyalite/transaction'
|
2
|
+
require 'hyalite/adler32'
|
3
|
+
require 'hyalite/try'
|
4
|
+
require 'hyalite/transaction'
|
5
|
+
require 'hyalite/element'
|
6
|
+
require 'hyalite/component'
|
7
|
+
require 'hyalite/instance_handles'
|
8
|
+
require 'hyalite/updates'
|
9
|
+
require 'hyalite/composite_component'
|
10
|
+
|
11
|
+
module Hyalite
|
12
|
+
module Mount
|
13
|
+
ID_ATTR_NAME = 'data-hyalite-id'
|
14
|
+
CHECKSUM_ATTR_NAME = 'data-react-checksum'
|
15
|
+
|
16
|
+
@instances_by_root_id = {}
|
17
|
+
@containers_by_root_id = {}
|
18
|
+
@is_batching_updates = false
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def instances_by_root_id(root_id)
|
22
|
+
@instances_by_root_id[root_id]
|
23
|
+
end
|
24
|
+
|
25
|
+
def render_subtree_into_container(parent_component, next_element, container, &block)
|
26
|
+
next_wrapped_element = ElementObject.new(TopLevelWrapper, nil, nil, nil, next_element)
|
27
|
+
prev_component = @instances_by_root_id[root_id(container)]
|
28
|
+
if prev_component
|
29
|
+
prev_wrapped_element = prev_component.current_element
|
30
|
+
prev_element = prev_wrapped_element.props;
|
31
|
+
if Reconciler.should_update_component(prev_element, next_element)
|
32
|
+
return update_root_component(
|
33
|
+
prev_component,
|
34
|
+
next_wrapped_element,
|
35
|
+
container,
|
36
|
+
&block
|
37
|
+
).rendered_component.public_instance
|
38
|
+
else
|
39
|
+
unmount_component_at_node(container)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
root_element = root_element_in_container(container)
|
44
|
+
container_has_markup = root_element && is_rendered(root_element)
|
45
|
+
should_reuse_markup = container_has_markup && prev_component.nil?
|
46
|
+
|
47
|
+
component = render_new_root_component(
|
48
|
+
next_wrapped_element,
|
49
|
+
container,
|
50
|
+
should_reuse_markup,
|
51
|
+
parent_component ?
|
52
|
+
parent_component.internal_instance.process_child_context(parent_component.internal_instance.context) :
|
53
|
+
{}
|
54
|
+
).rendered_component.public_instance
|
55
|
+
|
56
|
+
if block_given?
|
57
|
+
yield component
|
58
|
+
end
|
59
|
+
|
60
|
+
component
|
61
|
+
end
|
62
|
+
|
63
|
+
def is_rendered(node)
|
64
|
+
return false if node.node_type != Browser::DOM::Node::ELEMENT_NODE
|
65
|
+
|
66
|
+
id = node_id(node)
|
67
|
+
id ? id[0] == SEPARATOR : false
|
68
|
+
end
|
69
|
+
|
70
|
+
def render_new_root_component(next_element, container, should_reuse_markup, context)
|
71
|
+
component_instance = Hyalite.instantiate_component(next_element, nil)
|
72
|
+
root_id = register_component(component_instance, container)
|
73
|
+
|
74
|
+
Hyalite.updates.batched_updates do
|
75
|
+
mount_component_into_node(component_instance, root_id, container, should_reuse_markup, context)
|
76
|
+
end
|
77
|
+
|
78
|
+
component_instance
|
79
|
+
end
|
80
|
+
|
81
|
+
def register_component(next_component, container)
|
82
|
+
#ReactBrowserEventEmitter.ensureScrollValueMonitoring();
|
83
|
+
|
84
|
+
root_id = register_container(container)
|
85
|
+
@instances_by_root_id[root_id] = next_component;
|
86
|
+
root_id
|
87
|
+
end
|
88
|
+
|
89
|
+
def register_container(container)
|
90
|
+
root_id = root_id(container)
|
91
|
+
if root_id
|
92
|
+
root_id = InstanceHandles.root_id_from_node_id(root_id)
|
93
|
+
end
|
94
|
+
|
95
|
+
unless root_id
|
96
|
+
root_id = InstanceHandles.create_root_id
|
97
|
+
end
|
98
|
+
|
99
|
+
@containers_by_root_id[root_id] = container
|
100
|
+
root_id
|
101
|
+
end
|
102
|
+
|
103
|
+
def mount_component_into_node(component_instance, root_id, container, should_reuse_markup, context)
|
104
|
+
Hyalite.updates.reconcile_transaction.perform do |transaction|
|
105
|
+
markup = Reconciler.mount_component(component_instance, root_id, transaction.mount_ready, context)
|
106
|
+
component_instance.rendered_component.top_level_wrapper = component_instance
|
107
|
+
mount_image_into_node(markup, container, should_reuse_markup)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def mount_image_into_node(markup, container, should_reuse_markup)
|
112
|
+
if should_reuse_markup
|
113
|
+
root_element = root_element_in_container(container)
|
114
|
+
checksum = Adler32.checksum markup
|
115
|
+
checksum_attr = root_element.attr(CHECKSUM_ATTR_NAME)
|
116
|
+
if checksum == checksum_attr
|
117
|
+
return
|
118
|
+
end
|
119
|
+
|
120
|
+
root_element.remove_attr(CHECKSUM_ATTR_NAME)
|
121
|
+
root_element.attr(CHECKSUM_ATTR_NAME, checksum)
|
122
|
+
end
|
123
|
+
|
124
|
+
container.inner_dom = markup
|
125
|
+
end
|
126
|
+
|
127
|
+
def root_element_in_container(container)
|
128
|
+
if container.node_type == Browser::DOM::Node::DOCUMENT_NODE
|
129
|
+
$document
|
130
|
+
else
|
131
|
+
container.child
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def root_id(container)
|
136
|
+
root_element = root_element_in_container(container)
|
137
|
+
root_element && node_id(root_element)
|
138
|
+
end
|
139
|
+
|
140
|
+
def node_cache
|
141
|
+
@node_cache ||= {}
|
142
|
+
end
|
143
|
+
|
144
|
+
def purge_id(id)
|
145
|
+
@node_cache.delete(id)
|
146
|
+
end
|
147
|
+
|
148
|
+
def node_id(node)
|
149
|
+
id = internal_id(node)
|
150
|
+
if id
|
151
|
+
if node_cache.has_key?(id)
|
152
|
+
cached = node_cache[id]
|
153
|
+
if cached != node
|
154
|
+
#raise "Mount: Two valid but unequal nodes with the same `#{ID_ATTR_NAME}`: #{id}"
|
155
|
+
node_cache[id] = node
|
156
|
+
end
|
157
|
+
else
|
158
|
+
node_cache[id] = node
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
id
|
163
|
+
end
|
164
|
+
|
165
|
+
def internal_id(node)
|
166
|
+
if node.node_type == Browser::DOM::Node::ELEMENT_NODE
|
167
|
+
node.attr(ID_ATTR_NAME)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# cf. ReactMount#findReactContainerForID
|
172
|
+
def container_for_id(id)
|
173
|
+
root_id = InstanceHandles.root_id_from_node_id(id)
|
174
|
+
@containers_by_root_id[root_id]
|
175
|
+
end
|
176
|
+
|
177
|
+
def node(id)
|
178
|
+
node = node_cache[id]
|
179
|
+
unless node && is_valid(node, id)
|
180
|
+
root_id = InstanceHandles.root_id_from_node_id(id)
|
181
|
+
node = node_cache[id] = find_component_root(@containers_by_root_id[root_id], id)
|
182
|
+
end
|
183
|
+
node
|
184
|
+
end
|
185
|
+
|
186
|
+
def is_valid(node, id)
|
187
|
+
if node
|
188
|
+
container = @containers_by_root_id[id]
|
189
|
+
if container && contains_node(container, node)
|
190
|
+
return true
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
false
|
195
|
+
end
|
196
|
+
|
197
|
+
def find_component_root(ancestor_node, target_id)
|
198
|
+
deepest_ancestor = find_deepest_cached_ancestor(target_id) || ancestor_node
|
199
|
+
|
200
|
+
first_children = [ deepest_ancestor.child ]
|
201
|
+
|
202
|
+
while first_children.length > 0
|
203
|
+
child = first_children.shift
|
204
|
+
|
205
|
+
while child
|
206
|
+
child_id = node_id(child)
|
207
|
+
if child_id
|
208
|
+
if target_id == child_id
|
209
|
+
return child
|
210
|
+
elsif InstanceHandles.is_ancestor_id_of(child_id, target_id)
|
211
|
+
first_children = [ child.child ]
|
212
|
+
end
|
213
|
+
else
|
214
|
+
first_children.push(child.child)
|
215
|
+
end
|
216
|
+
|
217
|
+
child = child.next_sibling
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
raise "can't find component_root"
|
222
|
+
end
|
223
|
+
|
224
|
+
def find_deepest_cached_ancestor(target_id)
|
225
|
+
deepest_node_so_far = nil
|
226
|
+
InstanceHandles.traverse_ancestors(target_id) do |ancestor_id|
|
227
|
+
ancestor = node_cache[ancestor_id]
|
228
|
+
if ancestor && is_valid(ancestor, ancestor_id)
|
229
|
+
deepest_node_so_far = ancestor;
|
230
|
+
else
|
231
|
+
false
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
deepest_node_so_far
|
236
|
+
end
|
237
|
+
|
238
|
+
def contains_node(outer_node, inner_node)
|
239
|
+
case
|
240
|
+
when outer_node.nil? || inner_node.nil?
|
241
|
+
false
|
242
|
+
when outer_node == inner_node
|
243
|
+
true
|
244
|
+
when outer_node.node_type == Browser::DOM::Node::TEXT_NODE
|
245
|
+
false
|
246
|
+
else
|
247
|
+
contains_node(outer_node, inner_node.parent)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def find_first_hyalite_dom(node)
|
252
|
+
while node && node.parent != node
|
253
|
+
unless node.node_type == Browser::DOM::Node::ELEMENT_NODE && node_id = internal_id(node)
|
254
|
+
node = node.parent
|
255
|
+
next
|
256
|
+
end
|
257
|
+
|
258
|
+
root_id = InstanceHandles.root_id_from_node_id(node_id)
|
259
|
+
|
260
|
+
current = node
|
261
|
+
loop do
|
262
|
+
last_id = internal_id(current)
|
263
|
+
return nil unless current = current.parent
|
264
|
+
break if last_id == root_id
|
265
|
+
end
|
266
|
+
|
267
|
+
return node if current == @containers_by_root_id[root_id]
|
268
|
+
|
269
|
+
node = node.parent
|
270
|
+
end
|
271
|
+
|
272
|
+
nil
|
273
|
+
end
|
274
|
+
|
275
|
+
def update_root_component(prev_component, next_element, container, &callback)
|
276
|
+
UpdateQueue.enqueue_element_internal(prev_component, next_element)
|
277
|
+
if block_given?
|
278
|
+
UpdateQueue.enqueue_callback_internal(prev_component, &callback)
|
279
|
+
end
|
280
|
+
|
281
|
+
prev_component
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
@@ -0,0 +1,272 @@
|
|
1
|
+
module Hyalite
|
2
|
+
module MultiChildren
|
3
|
+
def mount_children(nested_children, mount_ready, context)
|
4
|
+
children = instantiate_children(nested_children, mount_ready, context)
|
5
|
+
@rendered_children = children
|
6
|
+
index = 0
|
7
|
+
children.keys.map do |name|
|
8
|
+
child = children[name]
|
9
|
+
root_id = root_node_id + name
|
10
|
+
mount_image = Reconciler.mount_component(children[name], root_id, mount_ready, context)
|
11
|
+
child.mount_index = index
|
12
|
+
index += 1
|
13
|
+
mount_image
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def unmount_children
|
18
|
+
if @rendered_children
|
19
|
+
Reconciler.unmount_children(@rendered_children)
|
20
|
+
@rendered_children = nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def update_children(next_nested_children, mount_ready, context)
|
25
|
+
MultiChildren.wrap_update do
|
26
|
+
prev_children = @rendered_children
|
27
|
+
next_children = Reconciler.update_children(prev_children, next_nested_children, mount_ready, context)
|
28
|
+
@rendered_children = next_children
|
29
|
+
return if next_children.nil? && prev_children.nil?
|
30
|
+
|
31
|
+
|
32
|
+
last_index = 0
|
33
|
+
next_index = 0
|
34
|
+
next_children.each do |name, next_child|
|
35
|
+
prev_child = prev_children && prev_children[name]
|
36
|
+
if prev_child == next_child
|
37
|
+
move_child(prev_child, next_index, last_index)
|
38
|
+
last_index = [prev_child.mount_index, last_index].max
|
39
|
+
prev_child.mount_index = next_index
|
40
|
+
else
|
41
|
+
if prev_child
|
42
|
+
last_index = [prev_child.mount_index, last_index].max
|
43
|
+
unmount_child(prev_child)
|
44
|
+
end
|
45
|
+
|
46
|
+
mount_child_by_name_at_index(next_child, name, next_index, mount_ready, context)
|
47
|
+
end
|
48
|
+
next_index += 1
|
49
|
+
end
|
50
|
+
|
51
|
+
prev_children.each do |name, prev_child|
|
52
|
+
unless next_children && next_children.has_key?(name)
|
53
|
+
unmount_child(prev_child)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def update_text_content(next_content)
|
60
|
+
MultiChildren.wrap_update do
|
61
|
+
prev_children = @rendered_children
|
62
|
+
if prev_children
|
63
|
+
Reconciler.unmount_children(prev_children)
|
64
|
+
prev_children.each do |prev_child|
|
65
|
+
unmount_child(prev_child)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
set_text_content(next_content)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def move_child(child, to_index, last_index)
|
73
|
+
if child.mount_index < last_index
|
74
|
+
enqueue_move(root_node_id, child.mount_index, to_index)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def remove_child(child)
|
79
|
+
enqueue_remove(root_node_id, child.mount_index)
|
80
|
+
end
|
81
|
+
|
82
|
+
def unmount_child(child)
|
83
|
+
remove_child(child)
|
84
|
+
child.mount_index = nil
|
85
|
+
end
|
86
|
+
|
87
|
+
def instantiate_children(nested_child_nodes, context)
|
88
|
+
Reconciler.flatten_children(nested_child_nodes).map {|name, child|
|
89
|
+
child_instance = Hyalite.instantiate_component(child, nil)
|
90
|
+
[name, child_instance]
|
91
|
+
}.to_h
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
class << self
|
97
|
+
def wrap_update(&block)
|
98
|
+
self.update_depth += 1
|
99
|
+
error_thrown = false
|
100
|
+
yield
|
101
|
+
ensure
|
102
|
+
self.update_depth -= 1
|
103
|
+
if self.update_depth == 0
|
104
|
+
unless error_thrown
|
105
|
+
self.process_queue
|
106
|
+
else
|
107
|
+
self.clear_queue
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def update_depth
|
113
|
+
@update_depth ||= 0
|
114
|
+
end
|
115
|
+
|
116
|
+
def update_depth=(depth)
|
117
|
+
@update_depth = depth
|
118
|
+
end
|
119
|
+
|
120
|
+
def update_queue
|
121
|
+
@update_queue ||= []
|
122
|
+
end
|
123
|
+
|
124
|
+
def markup_queue
|
125
|
+
@markup_queue ||= []
|
126
|
+
end
|
127
|
+
|
128
|
+
def clear_queue
|
129
|
+
self.update_queue.clear
|
130
|
+
self.markup_queue.clear
|
131
|
+
end
|
132
|
+
|
133
|
+
def process_queue
|
134
|
+
if MultiChildren.update_queue.any?
|
135
|
+
process_children_updates(MultiChildren.update_queue, MultiChildren.markup_queue)
|
136
|
+
clear_queue
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def process_children_updates(updates, markup)
|
141
|
+
updates.each do |update|
|
142
|
+
update[:parentNode] = Mount.node(update[:parentID])
|
143
|
+
end
|
144
|
+
process_updates(updates, markup)
|
145
|
+
end
|
146
|
+
|
147
|
+
def process_updates(updates, markup_list)
|
148
|
+
initial_children = {}
|
149
|
+
updated_children = []
|
150
|
+
|
151
|
+
updates.each_with_index do |update, updated_index|
|
152
|
+
if update[:type] == :move_existing || update[:type] == :remove_node
|
153
|
+
updated_index = update[:fromIndex]
|
154
|
+
updated_child = update[:parentNode].elements[updated_index]
|
155
|
+
parent_id = update[:parentID]
|
156
|
+
|
157
|
+
initial_children[parent_id] ||= []
|
158
|
+
initial_children[parent_id] << updated_child
|
159
|
+
|
160
|
+
updated_children << updated_child
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
if markup_list.any? && markup_list[0].is_a?(String)
|
165
|
+
#rendered_markup = Danger.dangerouslyRenderMarkup(markupList);
|
166
|
+
raise "not implemented"
|
167
|
+
else
|
168
|
+
rendered_markup = markup_list
|
169
|
+
end
|
170
|
+
|
171
|
+
updated_children.each do |child|
|
172
|
+
child.remove
|
173
|
+
end
|
174
|
+
|
175
|
+
updates.each do |update|
|
176
|
+
case update[:type]
|
177
|
+
when :insert_markup
|
178
|
+
insert_child_at(
|
179
|
+
update[:parentNode],
|
180
|
+
rendered_markup[update[:markupIndex]],
|
181
|
+
update[:toIndex])
|
182
|
+
when :move_existing
|
183
|
+
insert_child_at(
|
184
|
+
update[:parentNode],
|
185
|
+
initial_children[update[:parentID]][update[:fromIndex]],
|
186
|
+
update[:toIndex])
|
187
|
+
when :set_markup
|
188
|
+
update[:parentNode].inner_html = update[:textContent]
|
189
|
+
when :text_content
|
190
|
+
update[:parentNode].content = update[:textContent]
|
191
|
+
when :remove_node
|
192
|
+
# Already removed above.
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
def insert_child_at(parent_node, child_node, index)
|
199
|
+
if index >= parent_node.children.to_ary.length
|
200
|
+
parent_node.add_child(child_node)
|
201
|
+
else
|
202
|
+
parent_node[index].add_previous_sibling(child_node)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def mount_child_by_name_at_index(child, name, index, mount_ready, context)
|
208
|
+
root_id = root_node_id + name
|
209
|
+
mount_image = Reconciler.mount_component(child, root_id, mount_ready, context)
|
210
|
+
child.mount_index = index
|
211
|
+
create_child(child, mount_image)
|
212
|
+
end
|
213
|
+
|
214
|
+
def create_child(child, mount_image)
|
215
|
+
enqueue_markup(root_node_id, mount_image, child.mount_index)
|
216
|
+
end
|
217
|
+
|
218
|
+
def set_text_content(text_content)
|
219
|
+
enqueue_text_content(root_node_id, text_content)
|
220
|
+
end
|
221
|
+
|
222
|
+
def enqueue_remove(parent_id, from_index)
|
223
|
+
MultiChildren.update_queue << {
|
224
|
+
parentID: parent_id,
|
225
|
+
parentNode: nil,
|
226
|
+
type: :remove_node,
|
227
|
+
markupIndex: nil,
|
228
|
+
content: nil,
|
229
|
+
fromIndex: from_index,
|
230
|
+
toIndex: nil
|
231
|
+
}
|
232
|
+
end
|
233
|
+
|
234
|
+
def enqueue_move(parent_id, from_index, to_index)
|
235
|
+
MultiChildren.update_queue << {
|
236
|
+
parentID: parent_id,
|
237
|
+
parentNode: nil,
|
238
|
+
type: :move_existing,
|
239
|
+
markupIndex: nil,
|
240
|
+
content: nil,
|
241
|
+
fromIndex: from_index,
|
242
|
+
toIndex: to_index
|
243
|
+
}
|
244
|
+
end
|
245
|
+
|
246
|
+
def enqueue_text_content(parent_id, text_content)
|
247
|
+
MultiChildren.update_queue << {
|
248
|
+
parentID: parent_id,
|
249
|
+
parentNode: nil,
|
250
|
+
type: :text_content,
|
251
|
+
markupIndex: nil,
|
252
|
+
textContent: text_content,
|
253
|
+
fromIndex: nil,
|
254
|
+
toIndex: nil
|
255
|
+
}
|
256
|
+
end
|
257
|
+
|
258
|
+
def enqueue_markup(parent_id, markup, to_index)
|
259
|
+
MultiChildren.markup_queue << markup
|
260
|
+
MultiChildren.update_queue << {
|
261
|
+
parentID: parent_id,
|
262
|
+
parentNode: nil,
|
263
|
+
type: :insert_markup,
|
264
|
+
markupIndex: MultiChildren.markup_queue.length - 1,
|
265
|
+
textContent: nil,
|
266
|
+
fromIndex: nil,
|
267
|
+
toIndex: to_index
|
268
|
+
}
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
end
|