volt 0.9.3.pre1 → 0.9.3.pre2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/CHANGELOG.md +15 -1
- data/Gemfile +30 -3
- data/README.md +7 -2
- data/Rakefile +17 -0
- data/app/volt/models/user.rb +1 -1
- data/app/volt/tasks/live_query/live_query.rb +0 -1
- data/app/volt/tasks/live_query/live_query_pool.rb +8 -2
- data/app/volt/tasks/live_query/query_tracker.rb +2 -2
- data/app/volt/tasks/query_tasks.rb +10 -27
- data/app/volt/tasks/store_tasks.rb +6 -5
- data/app/volt/tasks/user_tasks.rb +2 -2
- data/docs/UPGRADE_GUIDE.md +14 -0
- data/lib/volt/boot.rb +1 -0
- data/lib/volt/cli/asset_compile.rb +25 -7
- data/lib/volt/cli/console.rb +6 -5
- data/lib/volt/cli/generate.rb +2 -2
- data/lib/volt/config.rb +2 -1
- data/lib/volt/controllers/http_controller.rb +4 -3
- data/lib/volt/controllers/model_controller.rb +41 -19
- data/lib/volt/controllers/template_helpers.rb +19 -0
- data/lib/volt/extra_core/array.rb +6 -0
- data/lib/volt/extra_core/hash.rb +8 -26
- data/lib/volt/extra_core/string.rb +1 -1
- data/lib/volt/models/array_model.rb +12 -4
- data/lib/volt/models/associations.rb +11 -13
- data/lib/volt/models/buffer.rb +1 -1
- data/lib/volt/models/model.rb +22 -13
- data/lib/volt/models/model_helpers/model_change_helpers.rb +0 -1
- data/lib/volt/models/model_helpers/model_helpers.rb +11 -0
- data/lib/volt/models/permissions.rb +9 -12
- data/lib/volt/models/persistors/array_store.rb +7 -7
- data/lib/volt/models/persistors/base.rb +9 -0
- data/lib/volt/models/persistors/cookies.rb +0 -4
- data/lib/volt/models/persistors/flash.rb +0 -4
- data/lib/volt/models/persistors/local_store.rb +0 -4
- data/lib/volt/models/persistors/model_store.rb +13 -21
- data/lib/volt/models/persistors/page.rb +22 -0
- data/lib/volt/models/persistors/params.rb +0 -4
- data/lib/volt/models/persistors/query/query_listener.rb +3 -2
- data/lib/volt/models/url.rb +2 -2
- data/lib/volt/models/validators/unique_validator.rb +1 -1
- data/lib/volt/models.rb +1 -0
- data/lib/volt/page/bindings/attribute_binding.rb +2 -2
- data/lib/volt/page/bindings/base_binding.rb +7 -3
- data/lib/volt/page/bindings/bindings.rb +9 -0
- data/lib/volt/page/bindings/content_binding.rb +2 -2
- data/lib/volt/page/bindings/each_binding.rb +16 -12
- data/lib/volt/page/bindings/event_binding.rb +4 -4
- data/lib/volt/page/bindings/if_binding.rb +3 -3
- data/lib/volt/page/bindings/view_binding.rb +4 -4
- data/lib/volt/page/bindings/yield_binding.rb +3 -3
- data/lib/volt/page/channel.rb +6 -0
- data/lib/volt/page/channel_stub.rb +1 -1
- data/lib/volt/page/page.rb +20 -54
- data/lib/volt/page/path_string_renderer.rb +5 -6
- data/lib/volt/page/string_template_renderer.rb +2 -2
- data/lib/volt/page/targets/attribute_section.rb +47 -0
- data/lib/volt/page/targets/base_section.rb +5 -5
- data/lib/volt/page/targets/binding_document/component_node.rb +6 -1
- data/lib/volt/page/template_renderer.rb +4 -4
- data/lib/volt/reactive/computation.rb +32 -3
- data/lib/volt/router/routes.rb +5 -5
- data/lib/volt/server/component_templates.rb +30 -2
- data/lib/volt/server/forking_server.rb +2 -2
- data/lib/volt/server/message_bus/base_message_bus.rb +52 -0
- data/lib/volt/server/message_bus/message_encoder.rb +64 -0
- data/lib/volt/server/message_bus/peer_to_peer/peer_connection.rb +186 -0
- data/lib/volt/server/message_bus/peer_to_peer/peer_server.rb +78 -0
- data/lib/volt/server/message_bus/peer_to_peer/server_tracker.rb +57 -0
- data/lib/volt/server/message_bus/peer_to_peer/socket_with_timeout.rb +27 -0
- data/lib/volt/server/message_bus/peer_to_peer.rb +198 -0
- data/lib/volt/server/message_bus/redis.rb +1 -0
- data/lib/volt/server/rack/asset_files.rb +2 -2
- data/lib/volt/server/rack/component_paths.rb +1 -1
- data/lib/volt/server/rack/http_resource.rb +3 -2
- data/lib/volt/server/rack/opal_files.rb +6 -9
- data/lib/volt/server/websocket/websocket_handler.rb +0 -3
- data/lib/volt/server.rb +5 -3
- data/lib/volt/spec/setup.rb +11 -12
- data/lib/volt/tasks/dispatcher.rb +8 -12
- data/lib/volt/tasks/task_handler.rb +3 -2
- data/lib/volt/utils/csso_patch.rb +24 -0
- data/lib/volt/utils/promise_patch.rb +2 -0
- data/lib/volt/version.rb +1 -1
- data/lib/volt/volt/app.rb +73 -36
- data/lib/volt/volt/server_setup/app.rb +81 -0
- data/lib/volt.rb +22 -1
- data/spec/apps/kitchen_sink/Gemfile +1 -1
- data/spec/controllers/http_controller_spec.rb +5 -3
- data/spec/controllers/model_controller_spec.rb +2 -2
- data/spec/extra_core/hash_spec.rb +9 -0
- data/spec/integration/list_spec.rb +3 -3
- data/spec/models/associations_spec.rb +10 -2
- data/spec/models/dirty_spec.rb +7 -7
- data/spec/models/model_spec.rb +10 -2
- data/spec/models/permissions_spec.rb +9 -0
- data/spec/models/persistors/store_spec.rb +8 -0
- data/spec/page/bindings/content_binding_spec.rb +6 -2
- data/spec/page/bindings/each_binding_spec.rb +59 -0
- data/spec/page/bindings/if_binding_spec.rb +57 -0
- data/spec/page/path_string_renderer_spec.rb +5 -5
- data/spec/reactive/computation_spec.rb +65 -1
- data/spec/router/routes_spec.rb +1 -1
- data/spec/server/html_parser/sandlebars_parser_spec.rb +12 -22
- data/spec/server/message_bus/message_encoder_spec.rb +49 -0
- data/spec/server/message_bus/peer_to_peer/peer_connection_spec.rb +108 -0
- data/spec/server/message_bus/peer_to_peer/peer_server_spec.rb +66 -0
- data/spec/server/message_bus/peer_to_peer/socket_with_timeout_spec.rb +11 -0
- data/spec/server/message_bus/peer_to_peer_spec.rb +11 -0
- data/spec/server/rack/asset_files_spec.rb +1 -1
- data/spec/server/rack/http_resource_spec.rb +4 -4
- data/spec/spec_helper.rb +16 -3
- data/spec/tasks/dispatcher_spec.rb +17 -5
- data/spec/tasks/live_query_spec.rb +1 -1
- data/spec/tasks/query_tracker_spec.rb +34 -34
- data/spec/tasks/user_tasks_spec.rb +4 -2
- data/templates/project/Gemfile.tt +14 -3
- data/templates/project/config/app.rb.tt +27 -2
- data/volt.gemspec +3 -8
- metadata +32 -101
- data/docs/FAQ.md +0 -7
@@ -0,0 +1,9 @@
|
|
1
|
+
# A file to require all client side bindings
|
2
|
+
require 'volt/page/bindings/attribute_binding'
|
3
|
+
require 'volt/page/bindings/content_binding'
|
4
|
+
require 'volt/page/bindings/each_binding'
|
5
|
+
require 'volt/page/bindings/if_binding'
|
6
|
+
require 'volt/page/bindings/view_binding'
|
7
|
+
require 'volt/page/bindings/yield_binding'
|
8
|
+
require 'volt/page/bindings/component_binding'
|
9
|
+
require 'volt/page/bindings/event_binding'
|
@@ -6,8 +6,8 @@ module Volt
|
|
6
6
|
HTML_ESCAPE_REGEXP = /[&"'><\n]/
|
7
7
|
HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"', "'" => ''', "\n" => "<br />\n" }
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
super(
|
9
|
+
def initialize(volt_app, target, context, binding_name, getter)
|
10
|
+
super(volt_app, target, context, binding_name)
|
11
11
|
|
12
12
|
# Listen for changes
|
13
13
|
@computation = lambda do
|
@@ -2,8 +2,8 @@ require 'volt/page/bindings/base_binding'
|
|
2
2
|
|
3
3
|
module Volt
|
4
4
|
class EachBinding < BaseBinding
|
5
|
-
def initialize(
|
6
|
-
super(
|
5
|
+
def initialize(volt_app, target, context, binding_name, getter, variable_name, index_name, template_name)
|
6
|
+
super(volt_app, target, context, binding_name)
|
7
7
|
|
8
8
|
@item_name = variable_name
|
9
9
|
@index_name = index_name
|
@@ -14,18 +14,22 @@ module Volt
|
|
14
14
|
@getter = getter
|
15
15
|
|
16
16
|
# Listen for changes
|
17
|
-
@computation =
|
18
|
-
|
17
|
+
@computation = lambda do
|
18
|
+
begin
|
19
|
+
value = @context.instance_eval(&@getter)
|
20
|
+
rescue => e
|
21
|
+
Volt.logger.error("EachBinding Error: #{e.inspect}")
|
22
|
+
value = []
|
23
|
+
end
|
19
24
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
value = @context.instance_eval(&@getter)
|
24
|
-
rescue => e
|
25
|
-
Volt.logger.error("EachBinding Error: #{e.inspect}")
|
26
|
-
value = []
|
25
|
+
value
|
26
|
+
end.watch_and_resolve! do |value|
|
27
|
+
update(value)
|
27
28
|
end
|
29
|
+
end
|
28
30
|
|
31
|
+
# When a changed event happens, we update to the new size.
|
32
|
+
def update(value)
|
29
33
|
# Since we're checking things like size, we don't want this to be re-triggered on a
|
30
34
|
# size change, so we run without tracking.
|
31
35
|
Computation.run_without_tracking do
|
@@ -110,7 +114,7 @@ module Volt
|
|
110
114
|
end
|
111
115
|
end
|
112
116
|
|
113
|
-
item_template = TemplateRenderer.new(@
|
117
|
+
item_template = TemplateRenderer.new(@volt_app, @target, item_context, binding_name, @template_name)
|
114
118
|
@templates.insert(position, item_template)
|
115
119
|
|
116
120
|
update_indexes_after(position)
|
@@ -29,8 +29,8 @@ module Volt
|
|
29
29
|
class EventBinding < BaseBinding
|
30
30
|
attr_accessor :context, :binding_name
|
31
31
|
|
32
|
-
def initialize(
|
33
|
-
super(
|
32
|
+
def initialize(volt_app, target, context, binding_name, event_name, call_proc)
|
33
|
+
super(volt_app, target, context, binding_name)
|
34
34
|
@event_name = event_name
|
35
35
|
|
36
36
|
handler = proc do |js_event|
|
@@ -42,12 +42,12 @@ module Volt
|
|
42
42
|
result = @context.instance_exec(event, &call_proc)
|
43
43
|
end
|
44
44
|
|
45
|
-
@listener =
|
45
|
+
@listener = page.events.add(event_name, self, handler)
|
46
46
|
end
|
47
47
|
|
48
48
|
# Remove the event binding
|
49
49
|
def remove
|
50
|
-
|
50
|
+
page.events.remove(@event_name, self)
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -2,8 +2,8 @@ require 'volt/page/bindings/base_binding'
|
|
2
2
|
|
3
3
|
module Volt
|
4
4
|
class IfBinding < BaseBinding
|
5
|
-
def initialize(
|
6
|
-
super(
|
5
|
+
def initialize(volt_app, target, context, binding_name, branches)
|
6
|
+
super(volt_app, target, context, binding_name)
|
7
7
|
|
8
8
|
getter, template_name = branches[0]
|
9
9
|
|
@@ -88,7 +88,7 @@ module Volt
|
|
88
88
|
end
|
89
89
|
|
90
90
|
if true_template
|
91
|
-
@template = TemplateRenderer.new(@
|
91
|
+
@template = TemplateRenderer.new(@volt_app, @target, @context, binding_name, true_template)
|
92
92
|
end
|
93
93
|
end
|
94
94
|
end
|
@@ -10,8 +10,8 @@ module Volt
|
|
10
10
|
# lookup paths in ViewLookupForPath
|
11
11
|
# @param [String|nil] content_template_path is the path to the template for the content
|
12
12
|
# provided in the tag.
|
13
|
-
def initialize(
|
14
|
-
super(
|
13
|
+
def initialize(volt_app, target, context, binding_name, binding_in_path, getter, content_template_path = nil)
|
14
|
+
super(volt_app, target, context, binding_name)
|
15
15
|
|
16
16
|
@content_template_path = content_template_path
|
17
17
|
|
@@ -189,7 +189,7 @@ module Volt
|
|
189
189
|
# from the group)
|
190
190
|
generated_new = true
|
191
191
|
# Setup the controller
|
192
|
-
controller_class.new(*args)
|
192
|
+
controller_class.new(@volt_app, *args)
|
193
193
|
end
|
194
194
|
|
195
195
|
# Fetch grouped controllers if we're grouping
|
@@ -217,7 +217,7 @@ module Volt
|
|
217
217
|
|
218
218
|
# The context for templates can be either a controller, or the original context.
|
219
219
|
def render_template(full_path, path)
|
220
|
-
@current_template = TemplateRenderer.new(@
|
220
|
+
@current_template = TemplateRenderer.new(@volt_app, @target, @controller, @binding_name, full_path, path)
|
221
221
|
|
222
222
|
call_ready
|
223
223
|
end
|
@@ -5,8 +5,8 @@ require 'volt/page/template_renderer'
|
|
5
5
|
|
6
6
|
module Volt
|
7
7
|
class YieldBinding < BaseBinding
|
8
|
-
def initialize(
|
9
|
-
super(
|
8
|
+
def initialize(volt_app, target, context, binding_name)
|
9
|
+
super(volt_app, target, context, binding_name)
|
10
10
|
|
11
11
|
# Get the path to the template to yield
|
12
12
|
full_path = @context.attrs.content_template_path
|
@@ -14,7 +14,7 @@ module Volt
|
|
14
14
|
# Grab the controller for the content
|
15
15
|
controller = @context.attrs.content_controller
|
16
16
|
|
17
|
-
@current_template = TemplateRenderer.new(
|
17
|
+
@current_template = TemplateRenderer.new(volt_app, @target, controller, @binding_name, full_path)
|
18
18
|
end
|
19
19
|
|
20
20
|
def remove
|
data/lib/volt/page/channel.rb
CHANGED
@@ -64,6 +64,9 @@ module Volt
|
|
64
64
|
@queue.each do |message|
|
65
65
|
send_message(message)
|
66
66
|
end
|
67
|
+
|
68
|
+
# Trigger a connect event
|
69
|
+
trigger!('connect')
|
67
70
|
end
|
68
71
|
|
69
72
|
def closed(error)
|
@@ -71,6 +74,9 @@ module Volt
|
|
71
74
|
self.connected = false
|
72
75
|
self.error = `error.reason`
|
73
76
|
|
77
|
+
# Trigger a disconnect event
|
78
|
+
trigger!('disconnect')
|
79
|
+
|
74
80
|
reconnect!
|
75
81
|
end
|
76
82
|
|
data/lib/volt/page/page.rb
CHANGED
@@ -1,38 +1,10 @@
|
|
1
|
-
require 'opal'
|
2
|
-
require 'volt/models'
|
3
|
-
require 'volt/controllers/model_controller'
|
4
|
-
require 'volt/tasks/task_handler'
|
5
|
-
require 'volt/page/bindings/attribute_binding'
|
6
|
-
require 'volt/page/bindings/content_binding'
|
7
|
-
require 'volt/page/bindings/each_binding'
|
8
|
-
require 'volt/page/bindings/if_binding'
|
9
|
-
require 'volt/page/bindings/view_binding'
|
10
|
-
require 'volt/page/bindings/yield_binding'
|
11
|
-
require 'volt/page/bindings/component_binding'
|
12
|
-
require 'volt/page/bindings/event_binding'
|
13
|
-
require 'volt/page/template_renderer'
|
14
|
-
require 'volt/page/string_template_renderer'
|
15
|
-
require 'volt/page/document_events'
|
16
|
-
require 'volt/page/sub_context'
|
17
|
-
require 'volt/page/targets/dom_target'
|
18
|
-
require 'volt/data_stores/base_adaptor_client'
|
19
|
-
|
20
|
-
if RUBY_PLATFORM == 'opal'
|
21
|
-
require 'volt/page/channel'
|
22
|
-
else
|
23
|
-
require 'volt/page/channel_stub'
|
24
|
-
end
|
25
|
-
require 'volt/router/routes'
|
26
|
-
require 'volt/models/url'
|
27
|
-
require 'volt/page/url_tracker'
|
28
|
-
require 'volt/benchmark/benchmark'
|
29
|
-
require 'volt/page/tasks'
|
30
1
|
|
31
2
|
module Volt
|
32
3
|
class Page
|
33
4
|
attr_reader :url, :params, :page, :routes, :events
|
34
5
|
|
35
|
-
def initialize
|
6
|
+
def initialize(volt_app)
|
7
|
+
@volt_app = volt_app
|
36
8
|
# Run the code to setup the page
|
37
9
|
@page = Model.new
|
38
10
|
|
@@ -44,24 +16,26 @@ module Volt
|
|
44
16
|
@events = DocumentEvents.new
|
45
17
|
|
46
18
|
if RUBY_PLATFORM == 'opal'
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
19
|
+
if Volt.in_browser?
|
20
|
+
# Setup escape binding for console
|
21
|
+
`
|
22
|
+
$(document).keyup(function(e) {
|
23
|
+
if (e.keyCode == 27) {
|
24
|
+
Opal.gvars.page.$launch_console();
|
25
|
+
}
|
26
|
+
});
|
27
|
+
|
28
|
+
$(document).on('click', 'a', function(event) {
|
29
|
+
return Opal.gvars.page.$link_clicked($(this).attr('href'), event);
|
30
|
+
});
|
31
|
+
`
|
32
|
+
end
|
59
33
|
end
|
60
34
|
|
61
35
|
# Initialize tasks so we can get the reload message
|
62
36
|
tasks if Volt.env.development?
|
63
37
|
|
64
|
-
if Volt.
|
38
|
+
if Volt.in_browser?
|
65
39
|
channel.on('reconnected') do
|
66
40
|
@page._reconnected = true
|
67
41
|
|
@@ -178,13 +152,13 @@ module Volt
|
|
178
152
|
# Do the initial url params parse
|
179
153
|
@url_tracker.url_updated(true)
|
180
154
|
|
181
|
-
main_controller = Main::MainController.new
|
155
|
+
main_controller = Main::MainController.new(@volt_app)
|
182
156
|
|
183
157
|
# Setup main page template
|
184
|
-
TemplateRenderer.new(
|
158
|
+
TemplateRenderer.new(@volt_app, DomTarget.new, main_controller, 'CONTENT', 'main/main/main/body')
|
185
159
|
|
186
160
|
# Setup title reactive template
|
187
|
-
@title_template = StringTemplateRenderer.new(
|
161
|
+
@title_template = StringTemplateRenderer.new(@volt_app, main_controller, 'main/main/main/title')
|
188
162
|
|
189
163
|
# Watch for changes to the title template
|
190
164
|
proc do
|
@@ -214,12 +188,4 @@ module Volt
|
|
214
188
|
Volt.logger.error("Unable to restore: #{e.inspect}")
|
215
189
|
end
|
216
190
|
end
|
217
|
-
|
218
|
-
if Volt.client?
|
219
|
-
$page = Page.new
|
220
|
-
|
221
|
-
`$(document).ready(function() {`
|
222
|
-
$page.start
|
223
|
-
`});`
|
224
|
-
end
|
225
191
|
end
|
@@ -9,13 +9,12 @@ module Volt
|
|
9
9
|
class ViewLookupException < Exception; end
|
10
10
|
class PathStringRenderer
|
11
11
|
attr_reader :html
|
12
|
-
def initialize(path, attrs = nil, page = nil, render_from_path = nil)
|
13
|
-
# use the global page if one is not passed in
|
14
|
-
page ||= $page
|
15
|
-
|
12
|
+
def initialize(volt_app, path, attrs = nil, page = nil, render_from_path = nil)
|
16
13
|
# where to do the path lookup from
|
17
14
|
render_from_path ||= 'main/main/main/body'
|
18
15
|
|
16
|
+
page ||= volt_app.page
|
17
|
+
|
19
18
|
# Make path into a full path
|
20
19
|
@view_lookup = Volt::ViewLookupForPath.new(page, render_from_path)
|
21
20
|
full_path, controller_path = @view_lookup.path_for_template(path, nil)
|
@@ -26,10 +25,10 @@ module Volt
|
|
26
25
|
|
27
26
|
controller_class, action = ControllerHandler.get_controller_and_action(controller_path)
|
28
27
|
|
29
|
-
controller = controller_class.new # (SubContext.new(attrs, nil, true))
|
28
|
+
controller = controller_class.new(volt_app) # (SubContext.new(attrs, nil, true))
|
30
29
|
controller.model = SubContext.new(attrs, nil, true)
|
31
30
|
|
32
|
-
renderer = StringTemplateRenderer.new(
|
31
|
+
renderer = StringTemplateRenderer.new(volt_app, controller, full_path)
|
33
32
|
|
34
33
|
@html = renderer.html
|
35
34
|
|
@@ -5,12 +5,12 @@ module Volt
|
|
5
5
|
# StringTemplateRenderer will intellegently update the string in the same way
|
6
6
|
# a normal bindings will update the dom.
|
7
7
|
class StringTemplateRenderer
|
8
|
-
def initialize(
|
8
|
+
def initialize(volt_app, context, template_path)
|
9
9
|
@dependency = Dependency.new
|
10
10
|
|
11
11
|
@template_path = template_path
|
12
12
|
@target = AttributeTarget.new(nil, nil, self)
|
13
|
-
@template = TemplateRenderer.new(
|
13
|
+
@template = TemplateRenderer.new(volt_app, @target, context, 'main', template_path)
|
14
14
|
end
|
15
15
|
|
16
16
|
# Render the template and get the current value
|
@@ -18,9 +18,56 @@ module Volt
|
|
18
18
|
set_content_and_rezero_bindings(value, {})
|
19
19
|
end
|
20
20
|
|
21
|
+
def insert_anchor_before_end(binding_name)
|
22
|
+
end_node = @target.find_by_binding_id(@binding_name)
|
23
|
+
if end_node.is_a?(ComponentNode)
|
24
|
+
component_node = ComponentNode.new(binding_name, end_node, end_node.root || end_node)
|
25
|
+
end_node.insert(-1, component_node)
|
26
|
+
else
|
27
|
+
raise "can not insert on HtmlNode"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# When using bindings, we have to change the binding id so we don't reuse
|
32
|
+
# the same id when rendering a binding multiple times.
|
33
|
+
def rezero_bindings(html, bindings)
|
34
|
+
@@base_binding_id ||= 20_000
|
35
|
+
# rezero
|
36
|
+
parts = html.split(/(\<\!\-\- \$\/?[0-9]+ \-\-\>)/).reject { |v| v == '' }
|
37
|
+
|
38
|
+
new_html = []
|
39
|
+
new_bindings = {}
|
40
|
+
id_map = {}
|
41
|
+
|
42
|
+
parts.each do |part|
|
43
|
+
case part
|
44
|
+
when /\<\!\-\- \$[0-9]+ \-\-\>/
|
45
|
+
# Open
|
46
|
+
binding_id = part.match(/\<\!\-\- \$([0-9]+) \-\-\>/)[1].to_i
|
47
|
+
binding = bindings[binding_id]
|
48
|
+
new_bindings[@@base_binding_id] = binding if binding
|
49
|
+
|
50
|
+
new_html << "<!-- $#{@@base_binding_id} -->"
|
51
|
+
id_map[binding_id] = @@base_binding_id
|
52
|
+
@@base_binding_id += 1
|
53
|
+
when /\<\!\-\- \$\/[0-9]+ \-\-\>/
|
54
|
+
# Close
|
55
|
+
binding_id = part.match(/\<\!\-\- \$\/([0-9]+) \-\-\>/)[1].to_i
|
56
|
+
new_html << "<!-- $/#{id_map[binding_id]} -->"
|
57
|
+
else
|
58
|
+
# html string
|
59
|
+
new_html << part
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
return new_html.join(''), new_bindings
|
64
|
+
end
|
65
|
+
|
21
66
|
# Takes in our html and bindings, and rezero's the comment names, and the
|
22
67
|
# bindings. Returns an updated bindings hash
|
23
68
|
def set_content_and_rezero_bindings(html, bindings)
|
69
|
+
html, bindings = rezero_bindings(html, bindings)
|
70
|
+
|
24
71
|
if @binding_name == 'main'
|
25
72
|
@target.html = html
|
26
73
|
else
|
@@ -6,19 +6,19 @@ module Volt
|
|
6
6
|
@@template_cache = {}
|
7
7
|
|
8
8
|
def remove
|
9
|
-
fail 'not implemented'
|
9
|
+
fail 'remove is not implemented'
|
10
10
|
end
|
11
11
|
|
12
12
|
def remove_anchors
|
13
|
-
fail 'not implemented'
|
13
|
+
fail 'remove_anchors is not implemented'
|
14
14
|
end
|
15
15
|
|
16
|
-
def insert_anchor_before_end
|
17
|
-
fail 'not implemented'
|
16
|
+
def insert_anchor_before_end(binding_name)
|
17
|
+
fail 'insert_anchor_before_end is not implemented'
|
18
18
|
end
|
19
19
|
|
20
20
|
def set_template
|
21
|
-
fail 'not implemented'
|
21
|
+
fail 'set_template is not implemented'
|
22
22
|
end
|
23
23
|
|
24
24
|
def set_content_to_template(page, template_name)
|
@@ -9,7 +9,7 @@ module Volt
|
|
9
9
|
class ComponentNode < BaseNode
|
10
10
|
include Eventable
|
11
11
|
|
12
|
-
attr_accessor :parent, :binding_id, :nodes
|
12
|
+
attr_accessor :parent, :binding_id, :nodes, :root
|
13
13
|
|
14
14
|
def initialize(binding_id = nil, parent = nil, root = nil)
|
15
15
|
@nodes = []
|
@@ -65,6 +65,11 @@ module Volt
|
|
65
65
|
@nodes << node
|
66
66
|
end
|
67
67
|
|
68
|
+
def insert(index, node)
|
69
|
+
@nodes.insert(index, node)
|
70
|
+
changed!
|
71
|
+
end
|
72
|
+
|
68
73
|
def to_html
|
69
74
|
str = []
|
70
75
|
@nodes.each do |node|
|
@@ -4,16 +4,16 @@ module Volt
|
|
4
4
|
class TemplateRenderer < BaseBinding
|
5
5
|
attr_reader :context
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
super(
|
7
|
+
def initialize(volt_app, target, context, binding_name, template_name)
|
8
|
+
super(volt_app, target, context, binding_name)
|
9
9
|
|
10
10
|
@sub_bindings = []
|
11
11
|
|
12
|
-
bindings = dom_section.set_content_to_template(page, template_name)
|
12
|
+
bindings = dom_section.set_content_to_template(volt_app.page, template_name)
|
13
13
|
|
14
14
|
bindings.each_pair do |id, bindings_for_id|
|
15
15
|
bindings_for_id.each do |binding|
|
16
|
-
@sub_bindings << binding.call(
|
16
|
+
@sub_bindings << binding.call(volt_app, target, context, id)
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
@@ -74,6 +74,10 @@ module Volt
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
+
def stopped?
|
78
|
+
@stopped
|
79
|
+
end
|
80
|
+
|
77
81
|
# Runs in this computation as the current computation, returns the computation
|
78
82
|
def run_in
|
79
83
|
previous = Computation.current
|
@@ -172,20 +176,45 @@ class Proc
|
|
172
176
|
#
|
173
177
|
# Example:
|
174
178
|
# -> { }
|
175
|
-
def watch_and_resolve!
|
179
|
+
def watch_and_resolve!(yield_nil_for_unresolved_promise=false)
|
176
180
|
unless block_given?
|
177
181
|
fail 'watch_and_resolve! requires a block to call when the value is resolved or another value other than a promise is returned in the watch.'
|
178
182
|
end
|
179
183
|
|
180
|
-
|
184
|
+
# Keep results between runs
|
185
|
+
result = nil
|
186
|
+
|
187
|
+
computation = proc do |comp|
|
181
188
|
result = call
|
189
|
+
last_promise = nil
|
182
190
|
|
183
191
|
if result.is_a?(Promise)
|
192
|
+
last_promise = result
|
193
|
+
|
194
|
+
# Often you want a to be alerted that an unresolved promise is waiting
|
195
|
+
# to be resolved.
|
196
|
+
if yield_nil_for_unresolved_promise && !result.resolved?
|
197
|
+
yield(nil)
|
198
|
+
end
|
199
|
+
|
184
200
|
result.then do |final|
|
185
|
-
|
201
|
+
# Check to make sure that a new value didn't get reactively pushed
|
202
|
+
# before the promise resolved.
|
203
|
+
if last_promise.is_a?(Promise) && last_promise == result
|
204
|
+
# Don't resolve if the computation was stopped
|
205
|
+
unless comp.stopped?
|
206
|
+
yield(final)
|
207
|
+
end
|
208
|
+
|
209
|
+
# Clear result for GC
|
210
|
+
result = nil
|
211
|
+
end
|
186
212
|
end
|
187
213
|
else
|
188
214
|
yield(result)
|
215
|
+
|
216
|
+
# Clear result for GC
|
217
|
+
result = nil
|
189
218
|
end
|
190
219
|
end.watch!
|
191
220
|
|
data/lib/volt/router/routes.rb
CHANGED
@@ -5,8 +5,8 @@ module Volt
|
|
5
5
|
# a url to params, and params to url.
|
6
6
|
# routes do
|
7
7
|
# client "/about", _view: 'about'
|
8
|
-
# client "/blog/{
|
9
|
-
# client "/blog/{
|
8
|
+
# client "/blog/{id}/edit", _view: 'blog/edit', _action: 'edit'
|
9
|
+
# client "/blog/{id}", _view: 'blog/show', _action: 'show'
|
10
10
|
# client "/blog", _view: 'blog'
|
11
11
|
# client "/blog/new", _view: 'blog/new', _action: 'new'
|
12
12
|
# client "/cool/{_name}", _view: 'cool'
|
@@ -27,16 +27,16 @@ module Volt
|
|
27
27
|
# @indirect_routes = {
|
28
28
|
# '*' => {
|
29
29
|
# 'edit' => {
|
30
|
-
# nil => {
|
30
|
+
# nil => {id: 1, _view: 'blog/edit', _action: 'edit'}
|
31
31
|
# }
|
32
|
-
# nil => {
|
32
|
+
# nil => {id: 1, _view: 'blog/show', _action: 'show'}
|
33
33
|
# }
|
34
34
|
# }
|
35
35
|
# }
|
36
36
|
#
|
37
37
|
# Match for params
|
38
38
|
# @param_matches = [
|
39
|
-
# {
|
39
|
+
# {id: nil, _view: 'blog/edit', _action: 'edit'} => Proc.new {|params| "/blog/#{params.id}/edit", params.reject {|k,v| k == :id }}
|
40
40
|
# ]
|
41
41
|
class Routes
|
42
42
|
def initialize
|
@@ -79,6 +79,9 @@ module Volt
|
|
79
79
|
|
80
80
|
# Load all templates in the folder
|
81
81
|
Dir["#{views_path}*/*.{#{exts.join(',')}}"].sort.each do |view_path|
|
82
|
+
path_parts = view_path.scan(/([^\/]+)\/([^\/]+)\/[^\/]+\/([^\/]+)[.](html|email)$/)
|
83
|
+
component_name, controller_name, view, _ = path_parts[0]
|
84
|
+
|
82
85
|
# file extension
|
83
86
|
format = File.extname(view_path).downcase.delete('.').to_sym
|
84
87
|
|
@@ -88,6 +91,8 @@ module Volt
|
|
88
91
|
|
89
92
|
file_contents = File.read(view_path)
|
90
93
|
|
94
|
+
template_calls = []
|
95
|
+
|
91
96
|
# Process template if we have a handler for this file type
|
92
97
|
if handler = ComponentTemplates.handler_for_extension(format)
|
93
98
|
file_contents = handler.call(file_contents)
|
@@ -107,8 +112,11 @@ module Volt
|
|
107
112
|
binding_code = "{#{binding_code.join(', ')}}"
|
108
113
|
|
109
114
|
code << "#{page_reference}.add_template(#{name.inspect}, #{template['html'].inspect}, #{binding_code})\n"
|
115
|
+
template_calls << "template(#{name.inspect}, #{template['html'].inspect}, #{binding_code})"
|
110
116
|
end
|
111
117
|
end
|
118
|
+
|
119
|
+
# puts "module #{component_name.camelize}\n class #{controller_name.camelize}\n class VoltTemplates < VoltTemplates\n #{template_calls.join("\n")}\n end\n end\nend"
|
112
120
|
end
|
113
121
|
|
114
122
|
code
|
@@ -118,9 +126,29 @@ module Volt
|
|
118
126
|
def generate_controller_code
|
119
127
|
code = ''
|
120
128
|
controllers_path = "#{@component_path}/controllers/"
|
129
|
+
views_path = "#{@component_path}/views/"
|
121
130
|
|
122
|
-
|
123
|
-
|
131
|
+
# Controllers are optional, specifying a view folder is enough to auto
|
132
|
+
# generate the controller.
|
133
|
+
|
134
|
+
implicit_controllers = Dir["#{views_path}*"].sort.map do |path|
|
135
|
+
# remove the /views/ folder and add _controller.rb
|
136
|
+
path.split('/').tap {|v| v[-2] = 'controllers' }.join('/') + '_controller.rb'
|
137
|
+
end
|
138
|
+
explicit_controllers = Dir["#{controllers_path}*_controller.rb"].sort
|
139
|
+
|
140
|
+
controllers = (implicit_controllers + explicit_controllers).uniq
|
141
|
+
controllers.each do |path|
|
142
|
+
if File.exists?(path)
|
143
|
+
code << File.read(path) + "\n\n"
|
144
|
+
else
|
145
|
+
# parts = path.scan(/([^\/]+)\/controllers\/([^\/]+)_controller[.]rb$/)
|
146
|
+
# component, controller = parts[0]
|
147
|
+
|
148
|
+
# # Generate a blank controller. (We need to actually generate one so
|
149
|
+
# # the Template can be attached to it for template inheritance)
|
150
|
+
# code << "\nmodule #{component.camelize}\n class #{controller.camelize} < Volt::ModelController\n end\nend\n"
|
151
|
+
end
|
124
152
|
end
|
125
153
|
|
126
154
|
code
|
@@ -58,11 +58,11 @@ module Volt
|
|
58
58
|
# Running as child
|
59
59
|
@reader.close
|
60
60
|
|
61
|
-
@server.boot_volt
|
61
|
+
volt_app = @server.boot_volt
|
62
62
|
@rack_app = @server.new_server
|
63
63
|
|
64
64
|
# Set the drb object locally
|
65
|
-
@dispatcher = Dispatcher.new
|
65
|
+
@dispatcher = Dispatcher.new(volt_app)
|
66
66
|
drb_object = DRb.start_service('drbunix:', [self, @dispatcher])
|
67
67
|
|
68
68
|
@writer.puts(drb_object.uri)
|