volt 0.9.4.pre3 → 0.9.4.pre5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/CODE_OF_CONDUCT.md +15 -0
  4. data/README.md +2 -0
  5. data/app/volt/models/user.rb +6 -4
  6. data/lib/volt/boot.rb +0 -2
  7. data/lib/volt/cli/bundle.rb +29 -0
  8. data/lib/volt/cli/console.rb +2 -2
  9. data/lib/volt/cli/generate.rb +2 -0
  10. data/lib/volt/cli/new_gem.rb +23 -0
  11. data/lib/volt/cli.rb +15 -2
  12. data/lib/volt/controllers/collection_helpers.rb +34 -3
  13. data/lib/volt/controllers/http_controller.rb +1 -1
  14. data/lib/volt/controllers/model_controller.rb +9 -33
  15. data/lib/volt/helpers/time.rb +43 -0
  16. data/lib/volt/models/array_model.rb +96 -90
  17. data/lib/volt/models/buffer.rb +42 -7
  18. data/lib/volt/models/helpers/array_model.rb +15 -0
  19. data/lib/volt/models/helpers/base.rb +113 -0
  20. data/lib/volt/models/helpers/change_helpers.rb +91 -0
  21. data/lib/volt/models/helpers/dirty.rb +93 -0
  22. data/lib/volt/models/helpers/listener_tracker.rb +19 -0
  23. data/lib/volt/models/helpers/model.rb +15 -0
  24. data/lib/volt/models/model.rb +17 -12
  25. data/lib/volt/models/permissions.rb +1 -1
  26. data/lib/volt/models/persistors/array_store.rb +4 -0
  27. data/lib/volt/models/persistors/base.rb +10 -0
  28. data/lib/volt/models/persistors/cookies.rb +2 -0
  29. data/lib/volt/models/persistors/local_store.rb +3 -0
  30. data/lib/volt/models/persistors/model_store.rb +7 -0
  31. data/lib/volt/models/persistors/params.rb +4 -1
  32. data/lib/volt/models/persistors/query/query_listener.rb +1 -1
  33. data/lib/volt/models/url.rb +12 -7
  34. data/lib/volt/models/validators/unique_validator.rb +1 -1
  35. data/lib/volt/page/bindings/base_binding.rb +2 -2
  36. data/lib/volt/page/bindings/event_binding.rb +2 -2
  37. data/lib/volt/page/bindings/view_binding/controller_handler.rb +20 -0
  38. data/lib/volt/page/bindings/view_binding/view_lookup_for_path.rb +6 -4
  39. data/lib/volt/page/bindings/view_binding.rb +7 -7
  40. data/lib/volt/page/path_string_renderer.rb +2 -4
  41. data/lib/volt/page/targets/base_section.rb +3 -3
  42. data/lib/volt/page/targets/dom_template.rb +2 -2
  43. data/lib/volt/page/tasks.rb +6 -6
  44. data/lib/volt/page/template_renderer.rb +1 -1
  45. data/lib/volt/page/url_tracker.rb +4 -4
  46. data/lib/volt/reactive/reactive_array.rb +31 -20
  47. data/lib/volt/server/component_templates.rb +5 -5
  48. data/lib/volt/server/forking_server.rb +2 -2
  49. data/lib/volt/server/message_bus/peer_to_peer/server_tracker.rb +3 -3
  50. data/lib/volt/server/message_bus/peer_to_peer.rb +7 -7
  51. data/lib/volt/server/rack/asset_files.rb +28 -8
  52. data/lib/volt/server/rack/component_paths.rb +4 -4
  53. data/lib/volt/server/rack/opal_files.rb +0 -1
  54. data/lib/volt/server/socket_connection_handler.rb +5 -2
  55. data/lib/volt/server.rb +0 -1
  56. data/lib/volt/spec/setup.rb +4 -5
  57. data/lib/volt/tasks/task.rb +2 -3
  58. data/lib/volt/utils/promise_extensions.rb +22 -6
  59. data/lib/volt/utils/time_patch.rb +12 -0
  60. data/lib/volt/utils/timers.rb +14 -2
  61. data/lib/volt/version.rb +1 -1
  62. data/lib/volt/volt/app.rb +44 -12
  63. data/lib/volt/volt/client_setup/browser.rb +113 -0
  64. data/lib/volt/volt/repos.rb +48 -0
  65. data/lib/volt/volt/server_setup/app.rb +1 -2
  66. data/lib/volt/volt/templates.rb +39 -0
  67. data/lib/volt/volt/users.rb +4 -4
  68. data/lib/volt.rb +1 -0
  69. data/spec/apps/file_loading/app/disable_auto/assets/css/test1.css.scss +0 -0
  70. data/spec/apps/file_loading/app/disable_auto/assets/css/test2.css.scss +0 -0
  71. data/spec/apps/file_loading/app/disable_auto/assets/js/test1.js +0 -0
  72. data/spec/apps/file_loading/app/disable_auto/assets/js/test2.js +0 -0
  73. data/spec/apps/file_loading/app/disable_auto/config/dependencies.rb +3 -0
  74. data/spec/apps/file_loading/app/main/assets/css/test3.css +0 -0
  75. data/spec/apps/file_loading/app/shared/config/dependencies.rb +1 -1
  76. data/spec/controllers/model_controller_spec.rb +7 -0
  77. data/spec/models/{model_helpers/model_helpers_spec.rb → helpers/base_spec.rb} +1 -1
  78. data/spec/models/helpers/model_spec.rb +26 -0
  79. data/spec/models/model_spec.rb +9 -0
  80. data/spec/models/persistors/params_spec.rb +1 -1
  81. data/spec/models/persistors/store_spec.rb +1 -0
  82. data/spec/page/bindings/content_binding_spec.rb +2 -4
  83. data/spec/page/bindings/each_binding_spec.rb +1 -4
  84. data/spec/page/bindings/if_binding_spec.rb +1 -4
  85. data/spec/page/bindings/template_binding/view_lookup_for_path_spec.rb +17 -27
  86. data/spec/page/path_string_renderer_spec.rb +15 -4
  87. data/spec/server/rack/asset_files_spec.rb +88 -8
  88. data/spec/tasks/user_tasks_spec.rb +1 -1
  89. data/spec/utils/promise_extensions_spec.rb +22 -0
  90. data/spec/volt/repos_spec.rb +11 -0
  91. data/templates/newgem/CODE_OF_CONDUCT.md.tt +13 -0
  92. data/templates/project/app/main/config/routes.rb +4 -1
  93. metadata +34 -10
  94. data/lib/volt/models/model_helpers/dirty.rb +0 -88
  95. data/lib/volt/models/model_helpers/listener_tracker.rb +0 -15
  96. data/lib/volt/models/model_helpers/model_change_helpers.rb +0 -87
  97. data/lib/volt/models/model_helpers/model_helpers.rb +0 -110
  98. data/lib/volt/models/state_helpers.rb +0 -11
  99. data/lib/volt/page/page.rb +0 -190
@@ -1,3 +1,5 @@
1
+ require 'volt/reactive/reactive_accessors'
2
+
1
3
  module Volt
2
4
  module Buffer
3
5
  # Save saves the contents of a buffer to the save_to location. If the buffer is new, it will create a new
@@ -14,7 +16,8 @@ module Volt
14
16
  result = nil
15
17
 
16
18
  if errors.size == 0
17
- save_to = options[:save_to]
19
+ # cache save_to in a local
20
+ save_to = self.save_to
18
21
  if save_to
19
22
  if save_to.is_a?(ArrayModel)
20
23
  # Add to the collection
@@ -33,7 +36,7 @@ module Volt
33
36
  new_model.change_state_to(:loaded_state, :loaded)
34
37
 
35
38
  # Set the buffer's id to track the main model's id
36
- options[:save_to] = new_model
39
+ self.save_to = new_model
37
40
  end
38
41
 
39
42
  # Copy attributes back from save_to model
@@ -76,11 +79,7 @@ module Volt
76
79
  end
77
80
 
78
81
  def buffer?
79
- options[:buffer]
80
- end
81
-
82
- def save_to
83
- options[:save_to]
82
+ options[:buffer] || false
84
83
  end
85
84
 
86
85
  # Returns a buffered version of the model
@@ -100,5 +99,41 @@ module Volt
100
99
 
101
100
  model
102
101
  end
102
+
103
+ def self.included(base)
104
+ base.include ReactiveAccessors
105
+ base.reactive_accessor :__save_to
106
+ end
107
+
108
+ def save_to
109
+ val = __save_to
110
+
111
+ unless val
112
+ # Lazy load the save_to
113
+ self.save_to = options[:save_to]
114
+ return __save_to
115
+ end
116
+
117
+ val
118
+ end
119
+
120
+ def save_to=(val)
121
+ self.__save_to = val
122
+ end
123
+
124
+ def saved_state
125
+ if buffer?
126
+ # cache save_to in local
127
+ lsave_to = self.save_to
128
+
129
+ lsave_to.try(:saved_state) || :not_saved
130
+ else
131
+ super
132
+ end
133
+ end
134
+
135
+ def saved?
136
+ saved_state == :saved
137
+ end
103
138
  end
104
139
  end
@@ -0,0 +1,15 @@
1
+ module Volt
2
+ module Models
3
+ module Helpers
4
+ module ArrayModel
5
+ def loaded_state
6
+ state_for(:loaded_state)
7
+ end
8
+
9
+ def loaded?
10
+ loaded_state == :loaded
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,113 @@
1
+ module Volt
2
+ module Models
3
+ module Helpers
4
+ # A place for things shared between an ArrayModel and a Model
5
+ module Base
6
+ def deep_unwrap(value)
7
+ if value.is_a?(Model)
8
+ value.to_h
9
+ elsif value.is_a?(ArrayModel)
10
+ value.to_a
11
+ else
12
+ value
13
+ end
14
+ end
15
+
16
+ # Pass to the persisotr
17
+ def event_added(event, first, first_for_event)
18
+ @persistor.event_added(event, first, first_for_event) if @persistor
19
+ end
20
+
21
+ # Pass to the persistor
22
+ def event_removed(event, last, last_for_event)
23
+ @persistor.event_removed(event, last, last_for_event) if @persistor
24
+ end
25
+
26
+ ID_CHARS = [('a'..'f'), ('0'..'9')].map(&:to_a).flatten
27
+
28
+ # Create a random unique id that can be used as the mongo id as well
29
+ def generate_id
30
+ id = []
31
+ 24.times { id << ID_CHARS.sample }
32
+
33
+ id.join
34
+ end
35
+
36
+
37
+ # Return the attributes that are only for this model and any hash sub models
38
+ # but not any sub-associations.
39
+ def self_attributes
40
+ # Don't store any sub-models, those will do their own saving.
41
+ attributes.reject { |k, v| v.is_a?(ArrayModel) }.map do |k,v|
42
+ if v.is_a?(Model)
43
+ v = v.self_attributes
44
+ end
45
+
46
+ [k,v]
47
+ end.to_h
48
+ end
49
+
50
+
51
+ # Takes the persistor if there is one and
52
+ def setup_persistor(persistor)
53
+ # Use page as the default persistor
54
+ persistor ||= Persistors::Page
55
+ if persistor.respond_to?(:new)
56
+ @persistor = persistor.new(self)
57
+ else
58
+ # an already initialized persistor was passed in
59
+ @persistor = persistor
60
+ end
61
+ end
62
+
63
+ def store
64
+ Volt.current_app.store
65
+ end
66
+
67
+ # returns the root model for the collection the model is currently on. So
68
+ # if the model is persisted somewhere on store, it will return ```store```
69
+ def root
70
+ persistor.try(:root_model)
71
+ end
72
+
73
+ module ClassMethods
74
+ # Gets the class for a model at the specified path.
75
+ def class_at_path(path)
76
+ if path
77
+ begin
78
+ # remove the _ and then singularize/pluralize
79
+ if path.last == :[]
80
+ index = -2
81
+ else
82
+ index = -1
83
+ end
84
+
85
+ # process_class_name is defined by Model/ArrayModel as
86
+ # singularize/pluralize
87
+ klass_name = process_class_name(klass_name = path[index]).camelize
88
+
89
+ # Lookup the class
90
+ klass = Object.const_get(klass_name)
91
+
92
+ # Use it if it is a model
93
+ klass = self unless klass < self
94
+ rescue NameError => e
95
+ # Ignore exception, just means the model isn't defined
96
+ klass = self
97
+ end
98
+ else
99
+ klass = self
100
+ end
101
+
102
+ klass
103
+ end
104
+ end
105
+
106
+ def self.included(base)
107
+ base.send :extend, ClassMethods
108
+ end
109
+
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,91 @@
1
+ # ModelChangeHelpers handle validating and persisting the data in a model
2
+ # when it is changed. #run_changed will be called from the model.
3
+ module Volt
4
+ module Models
5
+ module Helpers
6
+ module ChangeHelpers
7
+ def self.included(base)
8
+ base.setup_action_helpers_in_class(:before_save, :before_validate)
9
+ end
10
+
11
+ # Called when something in the model changes. Saves
12
+ # the model if there is a persistor, and changes the
13
+ # model to not be new.
14
+ #
15
+ # @return [Promise|nil] a promise for when the save is
16
+ # complete
17
+ def run_changed(attribute_name = nil)
18
+ # no_validate mode should only be used internally. no_validate mode is a
19
+ # performance optimization that prevents validation from running after each
20
+ # change when assigning multile attributes.
21
+ unless Volt.in_mode?(:no_validate)
22
+ # Run the validations for all fields
23
+ result = nil
24
+ return validate!.then do
25
+ # Buffers are allowed to be in an invalid state
26
+ unless buffer?
27
+ # First check that all local validations pass
28
+ if error_in_changed_attributes?
29
+ # Some errors are present, revert changes
30
+ revert_changes!
31
+
32
+ # After we revert, we need to validate again to get the error messages back
33
+ # TODO: Could probably cache the previous errors.
34
+ result = validate!.then do
35
+ # Reject the promise with the errors
36
+ Promise.new.reject(errs)
37
+ end
38
+ else
39
+ result = persist_changes(attribute_name)
40
+ end
41
+ end
42
+
43
+ # Return result inside of the validate! promise
44
+ result.then { self }
45
+ end
46
+ end
47
+
48
+ # Didn't run validations
49
+ self.then
50
+ end
51
+
52
+
53
+ private
54
+ # Should only be called from run_changed. Saves the changes back to the persistor
55
+ # and clears the tracked changes.
56
+ def persist_changes(attribute_name)
57
+ # No errors, tell the persistor to handle the change (usually save)
58
+ result = nil
59
+
60
+ # Don't save right now if we're in a nosave block
61
+ unless Volt.in_mode?(:no_save)
62
+ # Call the before_save callback
63
+ # skip validations when running before_save, this prevents n+1, and allows
64
+ # the before_save to put the model into an invalid state, which you want
65
+ # sometimes.
66
+ Volt::Model.no_validate do
67
+ run_callbacks(:before_save)
68
+ end
69
+
70
+ # the changed method on a persistor should return a promise that will
71
+ # be resolved when the save is complete, or fail with a hash of errors.
72
+ if @persistor
73
+ result = @persistor.changed(attribute_name)
74
+ else
75
+ result = Promise.new.resolve(nil)
76
+ end
77
+
78
+ # Saved, no longer new
79
+ @new = false
80
+
81
+ # Clear the change tracking
82
+ clear_tracked_changes!
83
+ end
84
+
85
+ result
86
+ end
87
+
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,93 @@
1
+ module Volt
2
+ module Models
3
+ module Helpers
4
+ # The dirty module provides helper methods for working with and tracking
5
+ # previous values on model attributes.
6
+ module Dirty
7
+ # Return the list of attributes that have changed since the last 'save' event.
8
+ def changed_attributes
9
+ @changed_attributes ||= {}
10
+ end
11
+
12
+ # Return true if key has changed
13
+ def changed?(key = nil)
14
+ if key
15
+ # return the changed values for the keys
16
+ changed_attributes.key?(key)
17
+ else
18
+ changed_attributes.present?
19
+ end
20
+ end
21
+
22
+ # Grab all previous versions of for key
23
+ def changes(key)
24
+ changed_attributes[key]
25
+ end
26
+
27
+ # Grab the previous value for the key
28
+ def was(key)
29
+ val = changed_attributes[key]
30
+
31
+ # Doing val && val[0] doesn't work in opal
32
+ # https://github.com/opal/opal/issues/664
33
+ if val
34
+ val[0]
35
+ else
36
+ nil
37
+ end
38
+ end
39
+
40
+ # Clear changed attributes
41
+ def clear_tracked_changes!
42
+ @changed_attributes = {}
43
+ end
44
+
45
+ # Reverts the model attributes back to the pre-change values.
46
+ def revert_changes!
47
+ # Reassign the first value since we started tracking
48
+ if @changed_attributes
49
+ @changed_attributes.each_pair do |key, value|
50
+ @attributes[key] = value.first
51
+ end
52
+ end
53
+
54
+ clear_tracked_changes!
55
+ end
56
+
57
+ def attribute_will_change!(attribute_name, old_value)
58
+ # Don't track nil models
59
+ old_value = nil if old_value.nil?
60
+
61
+ (changed_attributes[attribute_name] ||= []) << old_value
62
+ end
63
+
64
+ # Handle change and was method calls
65
+ # Example: name_was or name_changes
66
+ def method_missing(method_name, *args, &block)
67
+ # Quick check to see if changes or was are being called, this check
68
+ # keeps us from needing to parse out the parts if we're not going
69
+ # to use them.
70
+ if method_name =~ /[_](changes|was)$/
71
+ # Break apart the method call
72
+ # TODO: no destructuring because of https://github.com/opal/opal/issues/663
73
+ *parts = method_name.to_s.split('_')
74
+ action = parts.pop
75
+ key = parts.join('_').to_sym
76
+
77
+ # Handle changes or was calls.
78
+ case action
79
+ when 'changes'
80
+ return changes(key)
81
+ when 'was'
82
+ return was(key)
83
+ end
84
+ end
85
+
86
+ # Otherwise, run super
87
+ super
88
+ end
89
+ end
90
+ end
91
+
92
+ end
93
+ end
@@ -0,0 +1,19 @@
1
+ module Volt
2
+ module Models
3
+ module Helpers
4
+ # Included in model's so they can inform the ArrayModel when new listeners are added or removed.
5
+ module ListenerTracker
6
+ # Called when data from this model begins being watched
7
+ def listener_added
8
+ @listener_count ||= 0
9
+ @listener_count += 1
10
+ end
11
+
12
+ def listener_removed
13
+ @listener_count ||= 0
14
+ @listener_count -= 1
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ module Volt
2
+ module Models
3
+ module Helpers
4
+ module Model
5
+ def saved_state
6
+ state_for(:saved_state) || :saved
7
+ end
8
+
9
+ def saved?
10
+ saved_state == :saved
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,18 +1,18 @@
1
1
  require 'volt/models/model_wrapper'
2
2
  require 'volt/models/array_model'
3
- require 'volt/models/model_helpers/model_helpers'
3
+ require 'volt/models/helpers/base'
4
4
  require 'volt/models/model_hash_behaviour'
5
5
  require 'volt/models/validations/validations'
6
6
  require 'volt/utils/modes'
7
7
  require 'volt/models/state_manager'
8
- require 'volt/models/state_helpers'
8
+ require 'volt/models/helpers/model'
9
9
  require 'volt/models/buffer'
10
10
  require 'volt/models/field_helpers'
11
11
  require 'volt/reactive/reactive_hash'
12
12
  require 'volt/models/validators/user_validation'
13
- require 'volt/models/model_helpers/dirty'
14
- require 'volt/models/model_helpers/listener_tracker'
15
- require 'volt/models/model_helpers/model_change_helpers'
13
+ require 'volt/models/helpers/dirty'
14
+ require 'volt/models/helpers/listener_tracker'
15
+ require 'volt/models/helpers/change_helpers'
16
16
  require 'volt/models/permissions'
17
17
  require 'volt/models/associations'
18
18
  require 'volt/reactive/class_eventable'
@@ -33,22 +33,23 @@ module Volt
33
33
  class Model
34
34
  include LifecycleCallbacks
35
35
  include ModelWrapper
36
- include ModelHelpers
36
+ include Models::Helpers::Base
37
37
  include ModelHashBehaviour
38
38
  include StateManager
39
- include StateHelpers
39
+ include Models::Helpers::Model
40
40
  include Validations
41
+ # Buffer needs to go after StateHelpers so it can call saved_state as super
41
42
  include Buffer
42
43
  include FieldHelpers
43
44
  include UserValidatorHelpers
44
- include Dirty
45
+ include Models::Helpers::Dirty
45
46
  include ClassEventable
46
47
  include Modes
47
- include ListenerTracker
48
+ include Models::Helpers::ListenerTracker
48
49
  include Permissions
49
50
  include Associations
50
51
  include ReactiveAccessors
51
- include ModelChangeHelpers
52
+ include Models::Helpers::ChangeHelpers
52
53
 
53
54
  attr_reader :attributes, :parent, :path, :persistor, :options
54
55
 
@@ -305,7 +306,7 @@ module Volt
305
306
  options = options.dup
306
307
  options[:query] = []
307
308
 
308
- ArrayModel.new(attributes, options)
309
+ Volt::ArrayModel.class_at_path(options[:path]).new(attributes, options)
309
310
  end
310
311
 
311
312
  def inspect
@@ -336,7 +337,7 @@ module Volt
336
337
  result = parent.delete(self)
337
338
 
338
339
  # Wrap result in a promise if it isn't one
339
- return result.then
340
+ return result#.then
340
341
  else
341
342
  fail 'Model does not have a parent and cannot be deleted.'
342
343
  end
@@ -416,5 +417,9 @@ module Volt
416
417
  end
417
418
  end
418
419
 
420
+ def self.process_class_name(name)
421
+ name.singularize
422
+ end
423
+
419
424
  end
420
425
  end
@@ -23,7 +23,7 @@ module Volt
23
23
  end
24
24
  end
25
25
 
26
- on(:create, :update) do
26
+ permissions(:update) do
27
27
  # Don't allow the key to be changed
28
28
  deny(key)
29
29
  end
@@ -309,6 +309,10 @@ module Volt
309
309
  @ids.delete(model.id)
310
310
  end
311
311
  end
312
+
313
+ def async?
314
+ true
315
+ end
312
316
  end
313
317
  end
314
318
  end
@@ -10,6 +10,10 @@ module Volt
10
10
  @model.change_state_to(:loaded_state, initial_state || :loaded)
11
11
  end
12
12
 
13
+ # Method that is called when data on the model changes.
14
+ # @returns [true|Promise] - should return a Promise or true. On async
15
+ # persistors, the promise from set and save! will wait on the
16
+ # Promise.
13
17
  def changed(attribute_name)
14
18
  end
15
19
 
@@ -36,6 +40,12 @@ module Volt
36
40
  false
37
41
  end
38
42
 
43
+ # return true if this persistor is asynchronus and needs to return
44
+ # Promises.
45
+ def async?
46
+ false
47
+ end
48
+
39
49
  # Find the root for this model
40
50
  def root_model
41
51
  node = @model
@@ -76,6 +76,8 @@ module Volt
76
76
  # Temp, expire in 1 year, going to expand this api
77
77
  write_cookie(attribute_name, value.to_s, expires: Time.now + (356 * 24 * 60 * 60), path: '/')
78
78
  end
79
+
80
+ true
79
81
  end
80
82
 
81
83
  def removed(attribute_name)
@@ -12,6 +12,7 @@ module Volt
12
12
  end
13
13
 
14
14
  def loaded(initial_state = nil)
15
+ super
15
16
  # When the main model is first loaded, we pull in the data from the
16
17
  # store if it exists
17
18
  if @model.path == []
@@ -31,6 +32,8 @@ module Volt
31
32
  # Callled when an item is changed (or removed)
32
33
  def changed(attribute_name)
33
34
  root_model.persistor.save_all
35
+
36
+ true
34
37
  end
35
38
 
36
39
  # Called on the root
@@ -103,14 +103,21 @@ module Volt
103
103
  delete self.saveTimer;
104
104
  `
105
105
 
106
+ @model.change_state_to(:saved_state, :saving)
107
+
106
108
  StoreTasks.save(collection, @model.path, self_attributes).then do
107
109
  save_promises = @save_promises
108
110
  @save_promises = nil
109
111
  save_promises.each { |promise| promise.resolve(nil) }
112
+
113
+ @model.change_state_to(:saved_state, :saved)
110
114
  end.fail do |errors|
111
115
  save_promises = @save_promises
112
116
  @save_promises = nil
113
117
  save_promises.each { |promise| promise.reject(errors) }
118
+
119
+ # Mark that we failed to save
120
+ @model.change_state_to(:saved_state, :save_failed)
114
121
  end
115
122
  end
116
123
 
@@ -13,11 +13,14 @@ module Volt
13
13
  window.paramsUpdateTimer = setTimeout(this.$run_update.bind(this), 0);
14
14
  }
15
15
  `
16
+
16
17
  end
18
+
19
+ true
17
20
  end
18
21
 
19
22
  def run_update
20
- $page.url.update! if Volt.client?
23
+ Volt.current_app.url.update! if Volt.client?
21
24
  end
22
25
  end
23
26
  end
@@ -49,7 +49,7 @@ module Volt
49
49
  # If we get back that the user signature is wrong, log the user out.
50
50
  if err.to_s.start_with?('user id or hash is incorrectly signed')
51
51
  # Delete the invalid cookie
52
- $page.cookies.delete(:user_id)
52
+ Volt.current_app.cookies.delete(:user_id)
53
53
  end
54
54
 
55
55
  fail err
@@ -123,15 +123,20 @@ module Volt
123
123
  frag = fragment
124
124
  if frag.present?
125
125
  # Scroll to anchor via http://www.w3.org/html/wg/drafts/html/master/browsers.html#scroll-to-fragid
126
+ # Sometimes the fragment will cause a jquery parsing error, so we
127
+ # catch any exceptions.
126
128
  `
127
- var anchor = $('#' + frag);
128
- if (anchor.length == 0) {
129
- anchor = $('*[name="' + frag + '"]:first');
130
- }
131
- if (anchor && anchor.length > 0) {
132
- console.log('scroll to: ', anchor.offset().top);
133
- $(document.body).scrollTop(anchor.offset().top);
129
+ try {
130
+ var anchor = $('#' + frag);
131
+ if (anchor.length == 0) {
132
+ anchor = $('*[name="' + frag + '"]:first');
133
+ }
134
+ if (anchor && anchor.length > 0) {
135
+ console.log('scroll to: ', anchor.offset().top);
136
+ $(document.body).scrollTop(anchor.offset().top);
137
+ }
134
138
  }
139
+ catch(e) {}
135
140
  `
136
141
  else
137
142
  # Scroll to the top by default
@@ -12,7 +12,7 @@ module Volt
12
12
 
13
13
  # Check if the value is taken
14
14
  # TODO: need a way to handle scope for unique
15
- return $page.store.get(model.path[-2]).where(query).first.then do |item|
15
+ return Volt.current_app.store.get(model.path[-2]).where(query).first.then do |item|
16
16
  if item
17
17
  message = (args.is_a?(Hash) && args[:message]) || 'is already taken'
18
18
 
@@ -21,8 +21,8 @@ module Volt
21
21
  @@binding_number ||= 10_000
22
22
  end
23
23
 
24
- def page
25
- @volt_app.page
24
+ def browser
25
+ @volt_app.browser
26
26
  end
27
27
 
28
28
  def dom_section