volt 0.7.1 → 0.7.2
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/Gemfile +1 -2
- data/Readme.md +97 -56
- data/VERSION +1 -1
- data/app/volt/assets/js/sockjs-0.3.4.min.js +27 -0
- data/app/volt/assets/js/vertxbus.js +216 -0
- data/app/volt/tasks/live_query/live_query.rb +5 -5
- data/app/volt/tasks/live_query/live_query_pool.rb +1 -1
- data/app/volt/tasks/query_tasks.rb +5 -0
- data/app/volt/tasks/store_tasks.rb +44 -18
- data/docs/WHY.md +10 -0
- data/lib/volt/cli.rb +18 -7
- data/lib/volt/controllers/model_controller.rb +30 -8
- data/lib/volt/extra_core/inflections.rb +63 -0
- data/lib/volt/extra_core/inflector/inflections.rb +203 -0
- data/lib/volt/extra_core/inflector/methods.rb +63 -0
- data/lib/volt/extra_core/inflector.rb +4 -0
- data/lib/volt/extra_core/object.rb +9 -0
- data/lib/volt/extra_core/string.rb +10 -14
- data/lib/volt/models/array_model.rb +45 -27
- data/lib/volt/models/cursor.rb +6 -0
- data/lib/volt/models/model.rb +127 -12
- data/lib/volt/models/model_hash_behaviour.rb +8 -5
- data/lib/volt/models/model_helpers.rb +4 -4
- data/lib/volt/models/model_state.rb +22 -0
- data/lib/volt/models/persistors/array_store.rb +49 -35
- data/lib/volt/models/persistors/base.rb +3 -3
- data/lib/volt/models/persistors/model_store.rb +17 -6
- data/lib/volt/models/persistors/query/query_listener.rb +0 -2
- data/lib/volt/models/persistors/store.rb +0 -4
- data/lib/volt/models/persistors/store_state.rb +27 -0
- data/lib/volt/models/url.rb +2 -2
- data/lib/volt/models/validations/errors.rb +0 -0
- data/lib/volt/models/validations/length.rb +13 -0
- data/lib/volt/models/validations/validations.rb +82 -0
- data/lib/volt/models.rb +1 -1
- data/lib/volt/page/bindings/attribute_binding.rb +29 -14
- data/lib/volt/page/bindings/base_binding.rb +2 -2
- data/lib/volt/page/bindings/component_binding.rb +29 -25
- data/lib/volt/page/bindings/content_binding.rb +1 -0
- data/lib/volt/page/bindings/each_binding.rb +25 -33
- data/lib/volt/page/bindings/event_binding.rb +0 -1
- data/lib/volt/page/bindings/if_binding.rb +3 -1
- data/lib/volt/page/bindings/template_binding.rb +61 -28
- data/lib/volt/page/document_events.rb +3 -1
- data/lib/volt/page/draw_cycle.rb +22 -0
- data/lib/volt/page/page.rb +10 -1
- data/lib/volt/page/reactive_template.rb +23 -16
- data/lib/volt/page/sub_context.rb +1 -1
- data/lib/volt/page/targets/attribute_section.rb +3 -2
- data/lib/volt/page/targets/attribute_target.rb +0 -4
- data/lib/volt/page/targets/base_section.rb +25 -0
- data/lib/volt/page/targets/binding_document/component_node.rb +13 -14
- data/lib/volt/page/targets/binding_document/html_node.rb +4 -0
- data/lib/volt/page/targets/dom_section.rb +16 -67
- data/lib/volt/page/targets/dom_template.rb +99 -0
- data/lib/volt/page/targets/helpers/comment_searchers.rb +29 -0
- data/lib/volt/page/template_renderer.rb +2 -14
- data/lib/volt/reactive/array_extensions.rb +0 -1
- data/lib/volt/reactive/event_chain.rb +9 -2
- data/lib/volt/reactive/events.rb +44 -37
- data/lib/volt/reactive/object_tracking.rb +1 -1
- data/lib/volt/reactive/reactive_array.rb +18 -0
- data/lib/volt/reactive/reactive_count.rb +108 -0
- data/lib/volt/reactive/reactive_generator.rb +44 -0
- data/lib/volt/reactive/reactive_value.rb +73 -73
- data/lib/volt/reactive/string_extensions.rb +1 -1
- data/lib/volt/router/routes.rb +205 -88
- data/lib/volt/server/component_handler.rb +3 -1
- data/lib/volt/server/html_parser/view_parser.rb +20 -4
- data/lib/volt/server/rack/component_paths.rb +13 -10
- data/lib/volt/server/rack/index_files.rb +4 -4
- data/lib/volt/server/socket_connection_handler.rb +5 -1
- data/lib/volt/server.rb +10 -3
- data/spec/apps/kitchen_sink/.gitignore +8 -0
- data/spec/apps/kitchen_sink/Gemfile +32 -0
- data/spec/apps/kitchen_sink/app/home/views/index/index.html +3 -5
- data/spec/apps/kitchen_sink/config.ru +4 -0
- data/spec/apps/kitchen_sink/public/index.html +2 -2
- data/spec/extra_core/inflector_spec.rb +8 -0
- data/spec/models/event_chain_spec.rb +18 -0
- data/spec/models/model_buffers_spec.rb +9 -0
- data/spec/models/model_spec.rb +22 -9
- data/spec/models/reactive_array_spec.rb +26 -1
- data/spec/models/reactive_call_times_spec.rb +28 -0
- data/spec/models/reactive_value_spec.rb +19 -0
- data/spec/models/validations_spec.rb +39 -0
- data/spec/page/bindings/content_binding_spec.rb +1 -0
- data/spec/{templates → page/bindings}/template_binding_spec.rb +54 -0
- data/spec/router/routes_spec.rb +156 -8
- data/spec/server/html_parser/sandlebars_parser_spec.rb +55 -47
- data/spec/server/html_parser/view_parser_spec.rb +3 -0
- data/spec/server/rack/asset_files_spec.rb +1 -1
- data/spec/spec_helper.rb +25 -11
- data/spec/templates/targets/binding_document/component_node_spec.rb +12 -0
- data/templates/project/Gemfile.tt +11 -0
- data/templates/project/app/home/config/routes.rb +1 -1
- data/templates/project/app/home/controllers/index_controller.rb +5 -5
- data/templates/project/app/home/views/index/index.html +6 -6
- data/volt.gemspec +5 -6
- metadata +34 -76
- data/app/volt/assets/js/sockjs-0.2.1.min.js +0 -27
- data/lib/volt/reactive/object_tracker.rb +0 -107
|
@@ -15,34 +15,30 @@ class EachBinding < BaseBinding
|
|
|
15
15
|
@templates = []
|
|
16
16
|
|
|
17
17
|
# Run the initial render
|
|
18
|
-
update
|
|
18
|
+
# update
|
|
19
|
+
reload
|
|
19
20
|
|
|
20
21
|
@added_listener = @value.on('added') { |_, position, item| item_added(position) }
|
|
21
22
|
@changed_listener = @value.on('changed') { reload }
|
|
22
23
|
@removed_listener = @value.on('removed') { |_, position| item_removed(position) }
|
|
23
24
|
end
|
|
24
25
|
|
|
25
|
-
# When a
|
|
26
|
-
# array might have changed. In this case, just reload the whole thing
|
|
27
|
-
# TODO: Track to make sure the changed event isn't being called too often (it is currently)
|
|
26
|
+
# When a changed event happens, we update to the new size.
|
|
28
27
|
def reload
|
|
29
|
-
#
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
# Adjust to the new size
|
|
29
|
+
values = current_values
|
|
30
|
+
templates_size = @templates.size
|
|
31
|
+
values_size = values.size
|
|
32
|
+
|
|
33
|
+
if templates_size < values_size
|
|
34
|
+
(templates_size).upto(values_size-1) do |index|
|
|
35
|
+
item_added(index)
|
|
36
|
+
end
|
|
37
|
+
elsif templates_size > values_size
|
|
38
|
+
(templates_size-1).downto(values_size) do |index|
|
|
39
|
+
item_removed(index)
|
|
37
40
|
end
|
|
38
41
|
end
|
|
39
|
-
|
|
40
|
-
@templates = []
|
|
41
|
-
|
|
42
|
-
# Run update again to rebuild
|
|
43
|
-
update
|
|
44
|
-
|
|
45
|
-
# ObjectTracker.disable_cache
|
|
46
42
|
end
|
|
47
43
|
|
|
48
44
|
def item_removed(position)
|
|
@@ -77,7 +73,7 @@ class EachBinding < BaseBinding
|
|
|
77
73
|
item_template = TemplateRenderer.new(@page, @target, item_context, binding_name, @template_name)
|
|
78
74
|
@templates.insert(position, item_template)
|
|
79
75
|
|
|
80
|
-
update_indexes_after(position)
|
|
76
|
+
# update_indexes_after(position)
|
|
81
77
|
end
|
|
82
78
|
|
|
83
79
|
# When items are added or removed in the middle of the list, we need
|
|
@@ -85,27 +81,23 @@ class EachBinding < BaseBinding
|
|
|
85
81
|
def update_indexes_after(start_index)
|
|
86
82
|
size = @templates.size
|
|
87
83
|
if size > 0
|
|
88
|
-
start_index.upto(
|
|
84
|
+
start_index.upto(size-1) do |index|
|
|
85
|
+
puts "UP INDEX: #{index}"
|
|
89
86
|
@templates[index].context.locals[:index].cur = index
|
|
90
87
|
end
|
|
91
88
|
end
|
|
92
89
|
end
|
|
93
90
|
|
|
94
|
-
def
|
|
95
|
-
|
|
96
|
-
values = [item]
|
|
97
|
-
else
|
|
98
|
-
values = @value.cur
|
|
99
|
-
return if values.is_a?(Model) || values.is_a?(Exception)
|
|
100
|
-
values = values.attributes
|
|
101
|
-
end
|
|
91
|
+
def current_values
|
|
92
|
+
values = @value.cur
|
|
102
93
|
|
|
103
|
-
|
|
104
|
-
values
|
|
105
|
-
|
|
106
|
-
|
|
94
|
+
return [] if values.is_a?(Model) || values.is_a?(Exception)
|
|
95
|
+
values = values.attributes
|
|
96
|
+
|
|
97
|
+
return values
|
|
107
98
|
end
|
|
108
99
|
|
|
100
|
+
|
|
109
101
|
# When this each_binding is removed, cleanup.
|
|
110
102
|
def remove
|
|
111
103
|
# puts "Remove Each"
|
|
@@ -39,8 +39,10 @@ class IfBinding < BaseBinding
|
|
|
39
39
|
@branches.each do |branch|
|
|
40
40
|
value, template_name = branch
|
|
41
41
|
|
|
42
|
+
current_value = value.cur
|
|
43
|
+
|
|
42
44
|
# TODO: A bug in opal requires us to check == true
|
|
43
|
-
if
|
|
45
|
+
if current_value.true? == true && !current_value.is_a?(Exception)
|
|
44
46
|
# This branch is currently true
|
|
45
47
|
true_template = template_name
|
|
46
48
|
break
|
|
@@ -11,8 +11,6 @@ class TemplateBinding < BaseBinding
|
|
|
11
11
|
|
|
12
12
|
@current_template = nil
|
|
13
13
|
|
|
14
|
-
# puts "GETTER: #{value_from_getter(getter).inspect}"
|
|
15
|
-
|
|
16
14
|
# Find the source for the getter binding
|
|
17
15
|
@path, section = value_from_getter(getter)
|
|
18
16
|
|
|
@@ -20,15 +18,15 @@ class TemplateBinding < BaseBinding
|
|
|
20
18
|
# Render this as a section
|
|
21
19
|
@section = section
|
|
22
20
|
else
|
|
23
|
-
# Use the value passed in as the default
|
|
24
|
-
@
|
|
21
|
+
# Use the value passed in as the default arguments
|
|
22
|
+
@arguments = section
|
|
25
23
|
end
|
|
26
24
|
|
|
27
25
|
# Run the initial render
|
|
28
26
|
update
|
|
29
27
|
|
|
30
|
-
@path_changed_listener = @path.on('changed') {
|
|
31
|
-
@section_changed_listener = @section.on('changed') {
|
|
28
|
+
@path_changed_listener = @path.on('changed') { queue_update } if @path.reactive?
|
|
29
|
+
@section_changed_listener = @section.on('changed') { queue_update } if @section && @section.reactive?
|
|
32
30
|
end
|
|
33
31
|
|
|
34
32
|
def setup_path(binding_in_path)
|
|
@@ -44,7 +42,7 @@ class TemplateBinding < BaseBinding
|
|
|
44
42
|
end
|
|
45
43
|
|
|
46
44
|
# Takes in a lookup path and returns the full path for the matching
|
|
47
|
-
# template. Also returns the controller name if applicable.
|
|
45
|
+
# template. Also returns the controller and action name if applicable.
|
|
48
46
|
#
|
|
49
47
|
# Looking up a path is fairly simple. There are 4 parts needed to find
|
|
50
48
|
# the html to be rendered. File paths look like this:
|
|
@@ -79,7 +77,6 @@ class TemplateBinding < BaseBinding
|
|
|
79
77
|
|
|
80
78
|
full_path = [@collection_name, @controller_name, @page_name, nil]
|
|
81
79
|
|
|
82
|
-
offset = 0
|
|
83
80
|
start_at = full_path.size - parts_size - path_position
|
|
84
81
|
|
|
85
82
|
full_path.size.times do |index|
|
|
@@ -95,9 +92,12 @@ class TemplateBinding < BaseBinding
|
|
|
95
92
|
path = full_path.join('/')
|
|
96
93
|
if check_for_template?(path)
|
|
97
94
|
controller = nil
|
|
98
|
-
|
|
95
|
+
|
|
96
|
+
# Don't return a controller if we are just getting another section
|
|
97
|
+
# from the same controller
|
|
98
|
+
if path_position >= 1
|
|
99
99
|
# Lookup the controller
|
|
100
|
-
controller = [full_path[0], full_path[1] + '_controller']
|
|
100
|
+
controller = [full_path[0], full_path[1] + '_controller', full_path[2]]
|
|
101
101
|
end
|
|
102
102
|
return path, controller
|
|
103
103
|
end
|
|
@@ -107,45 +107,76 @@ class TemplateBinding < BaseBinding
|
|
|
107
107
|
end
|
|
108
108
|
|
|
109
109
|
def update
|
|
110
|
-
full_path,
|
|
110
|
+
full_path, controller_path = path_for_template(@path.cur, @section.cur)
|
|
111
|
+
# puts "UPDATE: #{@path.inspect} - #{full_path.inspect}"
|
|
111
112
|
|
|
112
113
|
@current_template.remove if @current_template
|
|
113
114
|
|
|
114
|
-
if @
|
|
115
|
+
if @arguments
|
|
115
116
|
# Load in any procs
|
|
116
|
-
@
|
|
117
|
+
@arguments.each_pair do |key,value|
|
|
117
118
|
if value.class == Proc
|
|
118
|
-
@
|
|
119
|
+
@arguments[key.gsub('-', '_')] = value.call
|
|
119
120
|
end
|
|
120
121
|
end
|
|
121
122
|
end
|
|
122
123
|
|
|
123
|
-
render_template(full_path,
|
|
124
|
+
render_template(full_path, controller_path)
|
|
124
125
|
end
|
|
125
126
|
|
|
126
127
|
# The context for templates can be either a controller, or the original context.
|
|
127
|
-
def render_template(full_path,
|
|
128
|
+
def render_template(full_path, controller_path)
|
|
129
|
+
args = @arguments ? [@arguments] : []
|
|
130
|
+
|
|
128
131
|
# TODO: at the moment a :body section and a :title will both initialize different
|
|
129
132
|
# controllers. Maybe we should have a way to tie them together?
|
|
130
|
-
controller_class = get_controller(
|
|
131
|
-
if controller_class
|
|
132
|
-
args = []
|
|
133
|
-
args << SubContext.new(@model) if @model
|
|
133
|
+
controller_class, action = get_controller(controller_path)
|
|
134
134
|
|
|
135
|
+
if controller_class
|
|
135
136
|
# Setup the controller
|
|
136
137
|
current_context = controller_class.new(*args)
|
|
137
|
-
@controller = current_context
|
|
138
138
|
else
|
|
139
|
-
|
|
140
|
-
current_context = @context
|
|
141
|
-
@controller = nil
|
|
139
|
+
current_context = ModelController.new(*args)
|
|
142
140
|
end
|
|
141
|
+
@controller = current_context
|
|
142
|
+
|
|
143
|
+
# Trigger the action
|
|
144
|
+
@controller.send(action) if @controller.respond_to?(action)
|
|
143
145
|
|
|
144
146
|
@current_template = TemplateRenderer.new(@page, @target, current_context, @binding_name, full_path)
|
|
145
147
|
|
|
146
148
|
call_ready
|
|
147
149
|
end
|
|
148
150
|
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
# # The context for templates can be either a controller, or the original context.
|
|
154
|
+
# def render_template(full_path, controller_path)
|
|
155
|
+
# # TODO: at the moment a :body section and a :title will both initialize different
|
|
156
|
+
# # controllers. Maybe we should have a way to tie them together?
|
|
157
|
+
# controller_class, action = get_controller(controller_path)
|
|
158
|
+
# if controller_class
|
|
159
|
+
# args = []
|
|
160
|
+
# puts "MODEL: #{@arguments.inspect}"
|
|
161
|
+
# args << SubContext.new(@arguments) if @arguments
|
|
162
|
+
#
|
|
163
|
+
# # Setup the controller
|
|
164
|
+
# current_context = controller_class.new(*args)
|
|
165
|
+
# @controller = current_context
|
|
166
|
+
#
|
|
167
|
+
# # Trigger the action
|
|
168
|
+
# @controller.send(action) if @controller.respond_to?(action)
|
|
169
|
+
# else
|
|
170
|
+
# # Pass the context directly
|
|
171
|
+
# current_context = @context
|
|
172
|
+
# @controller = nil
|
|
173
|
+
# end
|
|
174
|
+
#
|
|
175
|
+
# @current_template = TemplateRenderer.new(@page, @target, current_context, @binding_name, full_path)
|
|
176
|
+
#
|
|
177
|
+
# call_ready
|
|
178
|
+
# end
|
|
179
|
+
|
|
149
180
|
def call_ready
|
|
150
181
|
if @controller
|
|
151
182
|
if @controller.respond_to?(:section=)
|
|
@@ -190,11 +221,13 @@ class TemplateBinding < BaseBinding
|
|
|
190
221
|
private
|
|
191
222
|
|
|
192
223
|
# Fetch the controller class
|
|
193
|
-
def get_controller(
|
|
194
|
-
return nil unless
|
|
224
|
+
def get_controller(controller_path)
|
|
225
|
+
return nil, nil unless controller_path && controller_path.size > 0
|
|
226
|
+
|
|
227
|
+
action = controller_path[-1]
|
|
195
228
|
|
|
196
229
|
# Get the constant parts
|
|
197
|
-
parts =
|
|
230
|
+
parts = controller_path[0..-2].map {|v| v.gsub('-', '_').camelize }
|
|
198
231
|
|
|
199
232
|
# Home doesn't get namespaced
|
|
200
233
|
if parts.first == 'Home'
|
|
@@ -212,7 +245,7 @@ class TemplateBinding < BaseBinding
|
|
|
212
245
|
end
|
|
213
246
|
end
|
|
214
247
|
|
|
215
|
-
return obj
|
|
248
|
+
return obj, action
|
|
216
249
|
end
|
|
217
250
|
|
|
218
251
|
end
|
|
@@ -15,7 +15,7 @@ class DocumentEvents
|
|
|
15
15
|
|
|
16
16
|
%x{
|
|
17
17
|
$('body').on(event, function(e) {
|
|
18
|
-
that.$handle(event, e, e.originalEvent.target);
|
|
18
|
+
that.$handle(event, e, e.target || e.originalEvent.target);
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
21
|
|
|
@@ -37,6 +37,8 @@ class DocumentEvents
|
|
|
37
37
|
# TODO: Sometimes the event doesn't exist, but we still get
|
|
38
38
|
# an event.
|
|
39
39
|
handlers = @events[event_name]
|
|
40
|
+
# puts "EVENT: #{event_name} - #{handlers.inspect} for #{element.id}"
|
|
41
|
+
# `console.log('target: ', target);`
|
|
40
42
|
handlers = handlers[element.id] if handlers
|
|
41
43
|
|
|
42
44
|
if handlers
|
data/lib/volt/page/draw_cycle.rb
CHANGED
|
@@ -1,9 +1,31 @@
|
|
|
1
|
+
# The draw cycle is responsible for queueing redraws until all of the events have
|
|
2
|
+
# fired. Once that is done, everything will be redrawn. This prevents bindings
|
|
3
|
+
# from being drawn multiple times before all events have propigated.
|
|
1
4
|
class DrawCycle
|
|
2
5
|
def initialize
|
|
3
6
|
@queue = {}
|
|
7
|
+
@timer = nil
|
|
4
8
|
end
|
|
5
9
|
|
|
6
10
|
def queue(binding)
|
|
11
|
+
@queue[binding] = true
|
|
12
|
+
|
|
13
|
+
unless @timer
|
|
14
|
+
# Flush once everything else has finished running
|
|
15
|
+
@timer = `setTimeout(function() { self.$flush(); }, 0);`
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def flush
|
|
20
|
+
@timer = nil
|
|
21
|
+
|
|
22
|
+
work_queue = @queue
|
|
23
|
+
@queue = {}
|
|
24
|
+
|
|
25
|
+
work_queue.each_pair do |binding,_|
|
|
26
|
+
# Call the update if queued
|
|
27
|
+
binding.update
|
|
28
|
+
end
|
|
7
29
|
|
|
8
30
|
end
|
|
9
31
|
end
|
data/lib/volt/page/page.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
if RUBY_PLATFORM == 'opal'
|
|
2
2
|
require 'opal'
|
|
3
|
-
|
|
4
3
|
require 'opal-jquery'
|
|
5
4
|
end
|
|
6
5
|
require 'volt/models'
|
|
@@ -31,6 +30,15 @@ require 'volt/benchmark/benchmark'
|
|
|
31
30
|
require 'volt/page/draw_cycle'
|
|
32
31
|
require 'volt/page/tasks'
|
|
33
32
|
|
|
33
|
+
if RUBY_PLATFORM == 'opal'
|
|
34
|
+
require 'promise.rb'
|
|
35
|
+
else
|
|
36
|
+
# Opal doesn't expose its promise library directly
|
|
37
|
+
spec = Gem::Specification.find_by_name("opal")
|
|
38
|
+
require(spec.gem_dir + "/stdlib/promise")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
|
|
34
42
|
class Page
|
|
35
43
|
attr_reader :url, :params, :page, :templates, :routes, :draw_cycle, :events
|
|
36
44
|
|
|
@@ -164,6 +172,7 @@ class Page
|
|
|
164
172
|
title_target = AttributeTarget.new
|
|
165
173
|
title_target.on('changed') do
|
|
166
174
|
title = title_target.to_html
|
|
175
|
+
# puts "SET TITLE: #{title.inspect}: #{title_target.inspect}"
|
|
167
176
|
`document.title = title;`
|
|
168
177
|
end
|
|
169
178
|
TemplateRenderer.new(self, title_target, main_controller, "main", "home/index/index/title")
|
|
@@ -4,36 +4,43 @@ class ReactiveTemplate
|
|
|
4
4
|
def initialize(page, context, template_path)
|
|
5
5
|
# puts "New Reactive Template: #{context.inspect} - #{template_path.inspect}"
|
|
6
6
|
@template_path = template_path
|
|
7
|
-
@target = AttributeTarget.new
|
|
7
|
+
@target = AttributeTarget.new(nil, nil, self)
|
|
8
8
|
@template = TemplateRenderer.new(page, @target, context, "main", template_path)
|
|
9
|
-
end
|
|
10
9
|
|
|
11
|
-
def event_added(event, scope_provider, first)
|
|
12
|
-
if first && !@template_listener
|
|
13
|
-
@template_listener = @target.on('changed') { update }
|
|
14
|
-
end
|
|
15
10
|
end
|
|
16
11
|
|
|
17
|
-
def
|
|
18
|
-
|
|
19
|
-
@template_listener.remove
|
|
20
|
-
@template_listener = nil
|
|
21
|
-
end
|
|
12
|
+
def reactive?
|
|
13
|
+
true
|
|
22
14
|
end
|
|
23
15
|
|
|
16
|
+
# def event_added(event, scope_provider, first, first_for_event)
|
|
17
|
+
# if first && !@template_listener
|
|
18
|
+
# @template_listener = @target.on('changed') { update }
|
|
19
|
+
# end
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# def event_removed(event, last, last_for_event)
|
|
23
|
+
# if last && @template_listener
|
|
24
|
+
# @template_listener.remove
|
|
25
|
+
# @template_listener = nil
|
|
26
|
+
# end
|
|
27
|
+
# end
|
|
28
|
+
|
|
24
29
|
# Render the template and get the current value
|
|
25
30
|
def cur
|
|
26
31
|
@target.to_html
|
|
27
32
|
end
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
true
|
|
34
|
+
def update
|
|
35
|
+
trigger!('changed')
|
|
32
36
|
end
|
|
33
37
|
|
|
38
|
+
def remove
|
|
39
|
+
@template.remove
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
|
|
41
|
+
@template = nil
|
|
42
|
+
@target = nil
|
|
43
|
+
@template_path = nil
|
|
37
44
|
end
|
|
38
45
|
|
|
39
46
|
end
|
|
@@ -16,7 +16,7 @@ class SubContext
|
|
|
16
16
|
|
|
17
17
|
def method_missing(method_name, *args, &block)
|
|
18
18
|
method_name = method_name.to_s
|
|
19
|
-
if @locals
|
|
19
|
+
if @locals.has_key?(method_name)
|
|
20
20
|
return @locals[method_name]
|
|
21
21
|
elsif @context
|
|
22
22
|
return @context.send(method_name, *args, &block)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
require 'volt/page/targets/base_section'
|
|
5
5
|
|
|
6
|
-
class AttributeSection
|
|
6
|
+
class AttributeSection < BaseSection
|
|
7
7
|
def initialize(target, binding_name)
|
|
8
8
|
@target = target
|
|
9
9
|
@binding_name = binding_name
|
|
@@ -31,7 +31,8 @@ class AttributeSection
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def remove
|
|
34
|
+
# TODO: is this getting run for no reason?
|
|
34
35
|
node = @target.find_by_binding_id(@binding_name)
|
|
35
|
-
node.remove
|
|
36
|
+
node.remove if node
|
|
36
37
|
end
|
|
37
38
|
end
|
|
@@ -7,10 +7,6 @@ require 'volt/page/targets/binding_document/html_node'
|
|
|
7
7
|
# a string that can then be used to update a attribute binding.
|
|
8
8
|
|
|
9
9
|
class AttributeTarget < ComponentNode
|
|
10
|
-
# TODO: improve
|
|
11
|
-
def skip_current_queue_flush
|
|
12
|
-
true
|
|
13
|
-
end
|
|
14
10
|
|
|
15
11
|
def section(*args)
|
|
16
12
|
return AttributeSection.new(self, *args)
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
require 'volt/page/targets/dom_template'
|
|
2
|
+
|
|
1
3
|
# Class to describe the interface for sections
|
|
2
4
|
class BaseSection
|
|
5
|
+
@@template_cache = {}
|
|
6
|
+
|
|
3
7
|
def remove
|
|
4
8
|
raise "not implemented"
|
|
5
9
|
end
|
|
@@ -11,4 +15,25 @@ class BaseSection
|
|
|
11
15
|
def insert_anchor_before_end
|
|
12
16
|
raise "not implemented"
|
|
13
17
|
end
|
|
18
|
+
|
|
19
|
+
def set_content_to_template(page, template_name)
|
|
20
|
+
if self.is_a?(DomSection)
|
|
21
|
+
dom_template = (@@template_cache[template_name] ||= DomTemplate.new(page, template_name))
|
|
22
|
+
|
|
23
|
+
return set_template(dom_template)
|
|
24
|
+
else
|
|
25
|
+
template = page.templates[template_name]
|
|
26
|
+
|
|
27
|
+
if template
|
|
28
|
+
html = template['html']
|
|
29
|
+
bindings = template['bindings']
|
|
30
|
+
else
|
|
31
|
+
html = "<div>-- < missing template #{template_name.inspect.gsub('<', '<').gsub('>', '>')} > --</div>"
|
|
32
|
+
bindings = {}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
return set_content_and_rezero_bindings(html, bindings)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
14
39
|
end
|
|
@@ -9,21 +9,19 @@ class ComponentNode < BaseNode
|
|
|
9
9
|
include Events
|
|
10
10
|
|
|
11
11
|
attr_accessor :parent, :binding_id, :nodes
|
|
12
|
-
def initialize(binding_id=nil, parent=nil)
|
|
12
|
+
def initialize(binding_id=nil, parent=nil, root=nil)
|
|
13
13
|
@nodes = []
|
|
14
14
|
@binding_id = binding_id
|
|
15
15
|
@parent = parent
|
|
16
|
-
|
|
17
|
-
@change_listener = on('changed') do
|
|
18
|
-
if @parent
|
|
19
|
-
@parent.trigger!('changed')
|
|
20
|
-
end
|
|
21
|
-
end
|
|
16
|
+
@root = root
|
|
22
17
|
end
|
|
23
18
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
def trigger!(*args, &block)
|
|
20
|
+
if @root
|
|
21
|
+
@root.trigger!(*args, &block)
|
|
22
|
+
else
|
|
23
|
+
super
|
|
24
|
+
end
|
|
27
25
|
end
|
|
28
26
|
|
|
29
27
|
def text=(text)
|
|
@@ -44,7 +42,7 @@ class ComponentNode < BaseNode
|
|
|
44
42
|
# Open
|
|
45
43
|
binding_id = part.match(/\<\!\-\- \$([0-9]+) \-\-\>/)[1].to_i
|
|
46
44
|
|
|
47
|
-
sub_node = ComponentNode.new(binding_id, current_node)
|
|
45
|
+
sub_node = ComponentNode.new(binding_id, current_node, @root || self)
|
|
48
46
|
current_node << sub_node
|
|
49
47
|
current_node = sub_node
|
|
50
48
|
when /\<\!\-\- \$\/[0-9]+ \-\-\>/
|
|
@@ -93,6 +91,8 @@ class ComponentNode < BaseNode
|
|
|
93
91
|
@nodes = []
|
|
94
92
|
|
|
95
93
|
trigger!('changed')
|
|
94
|
+
|
|
95
|
+
# @binding_id = nil
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
def remove_anchors
|
|
@@ -100,10 +100,9 @@ class ComponentNode < BaseNode
|
|
|
100
100
|
|
|
101
101
|
@parent.nodes.delete(self)
|
|
102
102
|
|
|
103
|
-
@change_listener.remove
|
|
104
|
-
@change_listener = nil
|
|
105
|
-
|
|
106
103
|
trigger!('changed')
|
|
104
|
+
@parent = nil
|
|
105
|
+
@binding_id = nil
|
|
107
106
|
end
|
|
108
107
|
|
|
109
108
|
def inspect
|