ovto 0.5.0 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitmodules +3 -0
- data/CHANGELOG.md +14 -2
- data/Gemfile +2 -3
- data/Gemfile.lock +23 -27
- data/book/SUMMARY.md +2 -0
- data/book/api/actions.md +1 -1
- data/book/api/middleware.md +99 -0
- data/book/api/pure_component.md +3 -0
- data/docs/api/Array.html +190 -0
- data/docs/api/Hash.html +196 -0
- data/docs/api/Ovto/Actions.html +128 -40
- data/docs/api/Ovto/App.html +254 -40
- data/docs/api/Ovto/Component/MoreThanOneNode.html +6 -6
- data/docs/api/Ovto/Component.html +96 -29
- data/docs/api/Ovto/Middleware/Actions.html +428 -0
- data/docs/api/Ovto/Middleware/Base.html +605 -0
- data/docs/api/Ovto/Middleware/Component.html +354 -0
- data/docs/api/Ovto/Middleware.html +286 -0
- data/docs/api/Ovto/PureComponent/StateIsNotAvailable.html +6 -6
- data/docs/api/Ovto/PureComponent.html +11 -11
- data/docs/api/Ovto/Runtime.html +7 -7
- data/docs/api/Ovto/State/MissingValue.html +6 -6
- data/docs/api/Ovto/State/{UnknownKey.html → UnknownStateKey.html} +11 -11
- data/docs/api/Ovto/State.html +59 -43
- data/docs/api/Ovto/WiredActionSet.html +636 -0
- data/docs/api/Ovto/WiredActions.html +78 -35
- data/docs/api/Ovto.html +223 -30
- data/docs/api/_index.html +77 -11
- data/docs/api/actions.html +29 -3
- data/docs/api/app.html +28 -2
- data/docs/api/class_list.html +3 -3
- data/docs/api/component.html +30 -4
- data/docs/api/css/style.css +3 -2
- data/docs/api/fetch.html +30 -4
- data/docs/api/file.README.html +76 -78
- data/docs/api/file_list.html +2 -2
- data/docs/api/frames.html +2 -2
- data/docs/api/index.html +76 -78
- data/docs/api/js/app.js +14 -3
- data/docs/api/method_list.html +303 -31
- data/docs/api/middleware.html +498 -0
- data/docs/api/pure_component.html +428 -0
- data/docs/api/state.html +28 -2
- data/docs/api/top-level-namespace.html +11 -9
- data/docs/guides/debugging.html +28 -2
- data/docs/guides/development.html +28 -2
- data/docs/guides/install.html +28 -2
- data/docs/guides/tutorial.html +28 -2
- data/docs/index.html +28 -2
- data/docs/search_index.json +1 -1
- data/examples/sinatra/Gemfile +2 -0
- data/examples/sinatra/Gemfile.lock +32 -30
- data/examples/sinatra/app.rb +1 -4
- data/examples/sinatra/config.ru +6 -6
- data/examples/static/Gemfile.lock +9 -9
- data/lib/ovto/actions.rb +11 -0
- data/lib/ovto/app.rb +37 -13
- data/lib/ovto/component.rb +130 -67
- data/lib/ovto/middleware.rb +121 -0
- data/lib/ovto/pure_component.rb +1 -1
- data/lib/ovto/state.rb +13 -5
- data/lib/ovto/version.rb +1 -1
- data/lib/ovto/wired_action_set.rb +40 -0
- data/lib/ovto/wired_actions.rb +49 -11
- data/lib/ovto.rb +26 -0
- data/ovto.gemspec +1 -1
- metadata +21 -11
- data/docs/api/pure_component.md +0 -27
data/examples/sinatra/Gemfile
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: ../..
|
3
3
|
specs:
|
4
|
-
ovto (0.
|
4
|
+
ovto (0.6.0)
|
5
5
|
opal (>= 0.11, < 2)
|
6
6
|
rack (~> 2.0)
|
7
7
|
thor (~> 0.20)
|
@@ -9,44 +9,44 @@ PATH
|
|
9
9
|
GEM
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
|
-
ast (2.4.
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
opal (
|
12
|
+
ast (2.4.2)
|
13
|
+
concurrent-ruby (1.1.9)
|
14
|
+
multi_json (1.15.0)
|
15
|
+
mustermann (1.1.1)
|
16
|
+
ruby2_keywords (~> 0.0.1)
|
17
|
+
nio4r (2.5.8)
|
18
|
+
opal (1.2.0)
|
19
19
|
ast (>= 2.3.0)
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
opal (~> 0.11.0)
|
25
|
-
sprockets (~> 3.7)
|
20
|
+
parser (~> 3.0)
|
21
|
+
opal-sprockets (1.0.2)
|
22
|
+
opal (>= 1.0, < 2.0)
|
23
|
+
sprockets (~> 4.0)
|
26
24
|
tilt (>= 1.4)
|
27
|
-
parser (
|
28
|
-
ast (~> 2.
|
29
|
-
|
30
|
-
|
25
|
+
parser (3.0.2.0)
|
26
|
+
ast (~> 2.4.1)
|
27
|
+
puma (5.5.2)
|
28
|
+
nio4r (~> 2.0)
|
29
|
+
rack (2.2.3)
|
30
|
+
rack-protection (2.1.0)
|
31
31
|
rack
|
32
|
-
|
32
|
+
rake (13.0.6)
|
33
|
+
ruby2_keywords (0.0.5)
|
34
|
+
sinatra (2.1.0)
|
33
35
|
mustermann (~> 1.0)
|
34
|
-
rack (~> 2.
|
35
|
-
rack-protection (= 2.0
|
36
|
+
rack (~> 2.2)
|
37
|
+
rack-protection (= 2.1.0)
|
36
38
|
tilt (~> 2.0)
|
37
|
-
sinatra-contrib (2.0
|
38
|
-
backports (>= 2.8.2)
|
39
|
+
sinatra-contrib (2.1.0)
|
39
40
|
multi_json
|
40
41
|
mustermann (~> 1.0)
|
41
|
-
rack-protection (= 2.0
|
42
|
-
sinatra (= 2.0
|
43
|
-
tilt (
|
44
|
-
|
45
|
-
sprockets (3.7.2)
|
42
|
+
rack-protection (= 2.1.0)
|
43
|
+
sinatra (= 2.1.0)
|
44
|
+
tilt (~> 2.0)
|
45
|
+
sprockets (4.0.2)
|
46
46
|
concurrent-ruby (~> 1.0)
|
47
47
|
rack (> 1, < 3)
|
48
48
|
thor (0.20.3)
|
49
|
-
tilt (2.0.
|
49
|
+
tilt (2.0.10)
|
50
50
|
|
51
51
|
PLATFORMS
|
52
52
|
ruby
|
@@ -54,9 +54,11 @@ PLATFORMS
|
|
54
54
|
DEPENDENCIES
|
55
55
|
opal-sprockets
|
56
56
|
ovto!
|
57
|
+
puma
|
57
58
|
rack
|
59
|
+
rake
|
58
60
|
sinatra
|
59
61
|
sinatra-contrib
|
60
62
|
|
61
63
|
BUNDLED WITH
|
62
|
-
2.
|
64
|
+
2.2.22
|
data/examples/sinatra/app.rb
CHANGED
@@ -3,16 +3,13 @@ require 'sinatra/reloader'
|
|
3
3
|
require 'opal'
|
4
4
|
|
5
5
|
class SinatraApp < Sinatra::Base
|
6
|
-
# Proc to generate javascript include tag (see config.ru)
|
7
|
-
set :generate_javascript_include_tag, nil
|
8
|
-
|
9
6
|
configure(:development) do
|
10
7
|
register Sinatra::Reloader
|
11
8
|
also_reload "#{__dir__}/**/*.rb"
|
12
9
|
end
|
13
10
|
|
14
11
|
get '/' do
|
15
|
-
@js_tag =
|
12
|
+
@js_tag = $GENERATE_JAVASCRIPT_INCLUDE_TAG.call # Defined in config.ru
|
16
13
|
erb :index # Render views/index.erb
|
17
14
|
end
|
18
15
|
end
|
data/examples/sinatra/config.ru
CHANGED
@@ -2,20 +2,20 @@ require 'opal/sprockets'
|
|
2
2
|
require_relative './app.rb'
|
3
3
|
|
4
4
|
Opal.use_gem 'ovto'
|
5
|
-
|
5
|
+
opal_server = Opal::Sprockets::Server.new {|s|
|
6
6
|
s.append_path './ovto/'
|
7
7
|
s.main = 'app'
|
8
8
|
}
|
9
9
|
|
10
|
-
sprockets =
|
10
|
+
sprockets = opal_server.sprockets
|
11
11
|
prefix = '/assets'
|
12
12
|
|
13
13
|
map prefix do
|
14
14
|
run sprockets
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
::Opal::Sprockets.javascript_include_tag('app', sprockets: sprockets, prefix: prefix, debug: true)
|
20
|
-
}
|
17
|
+
$GENERATE_JAVASCRIPT_INCLUDE_TAG = ->{
|
18
|
+
::Opal::Sprockets.javascript_include_tag('app', sprockets: sprockets, prefix: prefix, debug: true)
|
21
19
|
}
|
20
|
+
|
21
|
+
run SinatraApp
|
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: ../..
|
3
3
|
specs:
|
4
|
-
ovto (0.
|
4
|
+
ovto (0.6.0)
|
5
5
|
opal (>= 0.11, < 2)
|
6
6
|
rack (~> 2.0)
|
7
7
|
thor (~> 0.20)
|
@@ -9,15 +9,15 @@ PATH
|
|
9
9
|
GEM
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
|
-
ast (2.4.
|
12
|
+
ast (2.4.2)
|
13
13
|
ifchanged (1.0.1)
|
14
|
-
opal (1.0
|
14
|
+
opal (1.2.0)
|
15
15
|
ast (>= 2.3.0)
|
16
|
-
parser (~>
|
17
|
-
parser (
|
18
|
-
ast (~> 2.4.
|
19
|
-
rack (2.
|
20
|
-
rake (
|
16
|
+
parser (~> 3.0)
|
17
|
+
parser (3.0.2.0)
|
18
|
+
ast (~> 2.4.1)
|
19
|
+
rack (2.2.3)
|
20
|
+
rake (13.0.6)
|
21
21
|
thor (0.20.3)
|
22
22
|
|
23
23
|
PLATFORMS
|
@@ -29,4 +29,4 @@ DEPENDENCIES
|
|
29
29
|
rake
|
30
30
|
|
31
31
|
BUNDLED WITH
|
32
|
-
2.
|
32
|
+
2.2.22
|
data/lib/ovto/actions.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
module Ovto
|
2
2
|
# Base class for ovto actions.
|
3
3
|
class Actions
|
4
|
+
# WiredActions must be set after initialization
|
5
|
+
# (this cannot be an argument of #initialize because Actions and
|
6
|
+
# WiredActions have references to each other)
|
4
7
|
attr_writer :wired_actions
|
5
8
|
|
6
9
|
def actions
|
@@ -10,5 +13,13 @@ module Ovto
|
|
10
13
|
def state
|
11
14
|
@wired_actions._app.state
|
12
15
|
end
|
16
|
+
|
17
|
+
def middleware_name
|
18
|
+
WiredActionSet::I_AM_APP_NOT_A_MIDDLEWARE
|
19
|
+
end
|
20
|
+
|
21
|
+
def middleware_path
|
22
|
+
[]
|
23
|
+
end
|
13
24
|
end
|
14
25
|
end
|
data/lib/ovto/app.rb
CHANGED
@@ -1,18 +1,37 @@
|
|
1
1
|
module Ovto
|
2
2
|
class App
|
3
|
+
# List of installed middleware classes
|
4
|
+
def self.middlewares
|
5
|
+
@middlewares ||= []
|
6
|
+
end
|
7
|
+
|
3
8
|
# Create an App and start it
|
4
9
|
def self.run(*args)
|
5
10
|
new.run(*args)
|
6
11
|
end
|
7
12
|
|
13
|
+
# Install a middleware
|
14
|
+
def self.use(middleware_class)
|
15
|
+
self.middlewares.push(middleware_class)
|
16
|
+
end
|
17
|
+
|
8
18
|
def initialize
|
9
|
-
|
10
|
-
|
19
|
+
app_state_class = self.class.const_get('State')
|
20
|
+
# Inject middleware states
|
21
|
+
app_state_class.item :_middlewares, default_proc: ->{
|
22
|
+
Ovto::Middleware.create_middleware_states_class(self.class.middlewares).new
|
23
|
+
}
|
24
|
+
@state = app_state_class.new
|
25
|
+
@wired_action_set = nil
|
26
|
+
@main_component = nil
|
11
27
|
end
|
12
28
|
attr_reader :state
|
13
29
|
|
30
|
+
# An instance of YourApp::MainComponent (mainly for testing)
|
31
|
+
attr_reader :main_component
|
32
|
+
|
14
33
|
def actions
|
15
|
-
@
|
34
|
+
@wired_action_set.app_wired_actions
|
16
35
|
end
|
17
36
|
|
18
37
|
# Internal use only
|
@@ -36,9 +55,9 @@ module Ovto
|
|
36
55
|
def _run(id: nil)
|
37
56
|
runtime = Ovto::Runtime.new(self)
|
38
57
|
actions = self.class.const_get('Actions').new
|
39
|
-
@
|
40
|
-
actions.wired_actions = @
|
41
|
-
|
58
|
+
@wired_action_set = WiredActionSet.new(self, actions, [], self.class.middlewares, runtime)
|
59
|
+
actions.wired_actions = @wired_action_set.app_wired_actions
|
60
|
+
@main_component = create_view(@wired_action_set)
|
42
61
|
if id
|
43
62
|
%x{
|
44
63
|
document.addEventListener('DOMContentLoaded', function(){
|
@@ -46,16 +65,16 @@ module Ovto
|
|
46
65
|
if (!container) {
|
47
66
|
throw "Ovto::App#run: tag with id='" + id + "' was not found";
|
48
67
|
}
|
49
|
-
#{start_application(runtime,
|
68
|
+
#{start_application(runtime, `container`)}
|
50
69
|
});
|
51
70
|
}
|
52
71
|
else
|
53
|
-
start_application(runtime,
|
72
|
+
start_application(runtime, nil)
|
54
73
|
end
|
55
74
|
end
|
56
75
|
|
57
76
|
# Instantiate MyApp::MainComponent
|
58
|
-
def create_view
|
77
|
+
def create_view(wired_action_set)
|
59
78
|
begin
|
60
79
|
main_component_class = self.class.const_get('MainComponent')
|
61
80
|
rescue NameError => orig_ex
|
@@ -68,12 +87,17 @@ module Ovto
|
|
68
87
|
"#{self.class}::View to #{self.class}::MainComponent"
|
69
88
|
end
|
70
89
|
end
|
71
|
-
return main_component_class.new(
|
90
|
+
return main_component_class.new(wired_action_set)
|
72
91
|
end
|
73
92
|
|
74
|
-
def start_application(runtime,
|
75
|
-
|
76
|
-
|
93
|
+
def start_application(runtime, container)
|
94
|
+
Ovto.log_error {
|
95
|
+
runtime.run(@main_component, container)
|
96
|
+
setup
|
97
|
+
self.class.middlewares.each do |m|
|
98
|
+
m._run_setup(@wired_action_set[m.name])
|
99
|
+
end
|
100
|
+
}
|
77
101
|
end
|
78
102
|
end
|
79
103
|
end
|
data/lib/ovto/component.rb
CHANGED
@@ -13,10 +13,16 @@ module Ovto
|
|
13
13
|
ret
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
# (internal) Defined for convenience
|
17
|
+
def self.middleware_name
|
18
|
+
WiredActionSet::I_AM_APP_NOT_A_MIDDLEWARE
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(wired_action_set, middleware_path=[])
|
22
|
+
@wired_action_set = wired_action_set || WiredActionSet.dummy
|
23
|
+
@middleware_path = middleware_path
|
18
24
|
# Initialize here for the unit tests
|
19
|
-
@
|
25
|
+
@vdom_stack = [[]]
|
20
26
|
@components = []
|
21
27
|
@components_index = 0
|
22
28
|
end
|
@@ -26,7 +32,7 @@ module Ovto
|
|
26
32
|
end
|
27
33
|
|
28
34
|
def state
|
29
|
-
@
|
35
|
+
@wired_action_set.app.state
|
30
36
|
end
|
31
37
|
|
32
38
|
private
|
@@ -37,35 +43,35 @@ module Ovto
|
|
37
43
|
do_render({}, state)
|
38
44
|
end
|
39
45
|
|
40
|
-
|
46
|
+
# Call #render to generate VDom
|
47
|
+
def do_render(args, state, &block)
|
41
48
|
Ovto.debug_trace_log("rendering #{self}")
|
42
|
-
@
|
49
|
+
@vdom_stack = [[]]
|
43
50
|
@components_index = 0
|
44
51
|
@done_render = false
|
45
52
|
@current_state = state
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
53
|
+
rendered = Ovto.log_error {
|
54
|
+
Ovto.send_args_with_state(self, :render, args, state, &block)
|
55
|
+
}
|
56
|
+
case rendered
|
57
|
+
when String
|
58
|
+
return rendered
|
59
|
+
when Array
|
60
|
+
if rendered.length > 1
|
61
|
+
raise MoreThanOneNode
|
62
|
+
end
|
63
|
+
raise "rendered is empty" if rendered.length == 0
|
64
|
+
return rendered[0]
|
51
65
|
else
|
52
|
-
#
|
53
|
-
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
# Return true if the method accepts `state:` keyword
|
58
|
-
def accepts_state?(parameters)
|
59
|
-
parameters.each do |item|
|
60
|
-
return true if item == [:key, :state] ||
|
61
|
-
item == [:keyreq, :state] ||
|
62
|
-
item[0] == :keyrest
|
66
|
+
console.error("#render returned unknown value", rendered)
|
67
|
+
raise "#render returned unknown value"
|
63
68
|
end
|
64
|
-
return false
|
65
69
|
end
|
66
70
|
|
67
71
|
def actions
|
68
|
-
@
|
72
|
+
return @middleware_path.inject(@wired_action_set){|wa_set, middleware_name|
|
73
|
+
wa_set[middleware_name]
|
74
|
+
}[WiredActionSet::THE_MIDDLEWARE_ITSELF]
|
69
75
|
end
|
70
76
|
|
71
77
|
# o 'div', 'Hello.'
|
@@ -78,31 +84,39 @@ module Ovto
|
|
78
84
|
# o 'h1', 'Hello.'
|
79
85
|
# end
|
80
86
|
# o 'div', `{nodeName: ....}` # Inject VDom spec directly
|
87
|
+
# o SubComponentClass
|
88
|
+
# o SubComponentClass do ... end # Ovto passes the block to SubComponent#render
|
81
89
|
def o(_tag_name, arg1=nil, arg2=nil, &block)
|
82
|
-
if native?(arg1)
|
90
|
+
if native?(arg1) # Embed VDom directly
|
83
91
|
attributes = {}
|
84
92
|
content = arg1
|
85
|
-
elsif arg1.is_a?(Hash)
|
93
|
+
elsif arg1.is_a?(Hash) # Has attributes
|
86
94
|
attributes = arg1
|
87
95
|
content = arg2
|
88
|
-
elsif arg2 == nil
|
96
|
+
elsif arg2 == nil # Has content instead of attributes, or both are nil
|
89
97
|
attributes = {}
|
90
98
|
content = arg1
|
91
99
|
else
|
92
100
|
raise ArgumentError
|
93
101
|
end
|
94
102
|
|
95
|
-
children = render_children(content, block)
|
96
103
|
case _tag_name
|
97
104
|
when Class
|
98
|
-
|
105
|
+
if content
|
106
|
+
raise ArgumentError, "use a block to pass content to sub component"
|
107
|
+
end
|
108
|
+
result = render_component(_tag_name, attributes, &block)
|
99
109
|
when 'text'
|
100
110
|
unless attributes.empty?
|
101
111
|
raise ArgumentError, "text cannot take attributes"
|
102
112
|
end
|
103
113
|
result = content
|
104
114
|
when String
|
115
|
+
children = render_children(content, block)
|
105
116
|
tag_name, base_attributes = *extract_attrs(_tag_name)
|
117
|
+
if tag_name == "textarea" && (content || block)
|
118
|
+
raise ArgumentError, "Use `value:` to specify content of a textarea"
|
119
|
+
end
|
106
120
|
# Ignore nil/false
|
107
121
|
more_attributes = attributes.reject{|k, v| !v}
|
108
122
|
result = render_tag(tag_name, merge_attrs(base_attributes, more_attributes), children)
|
@@ -110,16 +124,8 @@ module Ovto
|
|
110
124
|
raise TypeError, "tag_name must be a String or Component but got "+
|
111
125
|
Ovto.inspect(tag_name)
|
112
126
|
end
|
113
|
-
|
114
|
-
|
115
|
-
raise MoreThanOneNode, "#{self.class}#render must generate a single DOM node. Please wrap the tags with a 'div' or something."
|
116
|
-
end
|
117
|
-
@done_render = true
|
118
|
-
return result
|
119
|
-
else
|
120
|
-
@vdom_tree.last.push(result)
|
121
|
-
return @vdom_tree.last
|
122
|
-
end
|
127
|
+
@vdom_stack.last.push(result)
|
128
|
+
return @vdom_stack.last
|
123
129
|
end
|
124
130
|
|
125
131
|
def extract_attrs(tag_name)
|
@@ -164,37 +170,52 @@ module Ovto
|
|
164
170
|
[content.to_s]
|
165
171
|
end
|
166
172
|
when block
|
167
|
-
|
168
|
-
block_value = block.call
|
169
|
-
results = @vdom_tree.pop
|
170
|
-
if results.length > 0 # 'o' was called at least once
|
171
|
-
results
|
172
|
-
elsif native?(block_value)
|
173
|
-
# Inject VDom tree written in JS object
|
174
|
-
# eg. Embed markdown
|
175
|
-
[block_value]
|
176
|
-
elsif block_value.is_a?(String)
|
177
|
-
# When 'o' is never called in the child block, use the last value
|
178
|
-
# eg.
|
179
|
-
# o 'span' do
|
180
|
-
# 'Hello' #=> This will be the content of the span tag
|
181
|
-
# end
|
182
|
-
[block_value]
|
183
|
-
else
|
184
|
-
# o 'div' do
|
185
|
-
# # When items is `[]`, 'o' is never called and `block_value` will be `[]`
|
186
|
-
# items.each{ o 'div', '...' }
|
187
|
-
# end
|
188
|
-
[]
|
189
|
-
end
|
173
|
+
render_block(block)
|
190
174
|
else
|
191
175
|
[]
|
192
176
|
end
|
193
177
|
end
|
194
178
|
|
195
|
-
def
|
179
|
+
def render_block(block)
|
180
|
+
@vdom_stack.push []
|
181
|
+
orig_depth = @vdom_stack.length
|
182
|
+
block_value = block.call
|
183
|
+
@vdom_stack = @vdom_stack.first(orig_depth)
|
184
|
+
results = @vdom_stack.pop
|
185
|
+
|
186
|
+
if results.length > 0 # 'o' was called at least once
|
187
|
+
results
|
188
|
+
elsif native?(block_value)
|
189
|
+
# Inject VDom tree written in JS object
|
190
|
+
# eg. Embed markdown
|
191
|
+
[block_value]
|
192
|
+
elsif block_value.is_a?(String)
|
193
|
+
# When 'o' is never called in the child block, use the last value
|
194
|
+
# eg.
|
195
|
+
# o 'span' do
|
196
|
+
# 'Hello' #=> This will be the content of the span tag
|
197
|
+
# end
|
198
|
+
[block_value]
|
199
|
+
elsif block_value.is_a?(Array)
|
200
|
+
# Case 1
|
201
|
+
# o "div", &block
|
202
|
+
# Case 2
|
203
|
+
# items = []
|
204
|
+
# o 'div' do items.each{ o ... } end # == o 'div' do [] end
|
205
|
+
block_value
|
206
|
+
else
|
207
|
+
console.error("Invalid block_value:", Ovto.inspect(block_value))
|
208
|
+
raise "Invalid block value"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# Instantiate component and call its #render to get VDom
|
213
|
+
def render_component(comp_class, args, &block)
|
196
214
|
comp = new_component(comp_class)
|
197
|
-
|
215
|
+
orig_stack, @vdom_stack = @vdom_stack, [[]]
|
216
|
+
ret = comp.do_render(args, @current_state, &block)
|
217
|
+
@vdom_stack = orig_stack
|
218
|
+
ret
|
198
219
|
end
|
199
220
|
|
200
221
|
def new_component(comp_class)
|
@@ -204,14 +225,56 @@ module Ovto
|
|
204
225
|
return comp
|
205
226
|
end
|
206
227
|
|
207
|
-
|
228
|
+
middleware_path = new_middleware_path(comp_class)
|
229
|
+
comp = @components[@components_index] = comp_class.new(@wired_action_set, middleware_path)
|
208
230
|
@components_index += 1
|
209
231
|
comp
|
210
232
|
end
|
211
233
|
|
234
|
+
# Make new middleware_path by adding comp_class
|
235
|
+
def new_middleware_path(comp_class)
|
236
|
+
mw_name = comp_class.middleware_name
|
237
|
+
if (idx = @middleware_path.index(mw_name))
|
238
|
+
# eg. suppose OvtoIde uses OvtoWindow
|
239
|
+
# class CompI < OvtoIde::Component
|
240
|
+
# def render
|
241
|
+
# o Window do
|
242
|
+
# o AnotherComponentOfOvtoIde
|
243
|
+
# end
|
244
|
+
# end
|
245
|
+
# end
|
246
|
+
# class Window < OvtoWindow::Component
|
247
|
+
# def render(&block)
|
248
|
+
# o ".window", &block
|
249
|
+
# end
|
250
|
+
# end
|
251
|
+
# Rendering order:
|
252
|
+
# 1. CompI (ovto_ide)
|
253
|
+
# 2. Window (ovto_window)
|
254
|
+
# 3. AnotherComponentOfOvtoIde (ovto_ide again)
|
255
|
+
@middleware_path[0..idx]
|
256
|
+
else
|
257
|
+
if comp_class.middleware_name == WiredActionSet::I_AM_APP_NOT_A_MIDDLEWARE
|
258
|
+
@middleware_path
|
259
|
+
else
|
260
|
+
@middleware_path + [comp_class.middleware_name]
|
261
|
+
end
|
262
|
+
end
|
263
|
+
# TODO: it would be nice if we could raise an error when comp_class
|
264
|
+
# is invalid middleware (i.e. not use'd)
|
265
|
+
end
|
266
|
+
|
212
267
|
def render_tag(tag_name, attributes, children)
|
213
|
-
|
214
|
-
|
268
|
+
attributes_ = attributes.map{|k, v|
|
269
|
+
if k.start_with?("on")
|
270
|
+
# Inject log_error to event handlers
|
271
|
+
[k, ->(e){ Ovto.log_error{ v.call(e) }}]
|
272
|
+
else
|
273
|
+
[k, v]
|
274
|
+
end
|
275
|
+
}.to_h
|
276
|
+
js_attributes = Component.hash_to_js_obj(attributes_ || {})
|
277
|
+
if (style = attributes_['style'])
|
215
278
|
`js_attributes.style = #{Component.hash_to_js_obj(style)}`
|
216
279
|
end
|
217
280
|
children ||= `null`
|