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,87 +0,0 @@
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
-
4
- module Volt
5
- module ModelChangeHelpers
6
- def self.included(base)
7
- base.setup_action_helpers_in_class(:before_save, :before_validate)
8
- end
9
-
10
- # Called when something in the model changes. Saves
11
- # the model if there is a persistor, and changes the
12
- # model to not be new.
13
- #
14
- # @return [Promise|nil] a promise for when the save is
15
- # complete
16
- def run_changed(attribute_name = nil)
17
- # no_validate mode should only be used internally. no_validate mode is a
18
- # performance optimization that prevents validation from running after each
19
- # change when assigning multile attributes.
20
- unless Volt.in_mode?(:no_validate)
21
- # Run the validations for all fields
22
- result = nil
23
- return validate!.then do
24
- # Buffers are allowed to be in an invalid state
25
- unless buffer?
26
- # First check that all local validations pass
27
- if error_in_changed_attributes?
28
- # Some errors are present, revert changes
29
- revert_changes!
30
-
31
- # After we revert, we need to validate again to get the error messages back
32
- # TODO: Could probably cache the previous errors.
33
- result = validate!.then do
34
- # Reject the promise with the errors
35
- Promise.new.reject(errs)
36
- end
37
- else
38
- result = persist_changes(attribute_name)
39
- end
40
- end
41
-
42
- # Return result inside of the validate! promise
43
- result.then { self }
44
- end
45
- end
46
-
47
- # Didn't run validations
48
- self.then
49
- end
50
-
51
-
52
- private
53
- # Should only be called from run_changed. Saves the changes back to the persistor
54
- # and clears the tracked changes.
55
- def persist_changes(attribute_name)
56
- # No errors, tell the persistor to handle the change (usually save)
57
-
58
- # Don't save right now if we're in a nosave block
59
- unless Volt.in_mode?(:no_save)
60
- # Call the before_save callback
61
- # skip validations when running before_save, this prevents n+1, and allows
62
- # the before_save to put the model into an invalid state, which you want
63
- # sometimes.
64
- Volt::Model.no_validate do
65
- run_callbacks(:before_save)
66
- end
67
-
68
- # the changed method on a persistor should return a promise that will
69
- # be resolved when the save is complete, or fail with a hash of errors.
70
- if @persistor
71
- result = @persistor.changed(attribute_name)
72
- else
73
- result = Promise.new.resolve(nil)
74
- end
75
-
76
- # Saved, no longer new
77
- @new = false
78
-
79
- # Clear the change tracking
80
- clear_tracked_changes!
81
- end
82
-
83
- result
84
- end
85
-
86
- end
87
- end
@@ -1,110 +0,0 @@
1
- module Volt
2
- # A place for things shared between an ArrayModel and a Model
3
- module ModelHelpers
4
- def deep_unwrap(value)
5
- if value.is_a?(Model)
6
- value.to_h
7
- elsif value.is_a?(ArrayModel)
8
- value.to_a
9
- else
10
- value
11
- end
12
- end
13
-
14
- # Pass to the persisotr
15
- def event_added(event, first, first_for_event)
16
- @persistor.event_added(event, first, first_for_event) if @persistor
17
- end
18
-
19
- # Pass to the persistor
20
- def event_removed(event, last, last_for_event)
21
- @persistor.event_removed(event, last, last_for_event) if @persistor
22
- end
23
-
24
- ID_CHARS = [('a'..'f'), ('0'..'9')].map(&:to_a).flatten
25
-
26
- # Create a random unique id that can be used as the mongo id as well
27
- def generate_id
28
- id = []
29
- 24.times { id << ID_CHARS.sample }
30
-
31
- id.join
32
- end
33
-
34
-
35
- # Return the attributes that are only for this model and any hash sub models
36
- # but not any sub-associations.
37
- def self_attributes
38
- # Don't store any sub-models, those will do their own saving.
39
- attributes.reject { |k, v| v.is_a?(ArrayModel) }.map do |k,v|
40
- if v.is_a?(Model)
41
- v = v.self_attributes
42
- end
43
-
44
- [k,v]
45
- end.to_h
46
- end
47
-
48
-
49
- # Takes the persistor if there is one and
50
- def setup_persistor(persistor)
51
- # Use page as the default persistor
52
- persistor ||= Persistors::Page
53
- if persistor.respond_to?(:new)
54
- @persistor = persistor.new(self)
55
- else
56
- # an already initialized persistor was passed in
57
- @persistor = persistor
58
- end
59
- end
60
-
61
- def store
62
- # TODO: Move away from $page
63
- $page.store
64
- end
65
-
66
- # returns the root model for the collection the model is currently on. So
67
- # if the model is persisted somewhere on store, it will return ```store```
68
- def root
69
- persistor.try(:root_model)
70
- end
71
-
72
-
73
-
74
-
75
- module ClassMethods
76
- # Gets the class for a model at the specified path.
77
- def class_at_path(path)
78
- if path
79
- begin
80
- # remove the _ and then singularize
81
- if path.last == :[]
82
- index = -2
83
- else
84
- index = -1
85
- end
86
-
87
- klass_name = path[index].singularize.camelize
88
-
89
- # Lookup the class
90
- klass = Object.const_get(klass_name)
91
-
92
- # Use it if it is a model
93
- klass = Model unless klass < Model
94
- rescue NameError => e
95
- # Ignore exception, just means the model isn't defined
96
- klass = Model
97
- end
98
- else
99
- klass = Model
100
- end
101
-
102
- klass
103
- end
104
- end
105
-
106
- def self.included(base)
107
- base.send :extend, ClassMethods
108
- end
109
- end
110
- end
@@ -1,11 +0,0 @@
1
- module Volt
2
- module StateHelpers
3
- def loaded_state
4
- state_for(:loaded_state)
5
- end
6
-
7
- def loaded?
8
- loaded_state == :loaded
9
- end
10
- end
11
- end
@@ -1,190 +0,0 @@
1
- require 'volt/utils/ejson'
2
-
3
- module Volt
4
- class Page
5
- attr_reader :url, :params, :page, :routes, :events
6
-
7
- def initialize(volt_app)
8
- @volt_app = volt_app
9
- # Run the code to setup the page
10
- @page = PageRoot.new
11
-
12
- @url = URL.new
13
- @params = @url.params
14
- @url_tracker = UrlTracker.new(self)
15
- @templates = {}
16
-
17
- @events = DocumentEvents.new
18
-
19
- if RUBY_PLATFORM == 'opal'
20
- if Volt.in_browser?
21
- # Setup escape binding for console
22
- `
23
- $(document).keyup(function(e) {
24
- if (e.keyCode == 27) {
25
- Opal.gvars.page.$launch_console();
26
- }
27
- });
28
-
29
- $(document).on('click', 'a', function(event) {
30
- return Opal.gvars.page.$link_clicked($(this).attr('href'), event);
31
- });
32
- `
33
- end
34
- end
35
-
36
- # Initialize tasks so we can get the reload message
37
- tasks if Volt.env.development?
38
-
39
- if Volt.in_browser?
40
- channel.on('reconnected') do
41
- @page._reconnected = true
42
-
43
- `setTimeout(function() {`
44
- @page._reconnected = false
45
- `}, 2000);`
46
- end
47
- end
48
- end
49
-
50
- def flash
51
- @flash ||= FlashRoot.new({}, persistor: Persistors::Flash)
52
- end
53
-
54
- def store
55
- @store ||= StoreRoot.new({}, persistor: Persistors::StoreFactory.new(tasks))
56
- end
57
-
58
- def local_store
59
- @local_store ||= LocalStoreRoot.new({}, persistor: Persistors::LocalStore)
60
- end
61
-
62
- def cookies
63
- @cookies ||= CookiesRoot.new({}, persistor: Persistors::Cookies)
64
- end
65
-
66
- def tasks
67
- @tasks ||= Tasks.new(self)
68
- end
69
-
70
- def link_clicked(url = '', event = nil)
71
- # Skip when href == ''
72
- return false if url.blank?
73
-
74
- # Normalize url
75
- if @url.parse(url)
76
- if event
77
- # Handled new url
78
- `event.stopPropagation();`
79
- end
80
-
81
- # Clear the flash
82
- flash.clear
83
-
84
- # return false to stop the event propigation
85
- return false
86
- end
87
-
88
- # Not stopping, process link normally
89
- true
90
- end
91
-
92
- # We provide a binding_name, so we can bind events on the document
93
- def binding_name
94
- 'page'
95
- end
96
-
97
- def launch_console
98
- puts 'Launch Console'
99
- end
100
-
101
- def channel
102
- @channel ||= begin
103
- if Volt.client?
104
- Channel.new
105
- else
106
- ChannelStub.new
107
- end
108
- end
109
- end
110
-
111
- attr_reader :events
112
-
113
- def add_template(name, template, bindings)
114
- # First template gets priority. The backend will load templates in order so
115
- # that local templates come in before gems (so they can be overridden).
116
- #
117
- # TODO: Currently this means we will send templates to the client that will
118
- # not get used because they are being overridden. Need to detect that and
119
- # not send them.
120
- unless @templates[name]
121
- @templates[name] = { 'html' => template, 'bindings' => bindings }
122
- end
123
- end
124
-
125
- # On the server, we can delay loading the views until they are actually requeted. This
126
- # sets up an instance variable to call to load.
127
- attr_writer :template_loader
128
-
129
- def templates
130
- if @template_loader
131
- # Load the templates
132
- @template_loader.call
133
- @template_loader = nil
134
- end
135
-
136
- @templates
137
- end
138
-
139
- def add_routes(&block)
140
- @routes ||= Routes.new
141
- @routes.define(&block)
142
- @url.router = @routes
143
- end
144
-
145
- def start
146
- # Setup to render template
147
- `$('body').html('<!-- $CONTENT --><!-- $/CONTENT -->');`
148
-
149
- load_stored_page
150
-
151
- # Do the initial url params parse
152
- @url_tracker.url_updated(true)
153
-
154
- main_controller = Main::MainController.new(@volt_app)
155
-
156
- # Setup main page template
157
- TemplateRenderer.new(@volt_app, DomTarget.new, main_controller, 'CONTENT', 'main/main/main/body')
158
-
159
- # Setup title reactive template
160
- @title_template = StringTemplateRenderer.new(@volt_app, main_controller, 'main/main/main/title')
161
-
162
- # Watch for changes to the title template
163
- proc do
164
- title = @title_template.html.gsub(/\n/, ' ')
165
- `document.title = title;`
166
- end.watch!
167
- end
168
-
169
- # When the page is reloaded from the backend, we store the $page.page, so we
170
- # can reload the page in the exact same state. Speeds up development.
171
- def load_stored_page
172
- if Volt.client?
173
- if `sessionStorage`
174
- page_obj_str = nil
175
-
176
- `page_obj_str = sessionStorage.getItem('___page');`
177
- `if (page_obj_str) {`
178
- `sessionStorage.removeItem('___page');`
179
-
180
- EJSON.parse(page_obj_str).each_pair do |key, value|
181
- page.send(:"_#{key}=", value)
182
- end
183
- `}`
184
- end
185
- end
186
- rescue => e
187
- Volt.logger.error("Unable to restore: #{e.inspect}")
188
- end
189
- end
190
- end