volt 0.3.7 → 0.3.8

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