reactrb 0.7.42
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +6 -0
- data/.gitignore +33 -0
- data/.travis.yml +9 -0
- data/Gemfile +2 -0
- data/LICENSE +19 -0
- data/README.md +117 -0
- data/Rakefile +28 -0
- data/config.ru +16 -0
- data/example/examples/Gemfile +7 -0
- data/example/examples/app/basics.js.rb +42 -0
- data/example/examples/app/items.rb +11 -0
- data/example/examples/app/jquery.js +5 -0
- data/example/examples/app/nodes.rb +61 -0
- data/example/examples/app/react-router.js +6 -0
- data/example/examples/app/react_api_demo.rb +29 -0
- data/example/examples/app/rerendering.rb +72 -0
- data/example/examples/app/reuse.rb +59 -0
- data/example/examples/app/show.rb +52 -0
- data/example/examples/config.ru +38 -0
- data/example/rails-tutorial/.gitignore +17 -0
- data/example/rails-tutorial/Gemfile +51 -0
- data/example/rails-tutorial/README.rdoc +28 -0
- data/example/rails-tutorial/Rakefile +6 -0
- data/example/rails-tutorial/app/assets/images/.keep +0 -0
- data/example/rails-tutorial/app/assets/javascripts/application.rb +15 -0
- data/example/rails-tutorial/app/assets/stylesheets/application.css +15 -0
- data/example/rails-tutorial/app/controllers/application_controller.rb +6 -0
- data/example/rails-tutorial/app/controllers/concerns/.keep +0 -0
- data/example/rails-tutorial/app/controllers/home_controller.rb +6 -0
- data/example/rails-tutorial/app/helpers/application_helper.rb +2 -0
- data/example/rails-tutorial/app/mailers/.keep +0 -0
- data/example/rails-tutorial/app/models/.keep +0 -0
- data/example/rails-tutorial/app/models/concerns/.keep +0 -0
- data/example/rails-tutorial/app/views/components.rb +3 -0
- data/example/rails-tutorial/app/views/components/home/show.rb +47 -0
- data/example/rails-tutorial/app/views/layouts/application.html.erb +14 -0
- data/example/rails-tutorial/bin/bundle +3 -0
- data/example/rails-tutorial/bin/rails +8 -0
- data/example/rails-tutorial/bin/rake +8 -0
- data/example/rails-tutorial/bin/setup +29 -0
- data/example/rails-tutorial/bin/spring +15 -0
- data/example/rails-tutorial/config.ru +4 -0
- data/example/rails-tutorial/config/application.rb +26 -0
- data/example/rails-tutorial/config/boot.rb +3 -0
- data/example/rails-tutorial/config/database.yml +25 -0
- data/example/rails-tutorial/config/environment.rb +5 -0
- data/example/rails-tutorial/config/environments/development.rb +41 -0
- data/example/rails-tutorial/config/environments/production.rb +79 -0
- data/example/rails-tutorial/config/environments/test.rb +42 -0
- data/example/rails-tutorial/config/initializers/assets.rb +11 -0
- data/example/rails-tutorial/config/initializers/backtrace_silencers.rb +7 -0
- data/example/rails-tutorial/config/initializers/cookies_serializer.rb +3 -0
- data/example/rails-tutorial/config/initializers/filter_parameter_logging.rb +4 -0
- data/example/rails-tutorial/config/initializers/inflections.rb +16 -0
- data/example/rails-tutorial/config/initializers/mime_types.rb +4 -0
- data/example/rails-tutorial/config/initializers/session_store.rb +3 -0
- data/example/rails-tutorial/config/initializers/wrap_parameters.rb +14 -0
- data/example/rails-tutorial/config/locales/en.yml +23 -0
- data/example/rails-tutorial/config/routes.rb +59 -0
- data/example/rails-tutorial/config/secrets.yml +22 -0
- data/example/rails-tutorial/db/seeds.rb +7 -0
- data/example/rails-tutorial/lib/assets/.keep +0 -0
- data/example/rails-tutorial/lib/tasks/.keep +0 -0
- data/example/rails-tutorial/log/.keep +0 -0
- data/example/rails-tutorial/public/404.html +67 -0
- data/example/rails-tutorial/public/422.html +67 -0
- data/example/rails-tutorial/public/500.html +66 -0
- data/example/rails-tutorial/public/favicon.ico +0 -0
- data/example/rails-tutorial/public/robots.txt +5 -0
- data/example/rails-tutorial/test/controllers/.keep +0 -0
- data/example/rails-tutorial/test/fixtures/.keep +0 -0
- data/example/rails-tutorial/test/helpers/.keep +0 -0
- data/example/rails-tutorial/test/integration/.keep +0 -0
- data/example/rails-tutorial/test/mailers/.keep +0 -0
- data/example/rails-tutorial/test/models/.keep +0 -0
- data/example/rails-tutorial/test/test_helper.rb +10 -0
- data/example/rails-tutorial/vendor/assets/javascripts/.keep +0 -0
- data/example/rails-tutorial/vendor/assets/stylesheets/.keep +0 -0
- data/example/sinatra-tutorial/.DS_Store +0 -0
- data/example/sinatra-tutorial/Gemfile +5 -0
- data/example/sinatra-tutorial/README.md +8 -0
- data/example/sinatra-tutorial/_comments.json +42 -0
- data/example/sinatra-tutorial/app/example.rb +290 -0
- data/example/sinatra-tutorial/app/jquery.js +5 -0
- data/example/sinatra-tutorial/config.ru +58 -0
- data/example/sinatra-tutorial/public/base.css +62 -0
- data/example/todos/Gemfile +11 -0
- data/example/todos/README.md +37 -0
- data/example/todos/Rakefile +8 -0
- data/example/todos/app/application.rb +22 -0
- data/example/todos/app/components/app.react.rb +61 -0
- data/example/todos/app/components/footer.react.rb +31 -0
- data/example/todos/app/components/todo_item.react.rb +46 -0
- data/example/todos/app/components/todo_list.react.rb +25 -0
- data/example/todos/app/models/todo.rb +19 -0
- data/example/todos/config.ru +14 -0
- data/example/todos/index.html.haml +16 -0
- data/example/todos/spec/todo_spec.rb +28 -0
- data/example/todos/vendor/base.css +410 -0
- data/example/todos/vendor/bg.png +0 -0
- data/example/todos/vendor/jquery.js +4 -0
- data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/components.rb +4 -0
- data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/test_application.rb +2 -0
- data/lib/generators/reactive_ruby/test_app/templates/boot.rb.erb +6 -0
- data/lib/generators/reactive_ruby/test_app/templates/script/rails +5 -0
- data/lib/generators/reactive_ruby/test_app/templates/test_application.rb.erb +13 -0
- data/lib/generators/reactive_ruby/test_app/templates/views/components/hello_world.rb +11 -0
- data/lib/generators/reactive_ruby/test_app/templates/views/components/todo.rb +14 -0
- data/lib/generators/reactive_ruby/test_app/test_app_generator.rb +105 -0
- data/lib/rails-helpers/top_level_rails_component.rb +54 -0
- data/lib/react/api.rb +127 -0
- data/lib/react/callbacks.rb +42 -0
- data/lib/react/component.rb +269 -0
- data/lib/react/component/api.rb +50 -0
- data/lib/react/component/base.rb +9 -0
- data/lib/react/component/class_methods.rb +190 -0
- data/lib/react/component/props_wrapper.rb +82 -0
- data/lib/react/element.rb +77 -0
- data/lib/react/event.rb +76 -0
- data/lib/react/ext/hash.rb +9 -0
- data/lib/react/ext/string.rb +8 -0
- data/lib/react/native_library.rb +53 -0
- data/lib/react/observable.rb +29 -0
- data/lib/react/rendering_context.rb +109 -0
- data/lib/react/state.rb +140 -0
- data/lib/react/top_level.rb +97 -0
- data/lib/react/validator.rb +136 -0
- data/lib/reactive-ruby/component_loader.rb +45 -0
- data/lib/reactive-ruby/isomorphic_helpers.rb +196 -0
- data/lib/reactive-ruby/rails.rb +7 -0
- data/lib/reactive-ruby/rails/component_mount.rb +44 -0
- data/lib/reactive-ruby/rails/controller_helper.rb +13 -0
- data/lib/reactive-ruby/rails/railtie.rb +14 -0
- data/lib/reactive-ruby/serializers.rb +15 -0
- data/lib/reactive-ruby/server_rendering/contextual_renderer.rb +42 -0
- data/lib/reactive-ruby/version.rb +3 -0
- data/lib/reactrb.rb +50 -0
- data/lib/sources/react-latest.js +21167 -0
- data/lib/sources/react-v13.js +21642 -0
- data/lib/sources/react-v14.js +20818 -0
- data/lib/sources/react-v15.js +21167 -0
- data/logo1.png +0 -0
- data/logo2.png +0 -0
- data/logo3.png +0 -0
- data/path_release_steps.md +9 -0
- data/reactrb.gemspec +43 -0
- data/spec/controller_helper_spec.rb +22 -0
- data/spec/index.html.erb +12 -0
- data/spec/react/callbacks_spec.rb +106 -0
- data/spec/react/component/base_spec.rb +36 -0
- data/spec/react/component_spec.rb +721 -0
- data/spec/react/dsl_spec.rb +161 -0
- data/spec/react/element_spec.rb +47 -0
- data/spec/react/event_spec.rb +24 -0
- data/spec/react/native_library_spec.rb +10 -0
- data/spec/react/observable_spec.rb +7 -0
- data/spec/react/param_declaration_spec.rb +286 -0
- data/spec/react/react_spec.rb +211 -0
- data/spec/react/state_spec.rb +26 -0
- data/spec/react/top_level_component_spec.rb +68 -0
- data/spec/react/tutorial/tutorial_spec.rb +35 -0
- data/spec/react/validator_spec.rb +128 -0
- data/spec/reactive-ruby/component_loader_spec.rb +68 -0
- data/spec/reactive-ruby/isomorphic_helpers_spec.rb +155 -0
- data/spec/reactive-ruby/rails/asset_pipeline_spec.rb +9 -0
- data/spec/reactive-ruby/rails/component_mount_spec.rb +66 -0
- data/spec/reactive-ruby/server_rendering/contextual_renderer_spec.rb +35 -0
- data/spec/spec_helper.rb +109 -0
- data/spec/support/react/spec_helpers.rb +57 -0
- data/spec/vendor/es5-shim.min.js +6 -0
- data/spec/vendor/jquery-2.2.4.min.js +4 -0
- metadata +441 -0
@@ -0,0 +1,136 @@
|
|
1
|
+
module React
|
2
|
+
|
3
|
+
class Validator
|
4
|
+
attr_accessor :errors
|
5
|
+
private :errors
|
6
|
+
|
7
|
+
def initialize(component_class)
|
8
|
+
@component_class = component_class
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.build(&block)
|
12
|
+
self.new.build(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def build(&block)
|
16
|
+
instance_eval(&block)
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def requires(name, options = {})
|
21
|
+
options[:required] = true
|
22
|
+
define_rule(name, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def optional(name, options = {})
|
26
|
+
options[:required] = false
|
27
|
+
define_rule(name, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def allow_undefined_props=(allow)
|
31
|
+
@allow_undefined_props = allow
|
32
|
+
end
|
33
|
+
|
34
|
+
def undefined_props(props)
|
35
|
+
self.allow_undefined_props = true
|
36
|
+
props.reject { |name, value| rules[name] }
|
37
|
+
end
|
38
|
+
|
39
|
+
def validate(props)
|
40
|
+
self.errors = []
|
41
|
+
validate_undefined(props) unless allow_undefined_props?
|
42
|
+
props = coerce_native_hash_values(defined_props(props))
|
43
|
+
validate_required(props)
|
44
|
+
props.each do |name, value|
|
45
|
+
validate_types(name, value)
|
46
|
+
validate_allowed(name, value)
|
47
|
+
end
|
48
|
+
errors
|
49
|
+
end
|
50
|
+
|
51
|
+
def default_props
|
52
|
+
rules
|
53
|
+
.select {|key, value| value.keys.include?("default") }
|
54
|
+
.inject({}) {|memo, (k,v)| memo[k] = v[:default]; memo}
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def defined_props(props)
|
60
|
+
props.select { |name| rules.keys.include?(name) }
|
61
|
+
end
|
62
|
+
|
63
|
+
def allow_undefined_props?
|
64
|
+
!!@allow_undefined_props
|
65
|
+
end
|
66
|
+
|
67
|
+
def rules
|
68
|
+
@rules ||= { children: { required: false } }
|
69
|
+
end
|
70
|
+
|
71
|
+
def define_rule(name, options = {})
|
72
|
+
rules[name] = coerce_native_hash_values(options)
|
73
|
+
@component_class.define_param(name, options[:type]) unless name == :params
|
74
|
+
end
|
75
|
+
|
76
|
+
def errors
|
77
|
+
@errors ||= []
|
78
|
+
end
|
79
|
+
|
80
|
+
def validate_types(prop_name, value)
|
81
|
+
return unless klass = rules[prop_name][:type]
|
82
|
+
if !klass.is_a?(Array)
|
83
|
+
allow_nil = !!rules[prop_name][:allow_nil]
|
84
|
+
type_check("`#{prop_name}`", value, klass, allow_nil)
|
85
|
+
elsif klass.length > 0
|
86
|
+
validate_value_array(prop_name, value)
|
87
|
+
else
|
88
|
+
allow_nil = !!rules[prop_name][:allow_nil]
|
89
|
+
type_check("`#{prop_name}`", value, Array, allow_nil)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def type_check(prop_name, value, klass, allow_nil)
|
94
|
+
return if allow_nil && value.nil?
|
95
|
+
return if value.is_a?(klass)
|
96
|
+
return if klass.respond_to?(:_react_param_conversion) &&
|
97
|
+
klass._react_param_conversion(value, :validate_only)
|
98
|
+
errors << "Provided prop #{prop_name} could not be converted to #{klass}"
|
99
|
+
end
|
100
|
+
|
101
|
+
def validate_allowed(prop_name, value)
|
102
|
+
return unless values = rules[prop_name][:values]
|
103
|
+
return if values.include?(value)
|
104
|
+
errors << "Value `#{value}` for prop `#{prop_name}` is not an allowed value"
|
105
|
+
end
|
106
|
+
|
107
|
+
def validate_required(props)
|
108
|
+
(rules.keys - props.keys).each do |name|
|
109
|
+
next unless rules[name][:required]
|
110
|
+
errors << "Required prop `#{name}` was not specified"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def validate_undefined(props)
|
115
|
+
(props.keys - rules.keys).each do |prop_name|
|
116
|
+
errors << "Provided prop `#{prop_name}` not specified in spec"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def validate_value_array(name, value)
|
121
|
+
klass = rules[name][:type]
|
122
|
+
allow_nil = !!rules[name][:allow_nil]
|
123
|
+
value.each_with_index do |item, index|
|
124
|
+
type_check("`#{name}`[#{index}]", Native(item), klass[0], allow_nil)
|
125
|
+
end
|
126
|
+
rescue NoMethodError
|
127
|
+
errors << "Provided prop `#{name}` was not an Array"
|
128
|
+
end
|
129
|
+
|
130
|
+
def coerce_native_hash_values(hash)
|
131
|
+
hash.each do |key, value|
|
132
|
+
hash[key] = Native(value)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module ReactiveRuby
|
2
|
+
class ComponentLoader
|
3
|
+
attr_reader :v8_context
|
4
|
+
private :v8_context
|
5
|
+
|
6
|
+
def initialize(v8_context)
|
7
|
+
unless v8_context
|
8
|
+
raise ArgumentError.new('Could not obtain ExecJS runtime context')
|
9
|
+
end
|
10
|
+
@v8_context = v8_context
|
11
|
+
end
|
12
|
+
|
13
|
+
def load(file = components)
|
14
|
+
return true if loaded?
|
15
|
+
!!v8_context.eval(opal(file))
|
16
|
+
end
|
17
|
+
|
18
|
+
def load!(file = components)
|
19
|
+
return true if loaded?
|
20
|
+
self.load(file)
|
21
|
+
ensure
|
22
|
+
raise "No react.rb components found in #{components}.rb" unless loaded?
|
23
|
+
end
|
24
|
+
|
25
|
+
def loaded?
|
26
|
+
!!v8_context.eval('Opal.React')
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def components
|
32
|
+
# Make this configurable at some point
|
33
|
+
'components'
|
34
|
+
end
|
35
|
+
|
36
|
+
def opal(file)
|
37
|
+
Opal::Processor.load_asset_code(assets, file)
|
38
|
+
rescue # What exception is being caught here?
|
39
|
+
end
|
40
|
+
|
41
|
+
def assets
|
42
|
+
::Rails.application.assets
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
module React
|
2
|
+
module IsomorphicHelpers
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
if RUBY_ENGINE != 'opal'
|
8
|
+
def self.load_context(ctx, controller, name = nil)
|
9
|
+
puts "************************** React Server Context Initialized #{name} *********************************************"
|
10
|
+
@context = Context.new("#{controller.object_id}-#{Time.now.to_i}", ctx, controller, name)
|
11
|
+
end
|
12
|
+
else
|
13
|
+
def self.load_context(unique_id = nil, name = nil)
|
14
|
+
# can be called on the client to force re-initialization for testing purposes
|
15
|
+
if !unique_id || !@context || @context.unique_id != unique_id
|
16
|
+
if on_opal_server?
|
17
|
+
message = "************************ React Prerendering Context Initialized #{name} ***********************"
|
18
|
+
else
|
19
|
+
message = "************************ React Browser Context Initialized ****************************"
|
20
|
+
end
|
21
|
+
log(message)
|
22
|
+
@context = Context.new(unique_id)
|
23
|
+
end
|
24
|
+
@context
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.log(message, message_type = :info)
|
29
|
+
message = [message] unless message.is_a? Array
|
30
|
+
if message_type == :info
|
31
|
+
if on_opal_server?
|
32
|
+
style = 'background: #00FFFF; color: red'
|
33
|
+
else
|
34
|
+
style = 'background: #222; color: #bada55'
|
35
|
+
end
|
36
|
+
message = ["%c" + message[0], style]+message[1..-1]
|
37
|
+
`console.log.apply(console, message)`
|
38
|
+
elsif message_type == :warning
|
39
|
+
`console.warn.apply(console, message)`
|
40
|
+
else
|
41
|
+
`console.error.apply(console, message)`
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
if RUBY_ENGINE != 'opal'
|
46
|
+
def self.on_opal_server?
|
47
|
+
false
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.on_opal_client?
|
51
|
+
false
|
52
|
+
end
|
53
|
+
else
|
54
|
+
def self.on_opal_server?
|
55
|
+
`typeof window.document === 'undefined'`
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.on_opal_client?
|
59
|
+
!on_opal_server?
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def log(*args)
|
64
|
+
IsomorphicHelpers.log(*args)
|
65
|
+
end
|
66
|
+
|
67
|
+
def on_opal_server?
|
68
|
+
self.class.on_opal_server?
|
69
|
+
end
|
70
|
+
|
71
|
+
def on_opal_client?
|
72
|
+
self.class.on_opal_client?
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.prerender_footers
|
76
|
+
footer = Context.prerender_footer_blocks.collect { |block| block.call }.join("\n")
|
77
|
+
if RUBY_ENGINE != 'opal'
|
78
|
+
footer = (footer + "#{@context.send_to_opal(:prerender_footers)}") if @context
|
79
|
+
footer = footer.html_safe
|
80
|
+
end
|
81
|
+
footer
|
82
|
+
end
|
83
|
+
|
84
|
+
class Context
|
85
|
+
attr_reader :controller
|
86
|
+
attr_reader :unique_id
|
87
|
+
|
88
|
+
def self.before_first_mount_blocks
|
89
|
+
@before_first_mount_blocks ||= []
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.prerender_footer_blocks
|
93
|
+
@prerender_footer_blocks ||= []
|
94
|
+
end
|
95
|
+
|
96
|
+
def initialize(unique_id, ctx = nil, controller = nil, name = nil)
|
97
|
+
@unique_id = unique_id
|
98
|
+
if RUBY_ENGINE != 'opal'
|
99
|
+
@controller = controller
|
100
|
+
@ctx = ctx
|
101
|
+
ctx["ServerSideIsomorphicMethods"] = self
|
102
|
+
send_to_opal(:load_context, @unique_id, name)
|
103
|
+
end
|
104
|
+
self.class.before_first_mount_blocks.each { |block| block.call(self) }
|
105
|
+
end
|
106
|
+
|
107
|
+
def eval(js)
|
108
|
+
@ctx.eval(js) if @ctx
|
109
|
+
end
|
110
|
+
|
111
|
+
def send_to_opal(method, *args)
|
112
|
+
return unless @ctx
|
113
|
+
args = [1] if args.length == 0
|
114
|
+
::ReactiveRuby::ComponentLoader.new(@ctx).load!
|
115
|
+
@ctx.eval("Opal.React.IsomorphicHelpers.$#{method}(#{args.collect { |arg| "'#{arg}'"}.join(', ')})")
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.register_before_first_mount_block(&block)
|
119
|
+
before_first_mount_blocks << block
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.register_prerender_footer_block(&block)
|
123
|
+
prerender_footer_blocks << block
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class IsomorphicProcCall
|
128
|
+
def result
|
129
|
+
@result.first if @result
|
130
|
+
end
|
131
|
+
|
132
|
+
def initialize(name, block, *args)
|
133
|
+
@name = name
|
134
|
+
block.call(self, *args)
|
135
|
+
@result ||= send_to_server(*args) if IsomorphicHelpers.on_opal_server?
|
136
|
+
end
|
137
|
+
|
138
|
+
def when_on_client(&block)
|
139
|
+
@result = [block.call] if IsomorphicHelpers.on_opal_client?
|
140
|
+
end
|
141
|
+
|
142
|
+
def send_to_server(*args)
|
143
|
+
if IsomorphicHelpers.on_opal_server?
|
144
|
+
args_as_json = args.to_json
|
145
|
+
@result = [JSON.parse(`window.ServerSideIsomorphicMethods[#{@name}](#{args_as_json})`)]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def when_on_server(&block)
|
150
|
+
@result = [block.call.to_json] unless IsomorphicHelpers.on_opal_client? || IsomorphicHelpers.on_opal_server?
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
module ClassMethods
|
155
|
+
def on_opal_server?
|
156
|
+
IsomorphicHelpers.on_opal_server?
|
157
|
+
end
|
158
|
+
|
159
|
+
def on_opal_client?
|
160
|
+
IsomorphicHelpers.on_opal_client?
|
161
|
+
end
|
162
|
+
|
163
|
+
def log(*args)
|
164
|
+
IsomorphicHelpers.log(*args)
|
165
|
+
end
|
166
|
+
|
167
|
+
def controller
|
168
|
+
IsomorphicHelpers.context.controller
|
169
|
+
end
|
170
|
+
|
171
|
+
def before_first_mount(&block)
|
172
|
+
React::IsomorphicHelpers::Context.register_before_first_mount_block &block
|
173
|
+
end
|
174
|
+
|
175
|
+
def prerender_footer(&block)
|
176
|
+
React::IsomorphicHelpers::Context.register_prerender_footer_block &block
|
177
|
+
end
|
178
|
+
|
179
|
+
if RUBY_ENGINE != 'opal'
|
180
|
+
def isomorphic_method(name, &block)
|
181
|
+
React::IsomorphicHelpers::Context.send(:define_method, name) do |args_as_json|
|
182
|
+
React::IsomorphicHelpers::IsomorphicProcCall.new(name, block, *JSON.parse(args_as_json)).result
|
183
|
+
end
|
184
|
+
end
|
185
|
+
else
|
186
|
+
require 'json'
|
187
|
+
|
188
|
+
def isomorphic_method(name, &block)
|
189
|
+
self.class.send(:define_method, name) do | *args |
|
190
|
+
React::IsomorphicHelpers::IsomorphicProcCall.new(name, block, *args).result
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
require 'action_view'
|
2
|
+
require 'react-rails'
|
3
|
+
require 'reactive-ruby/server_rendering/contextual_renderer'
|
4
|
+
require 'reactive-ruby/rails/component_mount'
|
5
|
+
require 'reactive-ruby/rails/railtie'
|
6
|
+
require 'reactive-ruby/rails/controller_helper'
|
7
|
+
require 'reactive-ruby/component_loader'
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module ReactiveRuby
|
2
|
+
module Rails
|
3
|
+
class ComponentMount < React::Rails::ComponentMount
|
4
|
+
attr_accessor :controller
|
5
|
+
|
6
|
+
def setup(controller)
|
7
|
+
self.controller = controller
|
8
|
+
end
|
9
|
+
|
10
|
+
def react_component(name, props = {}, options = {}, &block)
|
11
|
+
options = context_initializer_options(options, name) if options[:prerender]
|
12
|
+
props = serialized_props(props, name, controller)
|
13
|
+
super(top_level_name, props, options, &block) + footers
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def context_initializer_options(options, name)
|
19
|
+
options[:prerender] = {options[:prerender] => true} unless options[:prerender].is_a? Hash
|
20
|
+
existing_context_initializer = options[:prerender][:context_initializer]
|
21
|
+
|
22
|
+
options[:prerender][:context_initializer] = lambda do |ctx|
|
23
|
+
React::IsomorphicHelpers.load_context(ctx, controller, name)
|
24
|
+
existing_context_initializer.call ctx if existing_context_initializer
|
25
|
+
end
|
26
|
+
|
27
|
+
options
|
28
|
+
end
|
29
|
+
|
30
|
+
def serialized_props(props, name, controller)
|
31
|
+
{ render_params: props, component_name: name,
|
32
|
+
controller: controller.class.name.gsub(/Controller$/,"") }.react_serializer
|
33
|
+
end
|
34
|
+
|
35
|
+
def top_level_name
|
36
|
+
'React.TopLevelRailsComponent'
|
37
|
+
end
|
38
|
+
|
39
|
+
def footers
|
40
|
+
React::IsomorphicHelpers.prerender_footers #if options[:prerender]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'action_controller'
|
2
|
+
|
3
|
+
module ReactiveRuby
|
4
|
+
module Rails
|
5
|
+
class ActionController::Base
|
6
|
+
def render_component(*args)
|
7
|
+
@component_name = ((args[0].is_a? Hash) || args.empty?) ? params[:action].camelize : args.shift
|
8
|
+
@render_params = (args[0].is_a? Hash) ? args[0] : {}
|
9
|
+
render inline: "<%= react_component @component_name, @render_params, { prerender: !params[:no_prerender] } %>", layout: 'application'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|