volt 0.3.7 → 0.3.8

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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/app/volt/assets/css/notices.css.scss +8 -0
  4. data/app/volt/tasks/channel_tasks.rb +33 -0
  5. data/app/volt/tasks/store_tasks.rb +45 -0
  6. data/app/volt/views/notices/index.html +11 -0
  7. data/lib/volt/controllers/model_controller.rb +4 -0
  8. data/lib/volt/models/array_model.rb +11 -1
  9. data/lib/volt/models/model.rb +22 -14
  10. data/lib/volt/models/model_wrapper.rb +13 -6
  11. data/lib/volt/models/params.rb +6 -1
  12. data/lib/volt/models/params_array.rb +9 -0
  13. data/lib/volt/models/store.rb +164 -0
  14. data/lib/volt/models/store_array.rb +15 -0
  15. data/lib/volt/models/url.rb +0 -4
  16. data/lib/volt/models.rb +1 -0
  17. data/lib/volt/{templates → page/bindings}/attribute_binding.rb +8 -7
  18. data/lib/volt/{templates → page/bindings}/base_binding.rb +6 -1
  19. data/lib/volt/{templates → page/bindings}/content_binding.rb +1 -1
  20. data/lib/volt/{templates → page/bindings}/each_binding.rb +15 -6
  21. data/lib/volt/{templates → page/bindings}/event_binding.rb +1 -5
  22. data/lib/volt/{templates → page/bindings}/if_binding.rb +1 -1
  23. data/lib/volt/{templates → page/bindings}/template_binding.rb +16 -7
  24. data/lib/volt/page/channel.rb +105 -0
  25. data/lib/volt/{templates → page}/document_events.rb +0 -0
  26. data/lib/volt/{templates → page}/memory_test.rb +0 -0
  27. data/lib/volt/{templates → page}/page.rb +22 -21
  28. data/lib/volt/{templates → page}/reactive_template.rb +0 -0
  29. data/lib/volt/{templates → page}/render_queue.rb +0 -0
  30. data/lib/volt/{templates → page}/sub_context.rb +0 -0
  31. data/lib/volt/{templates → page}/targets/attribute_section.rb +1 -1
  32. data/lib/volt/{templates → page}/targets/attribute_target.rb +4 -4
  33. data/lib/volt/{templates → page}/targets/base_section.rb +0 -0
  34. data/lib/volt/{templates → page}/targets/binding_document/base_node.rb +0 -0
  35. data/lib/volt/{templates → page}/targets/binding_document/component_node.rb +1 -1
  36. data/lib/volt/{templates → page}/targets/binding_document/html_node.rb +1 -1
  37. data/lib/volt/{templates → page}/targets/dom_section.rb +1 -1
  38. data/lib/volt/{templates → page}/targets/dom_target.rb +2 -2
  39. data/lib/volt/page/tasks.rb +61 -0
  40. data/lib/volt/{templates → page}/template_renderer.rb +1 -1
  41. data/lib/volt/reactive/destructive_methods.rb +19 -0
  42. data/lib/volt/reactive/event_chain.rb +13 -19
  43. data/lib/volt/reactive/events.rb +30 -116
  44. data/lib/volt/reactive/object_tracker.rb +29 -22
  45. data/lib/volt/reactive/reactive_array.rb +2 -3
  46. data/lib/volt/reactive/reactive_tags.rb +7 -0
  47. data/lib/volt/reactive/reactive_value.rb +86 -81
  48. data/lib/volt/reactive/string_extensions.rb +0 -3
  49. data/lib/volt/router/routes.rb +2 -2
  50. data/lib/volt/server/channel_handler.rb +24 -4
  51. data/lib/volt/server/component_handler.rb +2 -1
  52. data/lib/volt/server/rack/component_files.rb +3 -2
  53. data/lib/volt/server/rack/component_paths.rb +11 -1
  54. data/lib/volt/server/rack/index_files.rb +1 -1
  55. data/lib/volt/server.rb +16 -0
  56. data/lib/volt/store/mongo.rb +1 -1
  57. data/lib/volt/tasks/dispatcher.rb +25 -0
  58. data/spec/models/model_spec.rb +90 -15
  59. data/spec/models/params_spec.rb +16 -0
  60. data/spec/models/reactive_array_spec.rb +17 -18
  61. data/spec/models/reactive_value_spec.rb +11 -0
  62. data/spec/models/store_spec.rb +16 -0
  63. data/spec/server/rack/component_files_spec.rb +18 -16
  64. data/spec/server/rack/component_paths_spec.rb +21 -19
  65. data/spec/templates/targets/binding_document/component_node_spec.rb +1 -1
  66. data/spec/templates/template_binding_spec.rb +1 -1
  67. data/templates/project/app/home/views/index/index.html +2 -0
  68. data/volt.gemspec +2 -0
  69. metadata +67 -25
  70. data/lib/volt/templates/channel.rb +0 -47
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8411833ee4800b3e7d701875b963b718af2c8351
4
- data.tar.gz: f68ff074f4a685036f18e9a0536d431cee35ad1a
3
+ metadata.gz: 8d7bacdfeed9b6502911eb0eeea86c91ff909e58
4
+ data.tar.gz: f7a9dbc54254ba479f159054500e0d7be94383d8
5
5
  SHA512:
6
- metadata.gz: c20f7c8102cf7b8b5f7fb35996cc9bf15400bc2d027324ab263357f7b46b2e5ae8843445b503fc22e37521e6b8ec195eba226fa4bed9e81a4b3e55968bc7103e
7
- data.tar.gz: 3795c0247a76819a5ba58b444cf922db34c9234ae0816ebdf7c6d7ff7cfd535b03b0c5235277e52b20c47a491932667ca6137523135fde6195cec330f3bfdcb7
6
+ metadata.gz: 5fc4b3f656d8b40a8160eb5f386d0e76e156eb282ea3eb0f4359a246b2147127fd632eefea78f78916238474ecc721f12e88c22d1e8abac95b632b45bb4947c8
7
+ data.tar.gz: 559444ac5f139576652669add6d7fe23b7532b4dd1a6b8fe849181e584fad67298597668f0d975bd25338791c398ac952b663f3b88208564ead76607d93ce02b
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.7
1
+ 0.3.8
@@ -0,0 +1,8 @@
1
+ .notices {
2
+ position: absolute;
3
+ width: 600px;
4
+ top: 0px;
5
+ margin-left: -300px;
6
+ left: 50%;
7
+ z-index: 1000;
8
+ }
@@ -0,0 +1,33 @@
1
+ class ChannelTasks
2
+ @@listeners = {}
3
+
4
+ def initialize(channel, dispatcher)
5
+ @channel = channel
6
+ @dispatcher = dispatcher
7
+ end
8
+
9
+ def add_listener(channel_name)
10
+ @@listeners[channel_name] ||= []
11
+ @@listeners[channel_name] << @channel
12
+ end
13
+
14
+ def remove_listener(channel_name)
15
+ if @@listeners[channel_name]
16
+ @@listeners[channel_name].delete(@channel)
17
+ end
18
+ end
19
+
20
+ def self.send_message_to_channel(channel_name, message, skip_channel)
21
+ listeners = @@listeners[channel_name]
22
+
23
+ if listeners
24
+ listeners.each do |listener|
25
+ # We might need to skip a channel if the update came in on this
26
+ # channel.
27
+ next if listener == skip_channel
28
+
29
+ listener.send_message(*message)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,45 @@
1
+ require 'mongo'
2
+ require_relative 'channel_tasks'
3
+
4
+ class StoreTasks
5
+ def initialize(channel=nil, dispatcher=nil)
6
+ @@mongo_db ||= Mongo::MongoClient.new("localhost", 27017)
7
+ @@db ||= @@mongo_db.db("development")
8
+
9
+ @channel = channel
10
+ @dispatcher = dispatcher
11
+ end
12
+
13
+ def db
14
+ @@db
15
+ end
16
+
17
+ def save(collection, data)
18
+ puts "Insert: #{data.inspect} on #{collection.inspect}"
19
+ # Try to create
20
+ # TODO: Seems mongo is dumb and doesn't let you upsert with custom id's
21
+ begin
22
+ @@db[collection].insert(data)
23
+ id = {'_id' => data.delete('_id')}
24
+ rescue Mongo::OperationFailure => error
25
+ # Really mongo client?
26
+ if error.message[/^11000[:]/]
27
+ # Update because the id already exists
28
+ id = {'_id' => data.delete('_id')}
29
+ @@db[collection].update(id, data)
30
+ else
31
+ raise
32
+ end
33
+ end
34
+
35
+ id = id['_id']
36
+ # ChannelHandler.send_message_all(@channel, 'update', nil, id, data.merge('_id' => id))
37
+
38
+ ChannelTasks.send_message_to_channel("#{collection}##{id}", ['update', nil, id, data.merge('_id' => id)], @channel)
39
+ end
40
+
41
+ def find(collection, scope, query=nil)
42
+ puts "FIND: #{collection.inspect} - #{scope}"
43
+ return @@db[collection].find(scope).to_a
44
+ end
45
+ end
@@ -0,0 +1,11 @@
1
+ <:body>
2
+ {#if page._reloading}
3
+ <div class="notices alert alert-info">Reloading...</div>
4
+ {/}
5
+ {#if channel.state == :closed}
6
+ <div class="notices alert alert-info">
7
+ Connection Lost... {channel.error}...
8
+ {#if channel.reconnect_interval} Reconnecting in {(channel.reconnect_interval / 1000.0).round} sec{/}
9
+ </div>
10
+ {/}
11
+ </:body>
@@ -23,6 +23,10 @@ class ModelController
23
23
  $page.channel
24
24
  end
25
25
 
26
+ def tasks
27
+ $page.tasks
28
+ end
29
+
26
30
  def controller
27
31
  @controller ||= ReactiveValue.new(Model.new)
28
32
  end
@@ -2,10 +2,12 @@ require 'volt/models/model_wrapper'
2
2
 
3
3
  class ArrayModel < ReactiveArray
4
4
  include ModelWrapper
5
+
6
+ attr_reader :parent, :path
5
7
 
6
8
  def initialize(array=[], parent=nil, path=nil)
7
9
  @parent = parent
8
- @path = path
10
+ @path = path || []
9
11
 
10
12
  array = wrap_values(array)
11
13
 
@@ -34,4 +36,12 @@ class ArrayModel < ReactiveArray
34
36
  args = wrap_values(args)
35
37
  super(*args)
36
38
  end
39
+
40
+ def new_model(*args)
41
+ Model.new(*args)
42
+ end
43
+
44
+ def new_array_model(*args)
45
+ ArrayModel.new(*args)
46
+ end
37
47
  end
@@ -33,9 +33,9 @@ class Model
33
33
  end
34
34
 
35
35
  def initialize(attributes={}, parent=nil, path=nil, class_paths=nil)
36
- self.attributes = wrap_values(attributes)
37
36
  @parent = parent
38
- @path = path
37
+ @path = path || []
38
+ self.attributes = wrap_values(attributes)
39
39
  end
40
40
 
41
41
  # Pass the comparison through
@@ -58,9 +58,6 @@ class Model
58
58
  end
59
59
 
60
60
  tag_all_methods do
61
- destructive! do |method_name|
62
- method_name[0] == '_' && method_name[-1] == '='
63
- end
64
61
  pass_reactive! do |method_name|
65
62
  method_name[0] == '_' && method_name[-1] == '='
66
63
  end
@@ -89,7 +86,7 @@ class Model
89
86
  value = args[0]
90
87
  __assign_element(attribute_name, value)
91
88
 
92
- attributes[attribute_name] = wrap_value(value)
89
+ attributes[attribute_name] = wrap_value(value, [attribute_name])
93
90
  trigger_by_attribute!('changed', attribute_name)
94
91
  end
95
92
 
@@ -101,7 +98,7 @@ class Model
101
98
  # Reading an attribute, we may get back a nil model.
102
99
  method_name = method_name.to_sym
103
100
 
104
- if attributes == nil
101
+ if method_name[0] != '_' && attributes == nil
105
102
  # The method we are calling is on a nil model, return a wrapped
106
103
  # exception.
107
104
  return return_undefined_method(method_name)
@@ -109,9 +106,14 @@ class Model
109
106
  # Method has the key, look it up directly
110
107
  return attributes[method_name]
111
108
  else
112
- return new_model(nil, self, method_name)
109
+ return read_new_model(method_name)
113
110
  end
114
111
  end
112
+
113
+ # Get a new model, make it easy to override
114
+ def read_new_model(method_name)
115
+ return new_model(nil, self, path + [method_name])
116
+ end
115
117
 
116
118
  def return_undefined_method(method_name)
117
119
  # Methods called on nil capture an error so the user can know where
@@ -131,6 +133,10 @@ class Model
131
133
  Model.new(*args)
132
134
  end
133
135
 
136
+ def new_array_model(*args)
137
+ ArrayModel.new(*args)
138
+ end
139
+
134
140
  def trigger_by_attribute!(event_name, attribute, *passed_args)
135
141
  trigger_by_scope!(event_name, *passed_args) do |scope|
136
142
  method_name, *args, block = scope
@@ -152,24 +158,26 @@ class Model
152
158
  if @parent
153
159
  @parent.expand!
154
160
 
155
- @parent.attributes[@path] = self
161
+ @parent.attributes[@path.last] = self
156
162
  end
157
163
  end
158
164
  end
159
165
 
160
166
  tag_method(:<<) do
161
- destructive!
162
167
  pass_reactive!
163
168
  end
164
169
  # Initialize an empty array and append to it
165
170
  def <<(value)
166
171
  @parent.expand!
167
- result = @parent.send(@path)
172
+
173
+ # Grab the last section of the path, so we can do the assign on the parent
174
+ path = @path.last
175
+ result = @parent.send(path)
168
176
 
169
177
  if result.nil?
170
178
  # If this isn't a model yet, instantiate it
171
- @parent.send(:"#{@path}=", ArrayModel.new([], @parent, @path))
172
- result = @parent.send(@path)
179
+ @parent.send(:"#{path}=", new_array_model([], @parent, @path))
180
+ result = @parent.send(path)
173
181
 
174
182
  # Add the new item
175
183
  result << value
@@ -179,7 +187,7 @@ class Model
179
187
  end
180
188
 
181
189
  def inspect
182
- "<#{self.class.to_s}:#{@path} #{attributes.inspect}>"
190
+ "<#{self.class.to_s} #{attributes.inspect}>"
183
191
  end
184
192
 
185
193
 
@@ -1,21 +1,28 @@
1
1
  module ModelWrapper
2
2
  # For cretain values, we wrap them to make the behave as a
3
3
  # model.
4
- def wrap_value(value)
4
+ def wrap_value(value, lookup)
5
5
  if value.cur.is_a?(Array)
6
- value = ArrayModel.new(value, self, nil)
6
+ value = new_array_model(value, self, path + lookup)
7
7
  elsif value.cur.is_a?(Hash)
8
- value = Model.new(value)
8
+ value = new_model(value, self, path + lookup)
9
9
  end
10
10
 
11
11
  return value
12
12
  end
13
13
 
14
- def wrap_values(values)
14
+ def wrap_values(values, lookup=[])
15
15
  if values.cur.is_a?(Array)
16
- values = values.map {|v| wrap_value(v) }
16
+ # Coming from an array
17
+ values = values.map {|v| wrap_value(v,lookup + [:[]]) }
17
18
  elsif values.cur.is_a?(Hash)
18
- values = Hash[values.map {|k,v| [k, wrap_value(v)] }]
19
+ pairs = values.map do |k,v|
20
+ path = lookup + [k]
21
+
22
+ [k, wrap_value(v,path)]
23
+ end
24
+
25
+ values = Hash[pairs]
19
26
  end
20
27
 
21
28
  return values
@@ -1,3 +1,5 @@
1
+ require 'volt/models/params_array'
2
+
1
3
  # All url related data is stored in params. This includes the main uri
2
4
  # in addition to any query parameters. The router is responsible for
3
5
  # converting any uri sections into params. Sections in the uri will
@@ -6,7 +8,6 @@
6
8
  # The params value can be updated the same way a model would be, only
7
9
  # the updates will trigger an updated url via the browser history api.
8
10
  # TODO: Support # for browsers without the history api.
9
-
10
11
  class Params < Model
11
12
  def initialize(*args)
12
13
  super(*args)
@@ -64,4 +65,8 @@ class Params < Model
64
65
  def new_model(*args)
65
66
  Params.new(*args)
66
67
  end
68
+
69
+ def new_array_model(*args)
70
+ ParamsArray.new(*args)
71
+ end
67
72
  end
@@ -0,0 +1,9 @@
1
+ class ParamsArray < ArrayModel
2
+ def new_model(*args)
3
+ Params.new(*args)
4
+ end
5
+
6
+ def new_array_model(*args)
7
+ ParamsArray.new(*args)
8
+ end
9
+ end
@@ -0,0 +1,164 @@
1
+ require 'volt/models/store_array'
2
+
3
+ class Store < Model
4
+ ID_CHARS = [('a'..'z'), ('A'..'Z'), ('0'..'9')].map {|v| v.to_a }.flatten
5
+
6
+ @@identity_map = {}
7
+
8
+ def initialize(tasks=nil, *args)
9
+ @tasks = tasks
10
+
11
+ super(*args)
12
+
13
+ track_in_identity_map if attributes && attributes['_id']
14
+
15
+ value_updated
16
+ end
17
+
18
+ # def _id
19
+ # return attributes && attributes['_id']
20
+ # end
21
+
22
+ def event_added(event, scope_provider, first)
23
+ if first && event == :changed
24
+ # Start listening
25
+ ensure_id
26
+ if self.attributes && self.path.size > 1
27
+ channel_name = "#{self.path[-2]}##{self.attributes['_id']}"
28
+ puts "LISTENER ON: #{channel_name.inspect} -- #{self.path.inspect}"
29
+ $page.tasks.call('ChannelTasks', 'add_listener', channel_name)
30
+ end
31
+ end
32
+ end
33
+
34
+ def event_removed(event, no_more_events)
35
+ if no_more_events && event == :changed
36
+ # Stop listening
37
+ if self.attributes && self.path.size > 1
38
+ channel_name = "#{self.path[-2]}##{self.attributes['_id']}"
39
+ puts "REMOVE LISTENER ON: #{channel_name}"
40
+ $page.tasks.call('ChannelTasks', 'remove_listener', channel_name)
41
+ end
42
+ end
43
+ end
44
+
45
+ def self.update(model_id, data)
46
+ model = @@identity_map[model_id]
47
+
48
+ if model
49
+ data.each_pair do |key, value|
50
+ if key != '_id'
51
+ puts "update #{key} with #{value.inspect}"
52
+ model.send(:"#{key}=", value)
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ def generate_id
59
+ id = []
60
+ 12.times { id << ID_CHARS.sample }
61
+
62
+ return id.join
63
+ end
64
+
65
+ def method_missing(method_name, *args, &block)
66
+ result = super
67
+
68
+ if method_name[0] == '_' && method_name[-1] == '='
69
+ # Trigger value updated after an assignment
70
+ self.value_updated
71
+ end
72
+
73
+ return result
74
+ end
75
+
76
+ def track_in_identity_map
77
+ @@identity_map[attributes['_id']] = self
78
+ end
79
+
80
+ # When called, will setup an id if there is not one
81
+ def ensure_id
82
+ # No id yet, lets create one
83
+ if attributes && !attributes['_id']
84
+ self.attributes['_id'] = generate_id
85
+ track_in_identity_map
86
+ end
87
+ end
88
+
89
+ def value_updated
90
+ # puts "VU: #{@tasks.inspect} = #{path.inspect} - #{attributes.inspect}"
91
+ if (!defined?($loading_models) || !$loading_models) && @tasks && path.size > 0 && !self.nil?
92
+
93
+ ensure_id
94
+
95
+ if path.size > 2 && parent && source = parent.parent
96
+ self.attributes[path[-2].to_s.singularize+'_id'] = source._id
97
+ end
98
+
99
+ # Don't store any sub-stores, those will do their own saving.
100
+ attrs = attributes.reject {|k,v| v.is_a?(Model) || v.is_a?(ArrayModel) }
101
+
102
+ puts "Save: #{collection} - #{attrs.inspect}"
103
+ @tasks.call('StoreTasks', 'save', collection, attrs)
104
+ end
105
+ end
106
+
107
+ def collection(path=nil)
108
+ path ||= self.path
109
+
110
+ collection_name = path.last
111
+ collection_name = path[-2] if collection_name == :[]
112
+
113
+ return collection_name
114
+ end
115
+
116
+ # On stores, we store the model so we don't have to look it up
117
+ # every time we do a read.
118
+ def read_new_model(method_name)
119
+ model = new_model(nil, self, path + [method_name])
120
+
121
+ self.attributes ||= {}
122
+ attributes[method_name] = model
123
+
124
+ return model
125
+ end
126
+
127
+
128
+
129
+ def new_model(attributes={}, parent=nil, path=nil, class_paths=nil)
130
+ model = Store.new(@tasks, attributes, parent, path, class_paths)
131
+
132
+ if @tasks && path.last[-1] == 's'
133
+ # puts "FIND NEW MODEL: #{path.inspect} - #{attributes.inspect}"
134
+
135
+ # Check to see the parents scope so we can only lookup associated
136
+ # models.
137
+ scope = {}
138
+
139
+ if parent.attributes && parent.attributes['_id'].true?
140
+ scope[path[-1].singularize + '_id'] = parent._id
141
+ end
142
+
143
+ puts "FIND: #{collection(path).inspect} at #{scope.inspect}"
144
+ @tasks.call('StoreTasks', 'find', collection(path), scope) do |results|
145
+ # TODO: Globals evil, replace
146
+ $loading_models = true
147
+ results.each do |result|
148
+ # Get model again, we need to fetch it each time so it gets the
149
+ # updated model when it switches from nil.
150
+ # TODO: Strange that this is needed
151
+ model = self.send(path.last)
152
+ model << Store.new(@tasks, result, model, path + [:[]], class_paths)
153
+ end
154
+ $loading_models = false
155
+ end
156
+ end
157
+
158
+ return model
159
+ end
160
+
161
+ def new_array_model(*args)
162
+ StoreArray.new(@tasks, *args)
163
+ end
164
+ end
@@ -0,0 +1,15 @@
1
+ class StoreArray < ArrayModel
2
+ def initialize(tasks=nil, array=[], parent=nil, path=nil)
3
+ @tasks = tasks
4
+
5
+ super(array, parent, path)
6
+ end
7
+
8
+ def new_model(*args)
9
+ Store.new(@tasks, *args)
10
+ end
11
+
12
+ def new_array_model(*args)
13
+ StoreArray.new(@tasks, *args)
14
+ end
15
+ end
@@ -60,10 +60,6 @@ class URL
60
60
  # Called when the state has changed and the url in the
61
61
  # browser should be updated
62
62
  # Called when an attribute changes to update the url
63
- tag_method(:update!) do
64
- destructive!
65
- # TODO: ! methods should default to destructive
66
- end
67
63
  def update!
68
64
  new_url = full_url()
69
65
 
data/lib/volt/models.rb CHANGED
@@ -2,4 +2,5 @@ require 'volt/extra_core/extra_core'
2
2
  require 'volt/reactive/reactive_value'
3
3
  require 'volt/models/model'
4
4
  require 'volt/models/params'
5
+ require 'volt/models/store'
5
6
 
@@ -1,5 +1,5 @@
1
- require 'volt/templates/base_binding'
2
- require 'volt/templates/targets/attribute_target'
1
+ require 'volt/page/bindings/base_binding'
2
+ require 'volt/page/targets/attribute_target'
3
3
 
4
4
  class AttributeBinding < BaseBinding
5
5
  def initialize(target, context, binding_name, attribute_name, getter)
@@ -82,11 +82,7 @@ class AttributeBinding < BaseBinding
82
82
  value = false
83
83
  end
84
84
 
85
- if value
86
- element['checked'] = 'checked'
87
- else
88
- element.remove_attr('checked')
89
- end
85
+ element.prop('checked', value)
90
86
 
91
87
  end
92
88
 
@@ -104,6 +100,11 @@ class AttributeBinding < BaseBinding
104
100
  @update_listener.remove
105
101
  @update_listener = nil
106
102
  end
103
+
104
+ # Clear any references
105
+ @target = nil
106
+ @context = nil
107
+ @section = nil
107
108
  end
108
109
 
109
110
 
@@ -13,8 +13,13 @@ class BaseBinding
13
13
  @section ||= target.section(@binding_name)
14
14
  end
15
15
 
16
- def remove
16
+ def remove
17
17
  section.remove
18
+
19
+ # Clear any references
20
+ @target = nil
21
+ @context = nil
22
+ @section = nil
18
23
  end
19
24
 
20
25
  def remove_anchors
@@ -1,4 +1,4 @@
1
- require 'volt/templates/base_binding'
1
+ require 'volt/page/bindings/base_binding'
2
2
 
3
3
  class ContentBinding < BaseBinding
4
4
  def initialize(target, context, binding_name, getter)
@@ -1,4 +1,4 @@
1
- require 'volt/templates/base_binding'
1
+ require 'volt/page/bindings/base_binding'
2
2
 
3
3
  class EachBinding < BaseBinding
4
4
  def initialize(target, context, binding_name, getter, variable_name, template_name)
@@ -17,20 +17,23 @@ class EachBinding < BaseBinding
17
17
  # Run the initial render
18
18
  update
19
19
 
20
- @added_listener = @value.on('added') { |position, item| puts "ADDED" ; item_added(position) }
20
+ @added_listener = @value.on('added') { |_, position, item| puts "ADDED" ; item_added(position) }
21
21
  @changed_listener = @value.on('changed') { puts "CHANGED" ; reload }
22
- @removed_listener = @value.on('removed') { |position| puts "REMOVED at #{position.inspect}" ; item_removed(position) }
22
+ @removed_listener = @value.on('removed') { |_, position| item_removed(position) }
23
23
  end
24
24
 
25
25
  # When a change event comes through, its most likely upstream, so the whole
26
26
  # array might have changed. In this case, just reload the whole thing
27
27
  # TODO: Track to make sure the changed event isn't being called too often (it is currently)
28
28
  def reload
29
+ # ObjectTracker.enable_cache
29
30
  # Remove all of the current templates
30
31
  if @templates
31
32
  @templates.each do |template|
32
- template.remove
33
33
  template.remove_anchors
34
+
35
+ # TODO: Make sure this is being removed since we already removed the anchors
36
+ template.remove
34
37
  end
35
38
  end
36
39
 
@@ -38,12 +41,14 @@ class EachBinding < BaseBinding
38
41
 
39
42
  # Run update again to rebuild
40
43
  update
44
+
45
+ # ObjectTracker.disable_cache
41
46
  end
42
47
 
43
48
  def item_removed(position)
44
49
  position = position.cur
45
- @templates[position].remove
46
50
  @templates[position].remove_anchors
51
+ @templates[position].remove
47
52
  @templates.delete_at(position)
48
53
 
49
54
  value_obj = @value.cur
@@ -63,7 +68,8 @@ class EachBinding < BaseBinding
63
68
  end
64
69
 
65
70
  def item_added(position)
66
- # puts "ADDED AT #{position}"
71
+ # ObjectTracker.enable_cache
72
+ # puts "ADDED 1"
67
73
  binding_name = @@binding_number
68
74
  @@binding_number += 1
69
75
 
@@ -75,7 +81,10 @@ class EachBinding < BaseBinding
75
81
 
76
82
  item_context = SubContext.new({@item_name => value, :index => index, :parent => @value}, @context)
77
83
 
84
+ # ObjectTracker.enable_cache
78
85
  @templates << TemplateRenderer.new(@target, item_context, binding_name, @template_name)
86
+ # puts "ADDED 2"
87
+ # ObjectTracker.disable_cache
79
88
  end
80
89
 
81
90
  def update(item=nil)
@@ -1,4 +1,4 @@
1
- require 'volt/templates/base_binding'
1
+ require 'volt/page/bindings/base_binding'
2
2
 
3
3
  # TODO: We need to figure out how we want to wrap JS events
4
4
  class JSEvent
@@ -39,10 +39,6 @@ class EventBinding < BaseBinding
39
39
  @listener = $page.events.add(event_name, self, handler)
40
40
  end
41
41
 
42
- def element
43
- Element.find('#' + binding_name)
44
- end
45
-
46
42
  # Remove the event binding
47
43
  def remove
48
44
  # puts "REMOVE EL FOR #{@event}"
@@ -1,4 +1,4 @@
1
- require 'volt/templates/base_binding'
1
+ require 'volt/page/bindings/base_binding'
2
2
 
3
3
  class IfBinding < BaseBinding
4
4
  def initialize(target, context, binding_name, branches)