volt 0.8.14 → 0.8.15
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/Readme.md +8 -2
- data/VERSION +1 -1
- data/app/volt/controllers/notices_controller.rb +1 -1
- data/app/volt/models/user.rb +2 -2
- data/app/volt/tasks/live_query/live_query_pool.rb +1 -1
- data/app/volt/tasks/query_tasks.rb +1 -1
- data/app/volt/tasks/store_tasks.rb +1 -1
- data/app/volt/tasks/user_tasks.rb +2 -2
- data/lib/volt/boot.rb +2 -2
- data/lib/volt/cli/asset_compile.rb +31 -27
- data/lib/volt/cli.rb +64 -65
- data/lib/volt/config.rb +25 -23
- data/lib/volt/console.rb +17 -16
- data/lib/volt/controllers/model_controller.rb +82 -80
- data/lib/volt/data_stores/data_store.rb +2 -2
- data/lib/volt/data_stores/mongo_driver.rb +2 -2
- data/lib/volt/extra_core/inflections.rb +2 -2
- data/lib/volt/extra_core/inflector/inflections.rb +185 -183
- data/lib/volt/extra_core/inflector/methods.rb +50 -48
- data/lib/volt/extra_core/string.rb +2 -2
- data/lib/volt/models/array_model.rb +93 -92
- data/lib/volt/models/cursor.rb +3 -2
- data/lib/volt/models/model.rb +248 -251
- data/lib/volt/models/model_hash_behaviour.rb +44 -44
- data/lib/volt/models/model_helpers.rb +38 -36
- data/lib/volt/models/model_state.rb +16 -17
- data/lib/volt/models/model_wrapper.rb +25 -24
- data/lib/volt/models/persistors/array_store.rb +145 -143
- data/lib/volt/models/persistors/base.rb +18 -16
- data/lib/volt/models/persistors/flash.rb +24 -22
- data/lib/volt/models/persistors/local_store.rb +46 -44
- data/lib/volt/models/persistors/model_identity_map.rb +10 -8
- data/lib/volt/models/persistors/model_store.rb +76 -76
- data/lib/volt/models/persistors/params.rb +19 -17
- data/lib/volt/models/persistors/query/query_listener.rb +65 -63
- data/lib/volt/models/persistors/query/query_listener_pool.rb +12 -10
- data/lib/volt/models/persistors/store.rb +28 -28
- data/lib/volt/models/persistors/store_factory.rb +12 -10
- data/lib/volt/models/persistors/store_state.rb +33 -31
- data/lib/volt/models/url.rb +96 -104
- data/lib/volt/models/validations.rb +56 -54
- data/lib/volt/models/validators/length_validator.rb +24 -22
- data/lib/volt/models/validators/presence_validator.rb +14 -12
- data/lib/volt/page/bindings/attribute_binding.rb +106 -106
- data/lib/volt/page/bindings/base_binding.rb +23 -21
- data/lib/volt/page/bindings/component_binding.rb +3 -1
- data/lib/volt/page/bindings/content_binding.rb +34 -34
- data/lib/volt/page/bindings/each_binding.rb +113 -113
- data/lib/volt/page/bindings/event_binding.rb +38 -34
- data/lib/volt/page/bindings/if_binding.rb +56 -54
- data/lib/volt/page/bindings/template_binding/grouped_controllers.rb +24 -22
- data/lib/volt/page/bindings/template_binding.rb +182 -185
- data/lib/volt/page/channel.rb +79 -77
- data/lib/volt/page/channel_stub.rb +29 -27
- data/lib/volt/page/document.rb +6 -5
- data/lib/volt/page/document_events.rb +54 -52
- data/lib/volt/page/page.rb +139 -138
- data/lib/volt/page/string_template_renderer.rb +36 -36
- data/lib/volt/page/sub_context.rb +26 -25
- data/lib/volt/page/targets/attribute_section.rb +27 -25
- data/lib/volt/page/targets/attribute_target.rb +7 -6
- data/lib/volt/page/targets/base_section.rb +27 -26
- data/lib/volt/page/targets/binding_document/base_node.rb +3 -1
- data/lib/volt/page/targets/binding_document/component_node.rb +85 -82
- data/lib/volt/page/targets/binding_document/html_node.rb +11 -9
- data/lib/volt/page/targets/dom_section.rb +78 -77
- data/lib/volt/page/targets/dom_target.rb +8 -6
- data/lib/volt/page/targets/dom_template.rb +90 -88
- data/lib/volt/page/targets/helpers/comment_searchers.rb +51 -49
- data/lib/volt/page/tasks.rb +59 -57
- data/lib/volt/page/template_renderer.rb +17 -14
- data/lib/volt/page/url_tracker.rb +26 -24
- data/lib/volt/reactive/computation.rb +87 -88
- data/lib/volt/reactive/dependency.rb +30 -28
- data/lib/volt/reactive/eventable.rb +64 -62
- data/lib/volt/reactive/hash_dependency.rb +25 -23
- data/lib/volt/reactive/reactive_accessors.rb +34 -32
- data/lib/volt/reactive/reactive_array.rb +162 -162
- data/lib/volt/reactive/reactive_hash.rb +37 -35
- data/lib/volt/router/routes.rb +99 -101
- data/lib/volt/server/component_handler.rb +20 -21
- data/lib/volt/server/component_templates.rb +72 -70
- data/lib/volt/server/html_parser/attribute_scope.rb +109 -99
- data/lib/volt/server/html_parser/each_scope.rb +17 -16
- data/lib/volt/server/html_parser/if_view_scope.rb +51 -49
- data/lib/volt/server/html_parser/sandlebars_parser.rb +184 -177
- data/lib/volt/server/html_parser/textarea_scope.rb +24 -22
- data/lib/volt/server/html_parser/view_handler.rb +66 -65
- data/lib/volt/server/html_parser/view_parser.rb +23 -21
- data/lib/volt/server/html_parser/view_scope.rb +142 -141
- data/lib/volt/server/rack/asset_files.rb +81 -79
- data/lib/volt/server/rack/component_code.rb +17 -15
- data/lib/volt/server/rack/component_html_renderer.rb +14 -12
- data/lib/volt/server/rack/component_paths.rb +72 -71
- data/lib/volt/server/rack/index_files.rb +36 -39
- data/lib/volt/server/rack/opal_files.rb +43 -41
- data/lib/volt/server/rack/source_map_server.rb +23 -21
- data/lib/volt/server/socket_connection_handler.rb +46 -45
- data/lib/volt/server/socket_connection_handler_stub.rb +21 -19
- data/lib/volt/server.rb +60 -58
- data/lib/volt/spec/setup.rb +3 -3
- data/lib/volt/tasks/dispatcher.rb +24 -23
- data/lib/volt/tasks/task_handler.rb +35 -33
- data/lib/volt/utils/ejson.rb +8 -6
- data/lib/volt/utils/generic_counting_pool.rb +33 -31
- data/lib/volt/utils/generic_pool.rb +73 -70
- data/lib/volt/utils/local_storage.rb +42 -38
- data/lib/volt/volt/environment.rb +1 -1
- data/lib/volt.rb +44 -42
- data/spec/apps/kitchen_sink/app/main/assets/css/todos.css +28 -0
- data/spec/apps/kitchen_sink/app/main/config/routes.rb +1 -0
- data/spec/apps/kitchen_sink/app/main/controllers/main_controller.rb +2 -2
- data/spec/apps/kitchen_sink/app/main/controllers/todos_controller.rb +17 -0
- data/spec/apps/kitchen_sink/app/main/views/main/main.html +1 -0
- data/spec/apps/kitchen_sink/app/main/views/todos/index.html +24 -0
- data/spec/apps/kitchen_sink/config.ru +1 -1
- data/spec/controllers/reactive_accessors_spec.rb +5 -5
- data/spec/extra_core/inflector_spec.rb +2 -2
- data/spec/integration/list_spec.rb +68 -0
- data/spec/models/model_spec.rb +57 -57
- data/spec/models/persistors/params_spec.rb +6 -6
- data/spec/models/persistors/store_spec.rb +7 -7
- data/spec/models/validations_spec.rb +3 -3
- data/spec/page/bindings/content_binding_spec.rb +7 -7
- data/spec/page/bindings/template_binding_spec.rb +4 -5
- data/spec/page/sub_context_spec.rb +2 -2
- data/spec/reactive/computation_spec.rb +10 -10
- data/spec/reactive/dependency_spec.rb +2 -2
- data/spec/reactive/eventable_spec.rb +4 -4
- data/spec/reactive/reactive_array_spec.rb +13 -13
- data/spec/router/routes_spec.rb +5 -5
- data/spec/server/html_parser/sandlebars_parser_spec.rb +9 -9
- data/spec/server/html_parser/view_parser_spec.rb +27 -27
- data/spec/server/rack/asset_files_spec.rb +5 -5
- data/spec/server/rack/component_paths_spec.rb +2 -2
- data/spec/tasks/live_query_spec.rb +2 -2
- data/spec/tasks/query_tasks.rb +1 -1
- data/spec/tasks/query_tracker_spec.rb +1 -1
- data/spec/templates/targets/binding_document/component_node_spec.rb +2 -2
- data/spec/utils/generic_counting_pool_spec.rb +2 -2
- data/spec/utils/generic_pool_spec.rb +2 -2
- data/templates/component/controllers/main_controller.rb +1 -1
- data/templates/model/model.rb.tt +2 -2
- data/templates/newgem/app/newgem/controllers/main_controller.rb.tt +2 -2
- data/templates/project/app/main/controllers/main_controller.rb +1 -1
- data/templates/project/config.ru +1 -1
- metadata +10 -3
- data/app/volt/assets/js/vertxbus.js +0 -216
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
module
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
module Volt
|
|
2
|
+
module Persistors
|
|
3
|
+
# Implements the base persistor functionality.
|
|
4
|
+
class Base
|
|
5
|
+
def loaded(initial_state=nil)
|
|
6
|
+
end
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
def changed(attribute_name)
|
|
9
|
+
end
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
def added(model, index)
|
|
12
|
+
end
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
# For removed, the default action is to call changed for it
|
|
15
|
+
def removed(attribute_name)
|
|
16
|
+
changed(attribute_name)
|
|
17
|
+
end
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
def event_added(event, first, first_for_event)
|
|
20
|
+
end
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
def event_removed(event, last, last_for_event)
|
|
23
|
+
end
|
|
22
24
|
end
|
|
23
25
|
end
|
|
24
26
|
end
|
|
@@ -1,31 +1,33 @@
|
|
|
1
1
|
require 'volt/models/persistors/base'
|
|
2
2
|
|
|
3
|
-
module
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
module Volt
|
|
4
|
+
module Persistors
|
|
5
|
+
class Flash < Base
|
|
6
|
+
def initialize(model)
|
|
7
|
+
@model = model
|
|
8
|
+
end
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
def added(model, index)
|
|
11
|
+
if Volt.client?
|
|
12
|
+
# Setup a new timer for clearing the flash.
|
|
13
|
+
%x{
|
|
14
|
+
setTimeout(function() {
|
|
15
|
+
self.$clear_model(model);
|
|
16
|
+
}, 5000);
|
|
17
|
+
}
|
|
18
|
+
end
|
|
17
19
|
end
|
|
18
|
-
end
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
def clear_model(model)
|
|
22
|
+
@model.delete(model)
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
# Clear out the parent collection (usually the main flash)
|
|
25
|
+
# Makes it so flash.empty? reflects if there is any outstanding
|
|
26
|
+
# flashes.
|
|
27
|
+
if @model.size == 0
|
|
28
|
+
collection_name = @model.path[-1]
|
|
29
|
+
@model.parent.delete(collection_name)
|
|
30
|
+
end
|
|
29
31
|
end
|
|
30
32
|
end
|
|
31
33
|
end
|
|
@@ -2,64 +2,66 @@ require 'volt/models/persistors/base'
|
|
|
2
2
|
require 'volt/utils/local_storage'
|
|
3
3
|
require 'json'
|
|
4
4
|
|
|
5
|
-
module
|
|
5
|
+
module Volt
|
|
6
|
+
module Persistors
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
# Backs a collection in the local store
|
|
9
|
+
class LocalStore < Base
|
|
10
|
+
def initialize(model)
|
|
11
|
+
@model = model
|
|
12
|
+
end
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
# Find the root for this model
|
|
15
|
+
def root_model
|
|
16
|
+
node = @model
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
loop do
|
|
19
|
+
parent = node.parent
|
|
20
|
+
if parent
|
|
21
|
+
node = parent
|
|
22
|
+
else
|
|
23
|
+
break
|
|
24
|
+
end
|
|
23
25
|
end
|
|
24
|
-
end
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
return node
|
|
28
|
+
end
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
# Called when a model is added to the collection
|
|
31
|
+
def added(model, index)
|
|
32
|
+
root_model.persistor.save_all
|
|
33
|
+
end
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
def loaded(initial_state=nil)
|
|
36
|
+
# When the main model is first loaded, we pull in the data from the
|
|
37
|
+
# store if it exists
|
|
38
|
+
if @model.path == []
|
|
39
|
+
json_data = LocalStorage['volt-store']
|
|
40
|
+
if json_data
|
|
41
|
+
root_attributes = JSON.parse(json_data)
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
@loading_data = true
|
|
44
|
+
root_attributes.each_pair do |key, value|
|
|
45
|
+
@model.send(:"_#{key}=", value)
|
|
46
|
+
end
|
|
47
|
+
@loading_data = nil
|
|
45
48
|
end
|
|
46
|
-
@loading_data = nil
|
|
47
49
|
end
|
|
48
50
|
end
|
|
49
|
-
end
|
|
50
51
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
# Callled when an item is changed (or removed)
|
|
53
|
+
def changed(attribute_name)
|
|
54
|
+
root_model.persistor.save_all
|
|
55
|
+
end
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
# Called on the root
|
|
58
|
+
def save_all
|
|
59
|
+
return if @loading_data
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
json_data = JSON.dump(@model.to_h)
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
LocalStorage['volt-store'] = json_data
|
|
64
|
+
end
|
|
63
65
|
end
|
|
64
66
|
end
|
|
65
|
-
end
|
|
67
|
+
end
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
require 'volt/utils/generic_counting_pool'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
module Volt
|
|
4
|
+
# The identity map ensures that there is only one copy of a model
|
|
5
|
+
# used on the front end at a time.
|
|
6
|
+
class ModelIdentityMap < GenericCountingPool
|
|
7
|
+
# add extends GenericCountingPool so it can add in a model without
|
|
8
|
+
# a direct lookup. We use this when we create a model (without an id)
|
|
9
|
+
# then save it and it gets assigned an id.
|
|
10
|
+
def add(id, model)
|
|
11
|
+
@pool[id] = [1, model]
|
|
12
|
+
end
|
|
11
13
|
end
|
|
12
14
|
end
|
|
@@ -1,121 +1,121 @@
|
|
|
1
1
|
require 'volt/models/persistors/store'
|
|
2
2
|
require 'volt/models/persistors/store_state'
|
|
3
3
|
|
|
4
|
-
module
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
module Volt
|
|
5
|
+
module Persistors
|
|
6
|
+
class ModelStore < Store
|
|
7
|
+
include StoreState
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
ID_CHARS = [('a'..'f'), ('0'..'9')].map { |v| v.to_a }.flatten
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
attr_reader :model
|
|
12
|
+
attr_accessor :in_identity_map
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
def initialize(model, tasks)
|
|
15
|
+
super
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
@in_identity_map = false
|
|
18
|
+
end
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
def add_to_collection
|
|
21
|
+
@in_collection = true
|
|
22
|
+
ensure_setup
|
|
23
|
+
changed
|
|
24
|
+
end
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
def remove_from_collection
|
|
27
|
+
@in_collection = false
|
|
28
|
+
end
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
# Called the first time a value is assigned into this model
|
|
31
|
+
def ensure_setup
|
|
32
|
+
if @model.attributes
|
|
33
|
+
@model.attributes[:_id] ||= generate_id
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
add_to_identity_map
|
|
36
|
+
end
|
|
35
37
|
end
|
|
36
|
-
end
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
def add_to_identity_map
|
|
40
|
+
unless @in_identity_map
|
|
41
|
+
@@identity_map.add(@model._id, @model)
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
@in_identity_map = true
|
|
44
|
+
end
|
|
43
45
|
end
|
|
44
|
-
end
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
# Create a random unique id that can be used as the mongo id as well
|
|
48
|
+
def generate_id
|
|
49
|
+
id = []
|
|
50
|
+
24.times { id << ID_CHARS.sample }
|
|
50
51
|
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
return id.join
|
|
53
|
+
end
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
# Called when the model changes
|
|
56
|
+
def changed(attribute_name=nil)
|
|
57
|
+
path = @model.path
|
|
57
58
|
|
|
58
|
-
|
|
59
|
+
promise = Promise.new
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
ensure_setup
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
path_size = path.size
|
|
64
|
+
if !(defined?($loading_models) && $loading_models) && @tasks && path_size > 0 && !@model.nil?
|
|
65
|
+
if path_size > 3 && (parent = @model.parent) && (source = parent.parent)
|
|
66
|
+
@model.attributes[:"#{path[-4].singularize}_id"] = source._id
|
|
67
|
+
end
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
69
|
+
if !collection
|
|
70
|
+
puts "Attempting to save model directly on store."
|
|
71
|
+
raise "Attempting to save model directly on store."
|
|
72
|
+
else
|
|
73
|
+
StoreTasks.save(collection, self_attributes).then do |errors|
|
|
74
|
+
if errors.size == 0
|
|
75
|
+
promise.resolve(nil)
|
|
76
|
+
else
|
|
77
|
+
promise.reject(errors)
|
|
78
|
+
end
|
|
77
79
|
end
|
|
78
80
|
end
|
|
79
81
|
end
|
|
82
|
+
promise
|
|
80
83
|
end
|
|
81
84
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if first_for_event && event == :changed
|
|
87
|
-
ensure_setup
|
|
85
|
+
def event_added(event, first, first_for_event)
|
|
86
|
+
if first_for_event && event == :changed
|
|
87
|
+
ensure_setup
|
|
88
|
+
end
|
|
88
89
|
end
|
|
89
|
-
end
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
# Update the models based on the id/identity map. Usually these requests
|
|
92
|
+
# will come from the backend.
|
|
93
|
+
def self.changed(model_id, data)
|
|
94
|
+
model = @@identity_map.lookup(model_id)
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
if model
|
|
97
|
+
data.each_pair do |key, value|
|
|
98
|
+
if key != :_id
|
|
99
|
+
model.send(:"_#{key}=", value)
|
|
100
|
+
end
|
|
100
101
|
end
|
|
101
102
|
end
|
|
102
103
|
end
|
|
103
|
-
end
|
|
104
104
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
def [](val)
|
|
106
|
+
raise "Models do not support hash style lookup. Hashes inserted into other models are converted to models, see https://github.com/voltrb/volt#automatic-model-conversion"
|
|
107
|
+
end
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
private
|
|
110
110
|
# Return the attributes that are only for this store, not any sub-associations.
|
|
111
111
|
def self_attributes
|
|
112
112
|
# Don't store any sub-stores, those will do their own saving.
|
|
113
|
-
@model.attributes.reject {|k,v| v.is_a?(Model) || v.is_a?(ArrayModel) }
|
|
113
|
+
@model.attributes.reject { |k, v| v.is_a?(Model) || v.is_a?(ArrayModel) }
|
|
114
114
|
end
|
|
115
115
|
|
|
116
116
|
def collection
|
|
117
117
|
@model.path[-2]
|
|
118
118
|
end
|
|
119
|
-
|
|
119
|
+
end
|
|
120
120
|
end
|
|
121
121
|
end
|
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
require 'volt/models/persistors/base'
|
|
2
2
|
|
|
3
|
-
module
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
module Volt
|
|
4
|
+
module Persistors
|
|
5
|
+
class Params < Base
|
|
6
|
+
def initialize(model)
|
|
7
|
+
@model = model
|
|
8
|
+
end
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
def changed(attribute_name)
|
|
11
|
+
if RUBY_PLATFORM == 'opal'
|
|
12
|
+
%x{
|
|
13
|
+
if (window.setTimeout && this.$run_update.bind) {
|
|
14
|
+
if (window.paramsUpdateTimer) {
|
|
15
|
+
clearTimeout(window.paramsUpdateTimer);
|
|
16
|
+
}
|
|
17
|
+
window.paramsUpdateTimer = setTimeout(this.$run_update.bind(this), 0);
|
|
15
18
|
}
|
|
16
|
-
window.paramsUpdateTimer = setTimeout(this.$run_update.bind(this), 0);
|
|
17
19
|
}
|
|
18
|
-
|
|
20
|
+
end
|
|
19
21
|
end
|
|
20
|
-
end
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
def run_update
|
|
24
|
+
if Volt.client?
|
|
25
|
+
$page.url.update!
|
|
26
|
+
end
|
|
25
27
|
end
|
|
26
28
|
end
|
|
27
29
|
end
|
|
@@ -1,87 +1,89 @@
|
|
|
1
|
-
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
module Volt
|
|
2
|
+
# The query listener is what gets notified on the backend when the results from
|
|
3
|
+
# a query have changed. It then will make the necessary changes to any ArrayStore's
|
|
4
|
+
# to get them to display the new data.
|
|
5
|
+
class QueryListener
|
|
6
|
+
def initialize(query_listener_pool, tasks, collection, query)
|
|
7
|
+
@query_listener_pool = query_listener_pool
|
|
8
|
+
@tasks = tasks
|
|
9
|
+
@stores = []
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
@collection = collection
|
|
12
|
+
@query = query
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
@listening = false
|
|
15
|
+
end
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
def add_listener
|
|
18
|
+
@listening = true
|
|
19
|
+
QueryTasks.add_listener(@collection, @query).then do |ret|
|
|
20
|
+
results, errors = ret
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
# When the initial data comes back, add it into the stores.
|
|
23
|
+
@stores.dup.each do |store|
|
|
24
|
+
# Clear if there are existing items
|
|
25
|
+
store.model.clear if store.model.size > 0
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
results.each do |index, data|
|
|
28
|
+
store.add(index, data)
|
|
29
|
+
end
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
store.change_state_to(:loaded)
|
|
32
|
+
end
|
|
33
|
+
end.fail do |err|
|
|
34
|
+
puts "Err: #{err.inspect}"
|
|
31
35
|
end
|
|
32
|
-
end.fail do |err|
|
|
33
|
-
puts "Err: #{err.inspect}"
|
|
34
36
|
end
|
|
35
|
-
end
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
def add_store(store, &block)
|
|
39
|
+
@stores << store
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
if @listening
|
|
42
|
+
# We are already listening and have this model somewhere else,
|
|
43
|
+
# copy the data from the existing model.
|
|
44
|
+
store.model.clear
|
|
45
|
+
@stores.first.model.each_with_index do |item, index|
|
|
46
|
+
store.add(index, item.to_h)
|
|
47
|
+
end
|
|
48
|
+
else
|
|
49
|
+
# First time we've added a store, setup the listener and get
|
|
50
|
+
# the initial data.
|
|
51
|
+
add_listener
|
|
46
52
|
end
|
|
47
|
-
else
|
|
48
|
-
# First time we've added a store, setup the listener and get
|
|
49
|
-
# the initial data.
|
|
50
|
-
add_listener
|
|
51
53
|
end
|
|
52
|
-
end
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
def remove_store(store)
|
|
56
|
+
@stores.delete(store)
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
# When there are no stores left, remove the query listener from
|
|
59
|
+
# the pool, it can get created again later.
|
|
60
|
+
if @stores.size == 0
|
|
61
|
+
@query_listener_pool.remove(@collection, @query)
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
# Stop listening
|
|
64
|
+
if @listening
|
|
65
|
+
@listening = false
|
|
66
|
+
QueryTasks.remove_listener(@collection, @query)
|
|
67
|
+
end
|
|
66
68
|
end
|
|
67
69
|
end
|
|
68
|
-
end
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
def added(index, data)
|
|
72
|
+
@stores.each do |store|
|
|
73
|
+
store.add(index, data)
|
|
74
|
+
end
|
|
73
75
|
end
|
|
74
|
-
end
|
|
75
76
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
def removed(ids)
|
|
78
|
+
@stores.each do |store|
|
|
79
|
+
store.remove(ids)
|
|
80
|
+
end
|
|
79
81
|
end
|
|
80
|
-
end
|
|
81
82
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
def changed(model_id, data)
|
|
84
|
+
$loading_models = true
|
|
85
|
+
Persistors::ModelStore.changed(model_id, data)
|
|
86
|
+
$loading_models = false
|
|
87
|
+
end
|
|
86
88
|
end
|
|
87
89
|
end
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
require 'volt/utils/generic_pool'
|
|
2
2
|
require 'volt/models/persistors/query/query_listener'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
module Volt
|
|
5
|
+
# Keeps track of all query listeners, so they can be reused in different
|
|
6
|
+
# places. Dynamically generated queries may end up producing the same
|
|
7
|
+
# query in different places. This makes it so we only need to track a
|
|
8
|
+
# single query at once. Data updates will only be sent once as well.
|
|
9
|
+
class QueryListenerPool < GenericPool
|
|
10
|
+
def print
|
|
11
|
+
puts "--- Running Queries ---"
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
@pool.each_pair do |table, query_hash|
|
|
14
|
+
query_hash.keys.each do |query|
|
|
15
|
+
puts "#{table}: #{query.inspect}"
|
|
16
|
+
end
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
19
|
end
|