hyper-component 0.99.6 → 1.0.alpha1
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 +4 -4
- data/CHANGELOG.md +3 -3
- data/Gemfile +4 -3
- data/Gemfile.lock +51 -36
- data/{misc/how-component-name-lookup-works.md → how-component-name-lookup-works.md} +1 -1
- data/hyper-component.gemspec +9 -8
- data/lib/hyper-component.rb +31 -43
- data/lib/hyperstack/component.rb +145 -0
- data/lib/hyperstack/component/auto-import.rb +44 -0
- data/lib/hyperstack/component/children.rb +40 -0
- data/lib/hyperstack/component/element.rb +129 -0
- data/lib/hyperstack/component/event.rb +78 -0
- data/lib/hyperstack/component/haml.rb +18 -0
- data/lib/hyperstack/component/isomorphic_helpers.rb +235 -0
- data/lib/hyperstack/component/jquery.rb +2 -0
- data/lib/hyperstack/component/native_library.rb +92 -0
- data/lib/hyperstack/component/react_api.rb +142 -0
- data/lib/hyperstack/component/server.rb +21 -0
- data/lib/hyperstack/component/version.rb +5 -0
- data/lib/hyperstack/ext/component/boolean.rb +14 -0
- data/lib/{react/ext/opal-jquery → hyperstack/ext/component}/element.rb +17 -12
- data/lib/{react/ext → hyperstack/ext/component}/hash.rb +0 -0
- data/lib/{react/to_key.rb → hyperstack/ext/component/number.rb} +0 -12
- data/lib/hyperstack/ext/component/object.rb +32 -0
- data/lib/{reactive-ruby → hyperstack/ext/component}/serializers.rb +0 -0
- data/lib/{react/ext → hyperstack/ext/component}/string.rb +0 -0
- data/lib/hyperstack/internal/component.rb +16 -0
- data/lib/hyperstack/internal/component/class_methods.rb +212 -0
- data/lib/hyperstack/internal/component/haml.rb +56 -0
- data/lib/hyperstack/internal/component/instance_methods.rb +92 -0
- data/lib/hyperstack/internal/component/props_wrapper.rb +125 -0
- data/lib/hyperstack/internal/component/rails.rb +11 -0
- data/lib/hyperstack/internal/component/rails/component_loader.rb +49 -0
- data/lib/hyperstack/internal/component/rails/component_mount.rb +52 -0
- data/lib/{reactive-ruby → hyperstack/internal/component}/rails/controller_helper.rb +0 -0
- data/lib/hyperstack/internal/component/rails/railtie.rb +24 -0
- data/lib/hyperstack/internal/component/rails/server_rendering/contextual_renderer.rb +52 -0
- data/lib/hyperstack/internal/component/rails/server_rendering/hyper_asset_container.rb +52 -0
- data/lib/hyperstack/internal/component/react_wrapper.rb +308 -0
- data/lib/hyperstack/internal/component/rendering_context.rb +165 -0
- data/lib/hyperstack/internal/component/should_component_update.rb +101 -0
- data/lib/hyperstack/internal/component/tags.rb +109 -0
- data/lib/hyperstack/internal/component/top_level_rails_component.rb +83 -0
- data/lib/hyperstack/internal/component/validator.rb +149 -0
- data/lib/react/react-source.rb +2 -2
- data/unmounting-objects.md +78 -0
- metadata +73 -85
- data/DOCS.md +0 -1515
- data/LICENSE +0 -19
- data/README.md +0 -49
- data/lib/hyper-component/jquery.rb +0 -2
- data/lib/rails-helpers/top_level_rails_component.rb +0 -79
- data/lib/react/api.rb +0 -272
- data/lib/react/callbacks.rb +0 -42
- data/lib/react/children.rb +0 -38
- data/lib/react/component.rb +0 -189
- data/lib/react/component/api.rb +0 -70
- data/lib/react/component/base.rb +0 -13
- data/lib/react/component/class_methods.rb +0 -175
- data/lib/react/component/dsl_instance_methods.rb +0 -23
- data/lib/react/component/params.rb +0 -6
- data/lib/react/component/props_wrapper.rb +0 -90
- data/lib/react/component/should_component_update.rb +0 -99
- data/lib/react/component/tags.rb +0 -116
- data/lib/react/config.rb +0 -5
- data/lib/react/element.rb +0 -167
- data/lib/react/event.rb +0 -76
- data/lib/react/native_library.rb +0 -87
- data/lib/react/object.rb +0 -15
- data/lib/react/ref_callback.rb +0 -31
- data/lib/react/rendering_context.rb +0 -149
- data/lib/react/server.rb +0 -19
- data/lib/react/state_wrapper.rb +0 -23
- data/lib/react/test.rb +0 -16
- data/lib/react/test/dsl.rb +0 -17
- data/lib/react/test/matchers/render_html_matcher.rb +0 -56
- data/lib/react/test/rspec.rb +0 -15
- data/lib/react/test/session.rb +0 -37
- data/lib/react/test/utils.rb +0 -71
- data/lib/react/top_level.rb +0 -110
- data/lib/react/top_level_render.rb +0 -30
- data/lib/react/validator.rb +0 -132
- data/lib/reactive-ruby/component_loader.rb +0 -43
- data/lib/reactive-ruby/isomorphic_helpers.rb +0 -233
- data/lib/reactive-ruby/rails.rb +0 -8
- data/lib/reactive-ruby/rails/component_mount.rb +0 -48
- data/lib/reactive-ruby/rails/railtie.rb +0 -20
- data/lib/reactive-ruby/server_rendering/contextual_renderer.rb +0 -46
- data/lib/reactive-ruby/server_rendering/hyper_asset_container.rb +0 -46
- data/lib/reactive-ruby/version.rb +0 -5
- data/lib/reactrb/auto-import.rb +0 -27
- data/misc/generators/reactive_ruby/test_app/templates/assets/javascripts/components.rb +0 -3
- data/misc/generators/reactive_ruby/test_app/templates/assets/javascripts/server_rendering.js +0 -5
- data/misc/generators/reactive_ruby/test_app/templates/assets/javascripts/test_application.rb +0 -2
- data/misc/generators/reactive_ruby/test_app/templates/boot.rb.erb +0 -6
- data/misc/generators/reactive_ruby/test_app/templates/script/rails +0 -5
- data/misc/generators/reactive_ruby/test_app/templates/test_application.rb.erb +0 -13
- data/misc/generators/reactive_ruby/test_app/templates/views/components/hello_world.rb +0 -11
- data/misc/generators/reactive_ruby/test_app/templates/views/components/todo.rb +0 -14
- data/misc/generators/reactive_ruby/test_app/templates/views/layouts/test_layout.html.erb +0 -0
- data/misc/generators/reactive_ruby/test_app/test_app_generator.rb +0 -121
- data/misc/hyperloop-logo-small-pink.png +0 -0
- data/misc/logo1.png +0 -0
- data/misc/logo2.png +0 -0
- data/misc/logo3.png +0 -0
- data/path_release_steps.md +0 -9
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# rubocop:disable Style/FileName
|
|
2
|
+
# require 'reactrb/auto-import' to automatically
|
|
3
|
+
# import JS libraries and components when they are detected
|
|
4
|
+
if RUBY_ENGINE == 'opal'
|
|
5
|
+
# modifies const and method_missing so that they will attempt
|
|
6
|
+
# to auto import native libraries and components using Hyperstack::Component::NativeLibrary
|
|
7
|
+
class Object
|
|
8
|
+
class << self
|
|
9
|
+
alias _reactrb_original_const_missing const_missing
|
|
10
|
+
alias _reactrb_original_method_missing method_missing
|
|
11
|
+
|
|
12
|
+
def const_missing(const_name)
|
|
13
|
+
# Opal uses const_missing to initially define things,
|
|
14
|
+
# so we always call the original, and respond to the exception
|
|
15
|
+
_reactrb_original_const_missing(const_name)
|
|
16
|
+
rescue StandardError => e
|
|
17
|
+
Hyperstack::Internal::Component::NativeLibrary.import_const_from_native(Object, const_name, true) || raise(e)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def _reactrb_import_component_class(method)
|
|
21
|
+
Hyperstack::Internal::Component::NativeLibrary.import_const_from_native(self, method, false)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def method_missing(method, *args, &block)
|
|
25
|
+
component_class = _reactrb_import_component_class(method)
|
|
26
|
+
_reactrb_original_method_missing(method, *args, &block) unless component_class
|
|
27
|
+
Hyperstack::Internal::Component::RenderingContext.render(component_class, *args, &block)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# The public NativeLibrary can't be used directly to
|
|
33
|
+
# import_const_from_native, because it is set to import from
|
|
34
|
+
# `window.NativeLibrary`. So we set up an internal class that won't
|
|
35
|
+
# have any prefix defined.
|
|
36
|
+
module Hyperstack
|
|
37
|
+
module Internal
|
|
38
|
+
module Component
|
|
39
|
+
class NativeLibrary < Hyperstack::Component::NativeLibrary
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Hyperstack
|
|
2
|
+
module Component
|
|
3
|
+
class Children
|
|
4
|
+
include Enumerable
|
|
5
|
+
|
|
6
|
+
def initialize(children)
|
|
7
|
+
@children = children
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def render
|
|
11
|
+
each(&:render)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_proc
|
|
15
|
+
-> () { render }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def each(&block)
|
|
19
|
+
return to_enum(__callee__) { length } unless block_given?
|
|
20
|
+
return [] unless length > 0
|
|
21
|
+
collection = []
|
|
22
|
+
%x{
|
|
23
|
+
React.Children.forEach(#{@children}, function(context){
|
|
24
|
+
#{
|
|
25
|
+
element = Element.new(`context`)
|
|
26
|
+
block.call(element)
|
|
27
|
+
collection << element
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
collection
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def length
|
|
35
|
+
@length ||= `React.Children.count(#{@children})`
|
|
36
|
+
end
|
|
37
|
+
alias_method :size, :length
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
require 'hyperstack/ext/component/string'
|
|
2
|
+
|
|
3
|
+
module Hyperstack
|
|
4
|
+
module Component
|
|
5
|
+
#
|
|
6
|
+
# Wraps the React Native element class
|
|
7
|
+
#
|
|
8
|
+
# adds the #on method to add event handlers to the element
|
|
9
|
+
#
|
|
10
|
+
# adds the #render method to place elements in the DOM and
|
|
11
|
+
# #delete (alias/deprecated #as_node) method to remove elements from the DOM
|
|
12
|
+
#
|
|
13
|
+
# handles the haml style class notation so that
|
|
14
|
+
# div.bar.blat becomes div(class: "bar blat")
|
|
15
|
+
# by using method missing
|
|
16
|
+
#
|
|
17
|
+
class Element
|
|
18
|
+
include Native
|
|
19
|
+
|
|
20
|
+
alias_native :element_type, :type
|
|
21
|
+
alias_native :props, :props
|
|
22
|
+
|
|
23
|
+
attr_reader :type
|
|
24
|
+
attr_reader :properties
|
|
25
|
+
attr_reader :block
|
|
26
|
+
|
|
27
|
+
attr_accessor :waiting_on_resources
|
|
28
|
+
|
|
29
|
+
def initialize(native_element, type = nil, properties = {}, block = nil)
|
|
30
|
+
@type = type
|
|
31
|
+
@properties = (`typeof #{properties} === 'undefined'` ? nil : properties) || {}
|
|
32
|
+
@block = block
|
|
33
|
+
@native = native_element
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Attach event handlers.
|
|
37
|
+
|
|
38
|
+
def on(*event_names, &block)
|
|
39
|
+
event_names.each { |event_name| merge_event_prop!(event_name, &block) }
|
|
40
|
+
@native = `React.cloneElement(#{@native}, #{@properties.shallow_to_n})`
|
|
41
|
+
self
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Render element into DOM in the current rendering context.
|
|
45
|
+
# Used for elements that are not yet in DOM, i.e. they are provided as children
|
|
46
|
+
# or they have been explicitly removed from the rendering context using the delete method.
|
|
47
|
+
|
|
48
|
+
def render(props = {}, &new_block)
|
|
49
|
+
if props.empty?
|
|
50
|
+
Hyperstack::Internal::Component::RenderingContext.render(self)
|
|
51
|
+
else
|
|
52
|
+
props = Hyperstack::Internal::Component::ReactWrapper.convert_props(props)
|
|
53
|
+
Hyperstack::Internal::Component::RenderingContext.render(
|
|
54
|
+
Element.new(`React.cloneElement(#{@native}, #{props.shallow_to_n})`,
|
|
55
|
+
type, @properties.merge(props), block)
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Delete (remove) element from rendering context, the element may later be added back in
|
|
61
|
+
# using the render method.
|
|
62
|
+
|
|
63
|
+
def delete
|
|
64
|
+
Hyperstack::Internal::Component::RenderingContext.delete(self)
|
|
65
|
+
end
|
|
66
|
+
# Deprecated version of delete method
|
|
67
|
+
alias as_node delete
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
# built in events, events going to native components, and events going to reactrb
|
|
72
|
+
|
|
73
|
+
# built in events will have their event param translated to the Event wrapper
|
|
74
|
+
# and the name will camelcased and have on prefixed, so :click becomes onClick.
|
|
75
|
+
#
|
|
76
|
+
# events emitting from native components are assumed to have the same camel case and
|
|
77
|
+
# on prefixed.
|
|
78
|
+
#
|
|
79
|
+
# events emitting from reactrb components will just have on_ prefixed. So
|
|
80
|
+
# :play_button_pushed attaches to the :on_play_button_pushed param
|
|
81
|
+
#
|
|
82
|
+
# in all cases the default name convention can be overriden by wrapping in <...> brackets.
|
|
83
|
+
# So on("<MyEvent>") will attach to the "MyEvent" param.
|
|
84
|
+
|
|
85
|
+
def merge_event_prop!(event_name, &block)
|
|
86
|
+
if event_name =~ /^<(.+)>$/
|
|
87
|
+
merge_component_event_prop! event_name.gsub(/^<(.+)>$/, '\1'), &block
|
|
88
|
+
elsif Event::BUILT_IN_EVENTS.include?(name = "on#{event_name.event_camelize}")
|
|
89
|
+
merge_built_in_event_prop! name, &block
|
|
90
|
+
elsif event_name == :enter
|
|
91
|
+
merge_built_in_event_prop!('onKeyDown') { |evt| yield(evt) if evt.key_code == 13 }
|
|
92
|
+
elsif @type.instance_variable_get('@native_import')
|
|
93
|
+
merge_component_event_prop! name, &block
|
|
94
|
+
else
|
|
95
|
+
merge_component_event_prop! "on_#{event_name}", &block
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def merge_built_in_event_prop!(prop_name)
|
|
100
|
+
@properties.merge!(
|
|
101
|
+
prop_name => %x{
|
|
102
|
+
function(){
|
|
103
|
+
var react_event = arguments[0];
|
|
104
|
+
var all_args;
|
|
105
|
+
var other_args;
|
|
106
|
+
if (arguments.length > 1) {
|
|
107
|
+
all_args = Array.prototype.slice.call(arguments);
|
|
108
|
+
other_args = all_args.slice(1, arguments.length);
|
|
109
|
+
return #{yield(Event.new(`react_event`), *(`other_args`))};
|
|
110
|
+
} else {
|
|
111
|
+
return #{yield(Event.new(`react_event`))};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def merge_component_event_prop!(prop_name)
|
|
119
|
+
@properties.merge!(
|
|
120
|
+
prop_name => %x{
|
|
121
|
+
function(){
|
|
122
|
+
return #{yield(*Array(`arguments`))}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module Hyperstack
|
|
2
|
+
module Component
|
|
3
|
+
class Event
|
|
4
|
+
include Native
|
|
5
|
+
alias_native :bubbles, :bubbles
|
|
6
|
+
alias_native :cancelable, :cancelable
|
|
7
|
+
alias_native :current_target, :currentTarget
|
|
8
|
+
alias_native :default_prevented, :defaultPrevented
|
|
9
|
+
alias_native :event_phase, :eventPhase
|
|
10
|
+
alias_native :is_trusted?, :isTrusted
|
|
11
|
+
alias_native :native_event, :nativeEvent
|
|
12
|
+
alias_native :target, :target
|
|
13
|
+
alias_native :timestamp, :timeStamp
|
|
14
|
+
alias_native :event_type, :type
|
|
15
|
+
alias_native :prevent_default, :preventDefault
|
|
16
|
+
alias_native :stop_propagation, :stopPropagation
|
|
17
|
+
# Clipboard
|
|
18
|
+
alias_native :clipboard_data, :clipboardData
|
|
19
|
+
# Keyboard
|
|
20
|
+
alias_native :alt_key, :altKey
|
|
21
|
+
alias_native :char_code, :charCode
|
|
22
|
+
alias_native :ctrl_key, :ctrlKey
|
|
23
|
+
alias_native :get_modifier_state, :getModifierState
|
|
24
|
+
alias_native :key, :key
|
|
25
|
+
alias_native :key_code, :keyCode
|
|
26
|
+
alias_native :locale, :locale
|
|
27
|
+
alias_native :location, :location
|
|
28
|
+
alias_native :meta_key, :metaKey
|
|
29
|
+
alias_native :repeat, :repeat
|
|
30
|
+
alias_native :shift_key, :shiftKey
|
|
31
|
+
alias_native :which, :which
|
|
32
|
+
# Focus
|
|
33
|
+
alias_native :related_target, :relatedTarget
|
|
34
|
+
# Mouse
|
|
35
|
+
# aliased above: alias_native :alt_key, :altKey
|
|
36
|
+
alias_native :button, :button
|
|
37
|
+
alias_native :buttons, :buttons
|
|
38
|
+
alias_native :client_x, :clientX
|
|
39
|
+
alias_native :client_y, :clientY
|
|
40
|
+
# aliased above: alias_native :ctrl_key, :ctrlKey
|
|
41
|
+
alias_native :get_modifier_state, :getModifierState
|
|
42
|
+
# aliased above: alias_native :meta_key, :metaKey
|
|
43
|
+
alias_native :page_x, :pageX
|
|
44
|
+
alias_native :page_y, :pageY
|
|
45
|
+
# aliased above: alias_native :related_target, :relatedTarget
|
|
46
|
+
alias_native :screen_x, :screen_x
|
|
47
|
+
alias_native :screen_y, :screen_y
|
|
48
|
+
# aliased above: alias_native :shift_key, :shift_key
|
|
49
|
+
# Touch
|
|
50
|
+
# aliased above: alias_native :alt_key, :altKey
|
|
51
|
+
alias_native :changed_touches, :changedTouches
|
|
52
|
+
# aliased above: alias_native :ctrl_key, :ctrlKey
|
|
53
|
+
# aliased above: alias_native :get_modifier_state, :getModifierState
|
|
54
|
+
# aliased above: alias_native :meta_key, :metaKey
|
|
55
|
+
# aliased above: alias_native :shift_key, :shiftKey
|
|
56
|
+
alias_native :target_touches, :targetTouches
|
|
57
|
+
alias_native :touches, :touches
|
|
58
|
+
# UI
|
|
59
|
+
alias_native :detail, :detail
|
|
60
|
+
alias_native :view, :view
|
|
61
|
+
# Wheel
|
|
62
|
+
alias_native :delta_mode, :deltaMode
|
|
63
|
+
alias_native :delta_x, :deltaX
|
|
64
|
+
alias_native :delta_y, :deltaY
|
|
65
|
+
alias_native :delta_z, :deltaZ
|
|
66
|
+
|
|
67
|
+
BUILT_IN_EVENTS = %w{onCopy onCut onPaste onKeyDown onKeyPress onKeyUp
|
|
68
|
+
onFocus onBlur onChange onInput onSubmit onClick onContextMenu onDoubleClick onDrag
|
|
69
|
+
onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop
|
|
70
|
+
onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver
|
|
71
|
+
onMouseUp onSelect onTouchCancel onTouchEnd onTouchMove onTouchStart onScroll onWheel}
|
|
72
|
+
|
|
73
|
+
def initialize(native_event)
|
|
74
|
+
@native = native_event
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'hyperstack/internal/component/haml'
|
|
2
|
+
# to allow for easier testing we include the internal mixins
|
|
3
|
+
# from hyperstack/internal/component/haml
|
|
4
|
+
# see spec/deprecated_features/haml_spec
|
|
5
|
+
module Hyperstack
|
|
6
|
+
module Internal
|
|
7
|
+
module Component
|
|
8
|
+
module Tags
|
|
9
|
+
include HAMLTagInstanceMethods
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
module Component
|
|
14
|
+
class Element
|
|
15
|
+
include HAMLElementInstanceMethods
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
require "hyperstack/internal/component"
|
|
2
|
+
|
|
3
|
+
module Hyperstack
|
|
4
|
+
module Component
|
|
5
|
+
module IsomorphicHelpers
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.extend(ClassMethods)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
if RUBY_ENGINE != 'opal'
|
|
11
|
+
def self.load_context(ctx, controller, name = nil)
|
|
12
|
+
@context = Context.new("#{controller.object_id}-#{Time.now.to_i}", ctx, controller, name)
|
|
13
|
+
@context.load_opal_context
|
|
14
|
+
::Rails.logger.debug "************************** React Server Context Initialized #{name} #{Time.now.to_f} *********************************************"
|
|
15
|
+
@context
|
|
16
|
+
end
|
|
17
|
+
else
|
|
18
|
+
def self.load_context(unique_id = nil, name = nil)
|
|
19
|
+
# can be called on the client to force re-initialization for testing purposes
|
|
20
|
+
if !unique_id || !@context || @context.unique_id != unique_id
|
|
21
|
+
if on_opal_server?
|
|
22
|
+
`console.history = []` rescue nil
|
|
23
|
+
message = "************************ React Prerendering Context Initialized #{name} ***********************"
|
|
24
|
+
else
|
|
25
|
+
message = "************************ React Browser Context Initialized ****************************"
|
|
26
|
+
end
|
|
27
|
+
log(message)
|
|
28
|
+
@context = Context.new(unique_id)
|
|
29
|
+
end
|
|
30
|
+
@context
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.context
|
|
35
|
+
@context
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.log(message, message_type = :info)
|
|
39
|
+
message = [message] unless message.is_a? Array
|
|
40
|
+
|
|
41
|
+
if (message_type == :info || message_type == :warning) && Hyperstack.env.production?
|
|
42
|
+
return
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
if message_type == :info
|
|
46
|
+
if on_opal_server?
|
|
47
|
+
style = 'background: #00FFFF; color: red'
|
|
48
|
+
else
|
|
49
|
+
style = 'background: #222; color: #bada55'
|
|
50
|
+
end
|
|
51
|
+
message = ["%c" + message[0], style]+message[1..-1]
|
|
52
|
+
`console.log.apply(console, message)`
|
|
53
|
+
elsif message_type == :warning
|
|
54
|
+
`console.warn.apply(console, message)`
|
|
55
|
+
else
|
|
56
|
+
`console.error.apply(console, message)`
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
if RUBY_ENGINE != 'opal'
|
|
61
|
+
def self.on_opal_server?
|
|
62
|
+
false
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def self.on_opal_client?
|
|
66
|
+
false
|
|
67
|
+
end
|
|
68
|
+
else
|
|
69
|
+
def self.on_opal_server?
|
|
70
|
+
`typeof Opal.global.document === 'undefined'`
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def self.on_opal_client?
|
|
74
|
+
!on_opal_server?
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def log(*args)
|
|
79
|
+
IsomorphicHelpers.log(*args)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def on_opal_server?
|
|
83
|
+
self.class.on_opal_server?
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def on_opal_client?
|
|
87
|
+
self.class.on_opal_client?
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def self.prerender_footers(controller = nil)
|
|
91
|
+
footer = Context.prerender_footer_blocks.collect { |block| block.call controller }.join("\n")
|
|
92
|
+
if RUBY_ENGINE != 'opal'
|
|
93
|
+
footer = (footer + @context.send_to_opal(:prerender_footers).to_s) if @context
|
|
94
|
+
footer = footer.html_safe
|
|
95
|
+
end
|
|
96
|
+
footer
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
class Context
|
|
100
|
+
attr_reader :controller
|
|
101
|
+
attr_reader :unique_id
|
|
102
|
+
|
|
103
|
+
def self.define_isomorphic_method(method_name, &block)
|
|
104
|
+
@@ctx_methods ||= {}
|
|
105
|
+
@@ctx_methods[method_name] = block
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def self.before_first_mount_blocks
|
|
109
|
+
@before_first_mount_blocks ||= []
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def self.prerender_footer_blocks
|
|
113
|
+
@prerender_footer_blocks ||= []
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def initialize(unique_id, ctx = nil, controller = nil, cname = nil)
|
|
117
|
+
@unique_id = unique_id
|
|
118
|
+
@cname = cname
|
|
119
|
+
if RUBY_ENGINE != 'opal'
|
|
120
|
+
@controller = controller
|
|
121
|
+
@ctx = ctx
|
|
122
|
+
if defined? @@ctx_methods
|
|
123
|
+
@@ctx_methods.each do |method_name, block|
|
|
124
|
+
@ctx.attach("ServerSideIsomorphicMethod.#{method_name}", proc{|args| block.call(args.to_json)})
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
Hyperstack::Application::Boot.run(context: self)
|
|
129
|
+
self.class.before_first_mount_blocks.each { |block| block.call(self) }
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def load_opal_context
|
|
133
|
+
send_to_opal(:load_context, @unique_id, @cname)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def eval(js)
|
|
137
|
+
@ctx.eval(js) if @ctx
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def send_to_opal(method_name, *args)
|
|
141
|
+
return unless @ctx
|
|
142
|
+
args = [1] if args.length == 0
|
|
143
|
+
Hyperstack::Internal::Component::Rails::ComponentLoader.new(@ctx).load!
|
|
144
|
+
method_args = args.collect do |arg|
|
|
145
|
+
quarg = "#{arg}".tr('"', "'")
|
|
146
|
+
"\"#{quarg}\""
|
|
147
|
+
end.join(', ')
|
|
148
|
+
@ctx.eval("Opal.Hyperstack.$const_get('Component').$const_get('IsomorphicHelpers').$#{method_name}(#{method_args})")
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def self.register_before_first_mount_block(&block)
|
|
152
|
+
before_first_mount_blocks << block
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def self.register_prerender_footer_block(&block)
|
|
156
|
+
prerender_footer_blocks << block
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
class IsomorphicProcCall
|
|
161
|
+
|
|
162
|
+
attr_reader :context
|
|
163
|
+
|
|
164
|
+
def result
|
|
165
|
+
@result.first if @result
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def initialize(name, block, context, *args)
|
|
169
|
+
@name = name
|
|
170
|
+
@context = context
|
|
171
|
+
block.call(self, *args)
|
|
172
|
+
@result ||= send_to_server(*args)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def when_on_client(&block)
|
|
176
|
+
@result = [block.call] if IsomorphicHelpers.on_opal_client?
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def send_to_server(*args)
|
|
180
|
+
if IsomorphicHelpers.on_opal_server?
|
|
181
|
+
method_string = "ServerSideIsomorphicMethod." + @name + "(" + args.to_json + ")"
|
|
182
|
+
@result = [JSON.parse(`eval(method_string)`)]
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def when_on_server(&block)
|
|
187
|
+
@result = [block.call.to_json] unless IsomorphicHelpers.on_opal_client? || IsomorphicHelpers.on_opal_server?
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
module ClassMethods
|
|
192
|
+
def on_opal_server?
|
|
193
|
+
IsomorphicHelpers.on_opal_server?
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def on_opal_client?
|
|
197
|
+
IsomorphicHelpers.on_opal_client?
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def log(*args)
|
|
201
|
+
IsomorphicHelpers.log(*args)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def controller
|
|
205
|
+
IsomorphicHelpers.context.controller
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def before_first_mount(&block)
|
|
209
|
+
IsomorphicHelpers::Context.register_before_first_mount_block(&block)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def prerender_footer(&block)
|
|
213
|
+
IsomorphicHelpers::Context.register_prerender_footer_block(&block)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
if RUBY_ENGINE != 'opal'
|
|
217
|
+
def isomorphic_method(name, &block)
|
|
218
|
+
IsomorphicHelpers::Context.send(:define_isomorphic_method, name) do |args_as_json|
|
|
219
|
+
IsomorphicHelpers::IsomorphicProcCall.new(name, block, self, *JSON.parse(args_as_json)).result
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
else
|
|
223
|
+
require 'json'
|
|
224
|
+
|
|
225
|
+
def isomorphic_method(name, &block)
|
|
226
|
+
self.class.send(:define_method, name) do | *args |
|
|
227
|
+
IsomorphicHelpers::IsomorphicProcCall.new(name, block, self, *args).result
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
end
|