volt 0.7.1 → 0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|