hyalite 0.0.1
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.
- 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
|