This repository was archived by the owner on Oct 19, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathrendering_context.rb
More file actions
207 lines (179 loc) · 6.3 KB
/
rendering_context.rb
File metadata and controls
207 lines (179 loc) · 6.3 KB
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
module React
class RenderingContext
attr_accessor :waiting_on_resources
def build_only(name, *args, &block)
React::Component.deprecation_warning(
'..._as_node is deprecated. Render component and then use the .node method instead'
)
build { render(name, *args, &block) }.to_n
end
def render(name, *args, &block)
remove_nodes_from_args(args)
@buffer ||= [] unless @buffer
if block
element = build do
saved_waiting_on_resources = waiting_on_resources
self.waiting_on_resources = nil
run_child_block(name.nil?, &block)
if name
buffer = @buffer.dup
React.create_element(name, *args) { buffer }.tap do |element|
element.waiting_on_resources = saved_waiting_on_resources || !!buffer.detect { |e| e.waiting_on_resources if e.respond_to?(:waiting_on_resources) }
end
elsif @buffer.last.is_a? React::Element
@buffer.last.tap { |element| element.waiting_on_resources ||= saved_waiting_on_resources }
else
@buffer.last.to_s.span.tap { |element| element.waiting_on_resources = saved_waiting_on_resources }
end
end
elsif name.is_a? React::Element
element = name
else
element = React.create_element(name, *args)
element.waiting_on_resources = waiting_on_resources
end
@buffer << element
self.waiting_on_resources = nil
element
end
def build
current = @buffer
@buffer = []
return_val = yield @buffer
@buffer = current
return_val
end
def as_node(element)
@buffer.delete(element)
element
end
alias delete as_node
def rendered?(element)
@buffer.include? element
end
def replace(e1, e2)
@buffer[@buffer.index(e1)] = e2
end
def remove_nodes_from_args(args)
args[0].each do |key, value|
value.as_node if value.is_a?(Element) rescue nil
end if args[0] && args[0].is_a?(Hash)
end
# run_child_block gathers the element(s) generated by a child block.
# for example when rendering this div: div { "hello".span; "goodby".span }
# two child Elements will be generated.
#
# the final value of the block should either be
# 1 an object that responds to :acts_as_string?
# 2 a string,
# 3 an element that is NOT yet pushed on the rendering buffer
# 4 or the last element pushed on the buffer
#
# in case 1 we change the object to a string, and then it becomes case 2
# in case 2 we automatically push the string onto the buffer
# in case 3 we also push the Element onto the buffer IF the buffer is empty
# case 4 requires no special processing
#
# Once we have taken care of these special cases we do a check IF we are in an
# outer rendering scope. In this case react only allows us to generate 1 Element
# so we insure that is the case, and also check to make sure that element in the buffer
# is the element returned
def run_child_block(is_outer_scope)
result = yield
result = result.to_s if result.try :acts_as_string?
@buffer << result if result.is_a?(String) || (result.is_a?(Element) && @buffer.empty?)
raise_render_error(result) if is_outer_scope && @buffer != [result]
end
def raise_render_error(result)
improper_render 'A different element was returned than was generated within the DSL.',
'Possibly improper use of Element#delete.' if @buffer.count == 1
improper_render "Instead #{@buffer.count} elements were generated.",
'Do you want to wrap your elements in a div?' if @buffer.count > 1
improper_render "Instead the component #{result} was returned.",
"Did you mean #{result}()?" if result.try :reactrb_component?
improper_render "Instead the #{result.class} #{result} was returned.",
'You may need to convert this to a string.'
end
def improper_render(message, solution)
raise "a component's render method must generate and return exactly 1 element or a string.\n"\
" #{message} #{solution}"
end
class << self
attr_accessor :current_context
def contexts
@contexts ||= []
end
def clear
@contexts = nil
@current_context = nil
end
def create_context(&block)
is_root = !self.current_context
if is_root
self.current_context = self.new
result = yield
self.current_context = nil
result
else
contexts << self.current_context
self.current_context = self.new
result = yield
self.current_context = contexts.pop
result
end
rescue => e
contexts.clear
self.current_context = nil
raise e
end
def build_only(name, *args, &block)
current_context.build_only(name, *args, &block)
end
def render(name, *args, &block)
current_context.render(name, *args, &block)
end
def build(&block)
create_context {
current_context.build(&block)
}
end
def as_node(element)
current_context.as_node(element)
end
alias delete as_node
def rendered?(element)
current_context.rendered?(element)
end
def replace(e1, e2)
current_context.replace(e1, e2)
end
def remove_nodes_from_args(args)
current_context.remove_nodes_from_args(args)
end
def run_child_block(is_outer_scope)
current_context.run_child_block(is_outer_scope)
end
end
end
class ::Object
[:span, :td, :th, :while_loading].each do |tag|
define_method(tag) do |*args, &block|
args.unshift(tag)
return send(*args, &block) if is_a? React::Component
React::RenderingContext.render(*args) { to_s }
end
end
def para(*args, &block)
args.unshift(:p)
return send(*args, &block) if is_a? React::Component
React::RenderingContext.render(*args) { to_s }
end
def br
return send(:br) if is_a? React::Component
React::RenderingContext.render(:span) do
React::RenderingContext.render(to_s)
React::RenderingContext.render(:br)
end
end
end
end