volt 0.6.5 → 0.7.0
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/Readme.md +47 -40
- data/VERSION +1 -1
- data/app/volt/controllers/notices_controller.rb +3 -3
- data/app/volt/tasks/live_query/data_store.rb +2 -2
- data/app/volt/tasks/live_query/live_query.rb +20 -20
- data/app/volt/tasks/live_query/live_query_pool.rb +6 -6
- data/app/volt/tasks/live_query/query_tracker.rb +15 -15
- data/app/volt/tasks/query_tasks.rb +13 -13
- data/app/volt/tasks/store_tasks.rb +7 -7
- data/app/volt/views/notices/index.html +17 -18
- data/lib/volt/assets/test.rb +2 -2
- data/lib/volt/benchmark/benchmark.rb +25 -23
- data/lib/volt/cli/asset_compile.rb +11 -0
- data/lib/volt/cli/new_gem.rb +16 -16
- data/lib/volt/cli.rb +14 -12
- data/lib/volt/console.rb +5 -6
- data/lib/volt/controllers/model_controller.rb +18 -18
- data/lib/volt/extra_core/array.rb +4 -4
- data/lib/volt/extra_core/hash.rb +3 -3
- data/lib/volt/extra_core/object.rb +6 -6
- data/lib/volt/extra_core/string.rb +6 -6
- data/lib/volt/extra_core/symbol.rb +5 -5
- data/lib/volt/extra_core/time.rb +4 -4
- data/lib/volt/extra_core/true_false.rb +6 -6
- data/lib/volt/extra_core/try.rb +9 -9
- data/lib/volt/models/array_model.rb +26 -26
- data/lib/volt/models/model.rb +35 -35
- data/lib/volt/models/model_hash_behaviour.rb +15 -15
- data/lib/volt/models/model_helpers.rb +8 -8
- data/lib/volt/models/model_wrapper.rb +6 -6
- data/lib/volt/models/persistors/array_store.rb +36 -36
- data/lib/volt/models/persistors/base.rb +6 -6
- data/lib/volt/models/persistors/flash.rb +5 -5
- data/lib/volt/models/persistors/model_identity_map.rb +2 -2
- data/lib/volt/models/persistors/model_store.rb +22 -22
- data/lib/volt/models/persistors/params.rb +3 -3
- data/lib/volt/models/persistors/query/query_listener.rb +14 -14
- data/lib/volt/models/persistors/query/query_listener_pool.rb +2 -2
- data/lib/volt/models/persistors/store.rb +8 -8
- data/lib/volt/models/persistors/store_factory.rb +2 -2
- data/lib/volt/models/url.rb +37 -37
- data/lib/volt/page/bindings/attribute_binding.rb +14 -14
- data/lib/volt/page/bindings/base_binding.rb +9 -9
- data/lib/volt/page/bindings/component_binding.rb +7 -7
- data/lib/volt/page/bindings/content_binding.rb +3 -3
- data/lib/volt/page/bindings/each_binding.rb +13 -13
- data/lib/volt/page/bindings/event_binding.rb +4 -4
- data/lib/volt/page/bindings/if_binding.rb +12 -12
- data/lib/volt/page/bindings/template_binding.rb +30 -30
- data/lib/volt/page/channel.rb +19 -19
- data/lib/volt/page/channel_stub.rb +6 -6
- data/lib/volt/page/document.rb +2 -2
- data/lib/volt/page/document_events.rb +4 -4
- data/lib/volt/page/draw_cycle.rb +3 -3
- data/lib/volt/page/memory_test.rb +6 -6
- data/lib/volt/page/page.rb +19 -19
- data/lib/volt/page/reactive_template.rb +9 -9
- data/lib/volt/page/sub_context.rb +5 -5
- data/lib/volt/page/targets/attribute_section.rb +9 -9
- data/lib/volt/page/targets/attribute_target.rb +3 -3
- data/lib/volt/page/targets/base_section.rb +2 -2
- data/lib/volt/page/targets/binding_document/component_node.rb +23 -23
- data/lib/volt/page/targets/binding_document/html_node.rb +2 -2
- data/lib/volt/page/targets/dom_section.rb +40 -38
- data/lib/volt/page/targets/dom_target.rb +2 -2
- data/lib/volt/page/tasks.rb +12 -12
- data/lib/volt/page/template_renderer.rb +4 -4
- data/lib/volt/page/url_tracker.rb +6 -6
- data/lib/volt/reactive/array_extensions.rb +2 -2
- data/lib/volt/reactive/destructive_methods.rb +5 -5
- data/lib/volt/reactive/event_chain.rb +25 -25
- data/lib/volt/reactive/events.rb +33 -33
- data/lib/volt/reactive/object_tracker.rb +21 -21
- data/lib/volt/reactive/object_tracking.rb +2 -2
- data/lib/volt/reactive/reactive_array.rb +57 -57
- data/lib/volt/reactive/reactive_tags.rb +16 -16
- data/lib/volt/reactive/reactive_value.rb +72 -72
- data/lib/volt/reactive/string_extensions.rb +3 -3
- data/lib/volt/router/routes.rb +22 -23
- data/lib/volt/server/component_handler.rb +5 -5
- data/lib/volt/server/component_templates.rb +14 -11
- data/lib/volt/server/html_parser/attribute_scope.rb +116 -0
- data/lib/volt/server/html_parser/each_scope.rb +18 -0
- data/lib/volt/server/html_parser/if_view_scope.rb +71 -0
- data/lib/volt/server/html_parser/sandlebars_parser.rb +219 -0
- data/lib/volt/server/html_parser/textarea_scope.rb +31 -0
- data/lib/volt/server/html_parser/view_handler.rb +82 -0
- data/lib/volt/server/html_parser/view_parser.rb +23 -0
- data/lib/volt/server/html_parser/view_scope.rb +145 -0
- data/lib/volt/server/rack/asset_files.rb +17 -17
- data/lib/volt/server/rack/component_paths.rb +18 -18
- data/lib/volt/server/rack/index_files.rb +8 -8
- data/lib/volt/server/rack/opal_files.rb +11 -11
- data/lib/volt/server/socket_connection_handler.rb +13 -13
- data/lib/volt/server/socket_connection_handler_stub.rb +2 -2
- data/lib/volt/server.rb +18 -18
- data/lib/volt/tasks/dispatcher.rb +5 -5
- data/lib/volt/utils/ejson.rb +2 -2
- data/lib/volt/utils/generic_counting_pool.rb +8 -8
- data/lib/volt/utils/generic_pool.rb +16 -16
- data/lib/volt/volt/environment.rb +4 -4
- data/lib/volt.rb +6 -6
- data/spec/integration/test_integration_spec.rb +2 -2
- data/spec/models/event_chain_spec.rb +38 -38
- data/spec/models/model_spec.rb +128 -128
- data/spec/models/old_model_spec.rb +17 -17
- data/spec/models/persistors/params_spec.rb +3 -3
- data/spec/models/persistors/store_spec.rb +7 -7
- data/spec/models/reactive_array_spec.rb +82 -82
- data/spec/models/reactive_generator_spec.rb +11 -11
- data/spec/models/reactive_tags_spec.rb +6 -6
- data/spec/models/reactive_value_spec.rb +70 -70
- data/spec/models/store_spec.rb +4 -4
- data/spec/models/string_extensions_spec.rb +13 -13
- data/spec/page/bindings/content_binding_spec.rb +6 -6
- data/spec/page/sub_context_spec.rb +1 -1
- data/spec/router/routes_spec.rb +3 -3
- data/spec/server/html_parser/sample_page.html +595 -0
- data/spec/server/html_parser/sandlebars_parser_spec.rb +192 -0
- data/spec/server/html_parser/view_parser_spec.rb +286 -0
- data/spec/server/rack/asset_files_spec.rb +6 -6
- data/spec/server/rack/component_paths_spec.rb +5 -5
- data/spec/spec_helper.rb +4 -5
- data/spec/store/mongo_spec.rb +3 -3
- data/spec/tasks/live_query_spec.rb +6 -6
- data/spec/tasks/query_tasks.rb +4 -4
- data/spec/tasks/query_tracker_spec.rb +20 -20
- data/spec/templates/targets/binding_document/component_node_spec.rb +4 -4
- data/spec/templates/template_binding_spec.rb +28 -28
- data/spec/utils/generic_counting_pool_spec.rb +5 -5
- data/spec/utils/generic_pool_spec.rb +14 -14
- data/templates/newgem/app/newgem/views/index/index.html +1 -2
- data/templates/project/app/home/config/dependencies.rb +1 -1
- data/templates/project/app/home/controllers/index_controller.rb +1 -1
- data/templates/project/app/home/views/index/about.html +4 -6
- data/templates/project/app/home/views/index/home.html +4 -5
- data/templates/project/app/home/views/index/index.html +8 -9
- data/templates/project/spec/spec_helper.rb +1 -1
- metadata +17 -8
- data/lib/volt/server/binding_setup.rb +0 -2
- data/lib/volt/server/if_binding_setup.rb +0 -31
- data/lib/volt/server/scope.rb +0 -43
- data/lib/volt/server/template_parser.rb +0 -453
- data/spec/server/template_parser_spec.rb +0 -50
|
@@ -3,22 +3,22 @@ module Persistors
|
|
|
3
3
|
class Base
|
|
4
4
|
def loaded
|
|
5
5
|
end
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
def changed(attribute_name)
|
|
8
8
|
end
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
def added(model, index)
|
|
11
11
|
end
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
# For removed, the default action is to call changed for it
|
|
14
14
|
def removed(attribute_name)
|
|
15
15
|
changed(attribute_name)
|
|
16
16
|
end
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
def event_added(event, scope_provider, first)
|
|
19
19
|
end
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
def event_removed(event, no_more_events)
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
|
-
end
|
|
24
|
+
end
|
|
@@ -5,9 +5,9 @@ module Persistors
|
|
|
5
5
|
def initialize(model)
|
|
6
6
|
@model = model
|
|
7
7
|
end
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
def added(model, index)
|
|
10
|
-
if Volt.client?
|
|
10
|
+
if Volt.client?
|
|
11
11
|
# Setup a new timer for clearing the flash.
|
|
12
12
|
%x{
|
|
13
13
|
setTimeout(function() {
|
|
@@ -16,10 +16,10 @@ module Persistors
|
|
|
16
16
|
}
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
def clear_model(model)
|
|
21
21
|
@model.delete(model)
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
# Clear out the parent collection (usually the main flash)
|
|
24
24
|
# Makes it so flash.empty? reflects if there is any outstanding
|
|
25
25
|
# flashes.
|
|
@@ -29,4 +29,4 @@ module Persistors
|
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
|
-
end
|
|
32
|
+
end
|
|
@@ -2,11 +2,11 @@ require 'volt/utils/generic_counting_pool'
|
|
|
2
2
|
|
|
3
3
|
# The identity map ensures that there is only one copy of a model
|
|
4
4
|
# used on the front end at a time.
|
|
5
|
-
class ModelIdentityMap < GenericCountingPool
|
|
5
|
+
class ModelIdentityMap < GenericCountingPool
|
|
6
6
|
# add extends GenericCountingPool so it can add in a model without
|
|
7
7
|
# a direct lookup. We use this when we create a model (without an id)
|
|
8
8
|
# then save it and it gets assigned an id.
|
|
9
9
|
def add(id, model)
|
|
10
10
|
@pool[id] = [1, model]
|
|
11
11
|
end
|
|
12
|
-
end
|
|
12
|
+
end
|
|
@@ -4,26 +4,26 @@ require 'volt/models/persistors/store'
|
|
|
4
4
|
module Persistors
|
|
5
5
|
class ModelStore < Store
|
|
6
6
|
ID_CHARS = [('a'..'z'), ('A'..'Z'), ('0'..'9')].map {|v| v.to_a }.flatten
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
attr_reader :model
|
|
9
9
|
attr_accessor :in_identity_map
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
def initialize(model, tasks)
|
|
12
12
|
super
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
@in_identity_map = false
|
|
15
15
|
end
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
def add_to_collection
|
|
18
18
|
@in_collection = true
|
|
19
19
|
ensure_setup
|
|
20
20
|
changed
|
|
21
21
|
end
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
def remove_from_collection
|
|
24
24
|
@in_collection = false
|
|
25
25
|
end
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
# Called the first time a value is assigned into this model
|
|
28
28
|
def ensure_setup
|
|
29
29
|
if @model.attributes
|
|
@@ -32,34 +32,34 @@ module Persistors
|
|
|
32
32
|
add_to_identity_map
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
def add_to_identity_map
|
|
37
37
|
unless @in_identity_map
|
|
38
38
|
@@identity_map.add(@model._id, @model)
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
@in_identity_map = true
|
|
41
|
-
end
|
|
41
|
+
end
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
# Create a random unique id that can be used as the mongo id as well
|
|
45
45
|
def generate_id
|
|
46
46
|
id = []
|
|
47
47
|
12.times { id << ID_CHARS.sample }
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
return id.join
|
|
50
50
|
end
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
# Called when the model changes
|
|
53
53
|
def changed(attribute_name=nil)
|
|
54
54
|
# puts "CHANGED: #{attribute_name.inspect} - #{@model.inspect}"
|
|
55
55
|
ensure_setup
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
path_size = @model.path.size
|
|
58
|
-
if !(defined?($loading_models) && $loading_models) && @tasks && path_size > 0 && !@model.nil?
|
|
58
|
+
if !(defined?($loading_models) && $loading_models) && @tasks && path_size > 0 && !@model.nil?
|
|
59
59
|
if path_size > 3 && (parent = @model.parent) && source = parent.parent
|
|
60
60
|
@model.attributes[:"#{@model.path[-4].singularize}_id"] = source._id
|
|
61
61
|
end
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
puts "Save: #{collection} - #{self_attributes.inspect} - #{@model.path.inspect}"
|
|
64
64
|
@tasks.call('StoreTasks', 'save', collection, self_attributes)
|
|
65
65
|
end
|
|
@@ -70,12 +70,12 @@ module Persistors
|
|
|
70
70
|
ensure_setup
|
|
71
71
|
end
|
|
72
72
|
end
|
|
73
|
-
|
|
73
|
+
|
|
74
74
|
# Update the models based on the id/identity map. Usually these requests
|
|
75
75
|
# will come from the backend.
|
|
76
76
|
def self.changed(model_id, data)
|
|
77
77
|
model = @@identity_map.lookup(model_id)
|
|
78
|
-
|
|
78
|
+
|
|
79
79
|
if model
|
|
80
80
|
data.each_pair do |key, value|
|
|
81
81
|
if key != '_id'
|
|
@@ -84,21 +84,21 @@ module Persistors
|
|
|
84
84
|
end
|
|
85
85
|
end
|
|
86
86
|
end
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
def [](val)
|
|
89
89
|
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"
|
|
90
90
|
end
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
private
|
|
93
93
|
# Return the attributes that are only for this store, not any sub-associations.
|
|
94
94
|
def self_attributes
|
|
95
95
|
# Don't store any sub-stores, those will do their own saving.
|
|
96
|
-
@model.attributes.reject {|k,v| v.is_a?(Model) || v.is_a?(ArrayModel) }
|
|
96
|
+
@model.attributes.reject {|k,v| v.is_a?(Model) || v.is_a?(ArrayModel) }
|
|
97
97
|
end
|
|
98
|
-
|
|
98
|
+
|
|
99
99
|
def collection
|
|
100
100
|
@model.path[-2]
|
|
101
101
|
end
|
|
102
|
-
|
|
102
|
+
|
|
103
103
|
end
|
|
104
|
-
end
|
|
104
|
+
end
|
|
@@ -5,7 +5,7 @@ module Persistors
|
|
|
5
5
|
def initialize(model)
|
|
6
6
|
@model = model
|
|
7
7
|
end
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
def changed(attribute_name)
|
|
10
10
|
if RUBY_PLATFORM == 'opal'
|
|
11
11
|
%x{
|
|
@@ -18,9 +18,9 @@ module Persistors
|
|
|
18
18
|
}
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
def run_update
|
|
23
23
|
$page.params.trigger!('child_changed') if Volt.client?
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
|
-
end
|
|
26
|
+
end
|
|
@@ -6,13 +6,13 @@ class QueryListener
|
|
|
6
6
|
@query_listener_pool = query_listener_pool
|
|
7
7
|
@tasks = tasks
|
|
8
8
|
@stores = []
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
@collection = collection
|
|
11
11
|
@query = query
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
@listening = false
|
|
14
14
|
end
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
def add_listener
|
|
17
17
|
@listening = true
|
|
18
18
|
@tasks.call('QueryTasks', 'add_listener', @collection, @query) do |results|
|
|
@@ -22,15 +22,15 @@ class QueryListener
|
|
|
22
22
|
results.each do |index, data|
|
|
23
23
|
store.add(index, data)
|
|
24
24
|
end
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
store.change_state_to(:loaded)
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
def add_store(store, &block)
|
|
32
32
|
@stores << store
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
if @listening
|
|
35
35
|
# We are already listening and have this model somewhere else,
|
|
36
36
|
# copy the data from the existing model.
|
|
@@ -44,40 +44,40 @@ class QueryListener
|
|
|
44
44
|
add_listener
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
def remove_store(store)
|
|
49
49
|
@stores.delete(store)
|
|
50
|
-
|
|
50
|
+
|
|
51
51
|
# When there are no stores left, remove the query listener from
|
|
52
52
|
# the pool, it can get created again later.
|
|
53
53
|
if @stores.size == 0
|
|
54
54
|
@query_listener_pool.remove(@collection, @query)
|
|
55
|
-
|
|
55
|
+
|
|
56
56
|
# Stop listening
|
|
57
57
|
if @listening
|
|
58
58
|
@listening = false
|
|
59
|
-
@tasks.call('QueryTasks', 'remove_listener', @collection, @query)
|
|
59
|
+
@tasks.call('QueryTasks', 'remove_listener', @collection, @query)
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
62
|
end
|
|
63
|
-
|
|
63
|
+
|
|
64
64
|
def added(index, data)
|
|
65
65
|
@stores.each do |store|
|
|
66
66
|
store.add(index, data)
|
|
67
67
|
end
|
|
68
68
|
puts "Added: #{index} - #{data.inspect}"
|
|
69
69
|
end
|
|
70
|
-
|
|
70
|
+
|
|
71
71
|
def removed(ids)
|
|
72
72
|
@stores.each do |store|
|
|
73
73
|
store.remove(ids)
|
|
74
74
|
end
|
|
75
75
|
end
|
|
76
|
-
|
|
76
|
+
|
|
77
77
|
def changed(model_id, data)
|
|
78
78
|
$loading_models = true
|
|
79
79
|
puts "From Backend: UPDATE: #{model_id} with #{data.inspect}"
|
|
80
80
|
Persistors::ModelStore.changed(model_id, data)
|
|
81
81
|
$loading_models = false
|
|
82
82
|
end
|
|
83
|
-
end
|
|
83
|
+
end
|
|
@@ -5,5 +5,5 @@ require 'volt/models/persistors/query/query_listener'
|
|
|
5
5
|
# places. Dynamically generated queries may end up producing the same
|
|
6
6
|
# query in different places. This makes it so we only need to track a
|
|
7
7
|
# single query at once. Data updates will only be sent once as well.
|
|
8
|
-
class QueryListenerPool < GenericPool
|
|
9
|
-
end
|
|
8
|
+
class QueryListenerPool < GenericPool
|
|
9
|
+
end
|
|
@@ -3,16 +3,16 @@ require 'volt/models/persistors/model_identity_map'
|
|
|
3
3
|
|
|
4
4
|
module Persistors
|
|
5
5
|
class Store < Base
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
@@identity_map = ModelIdentityMap.new
|
|
8
|
-
|
|
9
|
-
def initialize(model, tasks=nil)
|
|
8
|
+
|
|
9
|
+
def initialize(model, tasks=nil)
|
|
10
10
|
@tasks = tasks
|
|
11
11
|
@model = model
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
@saved = false
|
|
14
14
|
end
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
def saved?
|
|
17
17
|
@saved
|
|
18
18
|
end
|
|
@@ -28,15 +28,15 @@ module Persistors
|
|
|
28
28
|
else
|
|
29
29
|
model = @model.new_model(nil, options)
|
|
30
30
|
end
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
@model.attributes ||= {}
|
|
33
33
|
@model.attributes[method_name] = model
|
|
34
34
|
|
|
35
35
|
# if model.is_a?(StoreArray)# && model.state == :not_loaded
|
|
36
36
|
# model.load!
|
|
37
37
|
# end
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
return model
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
|
-
end
|
|
42
|
+
end
|
data/lib/volt/models/url.rb
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# The url class handles parsing and updating the url
|
|
2
2
|
class URL
|
|
3
3
|
include ReactiveTags
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
# TODO: we need to make it so change events only trigger on changes
|
|
6
6
|
attr_reader :scheme, :host, :port, :path, :query, :params
|
|
7
7
|
attr_accessor :router
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
def initialize(router=nil)
|
|
10
10
|
@router = router
|
|
11
11
|
@params = Model.new({}, persistor: Persistors::Params)
|
|
12
12
|
end
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
# Parse takes in a url and extracts each sections.
|
|
15
15
|
# It also assigns and changes to the params.
|
|
16
16
|
tag_method(:parse) do
|
|
@@ -34,21 +34,21 @@ class URL
|
|
|
34
34
|
return false
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
matcher = url.match(/^(https?)[:]\/\/([^\/]+)(.*)$/)
|
|
39
39
|
@scheme = matcher[1]
|
|
40
40
|
@host, @port = matcher[2].split(':')
|
|
41
41
|
@port ||= 80
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
@path = matcher[3]
|
|
44
44
|
@path, @fragment = @path.split('#', 2)
|
|
45
45
|
@path, @query = @path.split('?', 2)
|
|
46
46
|
|
|
47
47
|
assign_query_hash_to_params
|
|
48
48
|
end
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
scroll
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
return true
|
|
53
53
|
end
|
|
54
54
|
|
|
@@ -59,11 +59,11 @@ class URL
|
|
|
59
59
|
else
|
|
60
60
|
host_with_port = @host
|
|
61
61
|
end
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
path, params = @router.url_for_params(@params)
|
|
64
64
|
|
|
65
65
|
new_url = "#{@scheme}://#{host_with_port}#{(path || @path).chomp('/')}"
|
|
66
|
-
|
|
66
|
+
|
|
67
67
|
unless params.empty?
|
|
68
68
|
new_url += '?'
|
|
69
69
|
query_parts = []
|
|
@@ -73,28 +73,28 @@ class URL
|
|
|
73
73
|
value = `encodeURI(value)`
|
|
74
74
|
query_parts << "#{key}=#{value}"
|
|
75
75
|
end
|
|
76
|
-
|
|
76
|
+
|
|
77
77
|
new_url += query_parts.join('&')
|
|
78
78
|
end
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
new_url += '#' + @fragment if @fragment
|
|
81
|
-
|
|
81
|
+
|
|
82
82
|
return new_url
|
|
83
83
|
end
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
# Called when the state has changed and the url in the
|
|
86
86
|
# browser should be updated
|
|
87
87
|
# Called when an attribute changes to update the url
|
|
88
88
|
def update!
|
|
89
89
|
if Volt.client?
|
|
90
90
|
new_url = full_url()
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
if `(document.location.href != new_url)`
|
|
93
93
|
`history.pushState(null, null, new_url)`
|
|
94
94
|
end
|
|
95
95
|
end
|
|
96
96
|
end
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
def scroll
|
|
99
99
|
if Volt.client?
|
|
100
100
|
if @fragment
|
|
@@ -115,35 +115,35 @@ class URL
|
|
|
115
115
|
end
|
|
116
116
|
end
|
|
117
117
|
end
|
|
118
|
-
|
|
118
|
+
|
|
119
119
|
private
|
|
120
120
|
# Assigning the params is tricky since we don't want to trigger changed on
|
|
121
121
|
# any values that have not changed. So we first loop through all current
|
|
122
122
|
# url params, removing any not present in the params, while also removing
|
|
123
|
-
# them from the list of new params as added. Then we loop through the
|
|
123
|
+
# them from the list of new params as added. Then we loop through the
|
|
124
124
|
# remaining new parameters and assign them.
|
|
125
125
|
def assign_query_hash_to_params
|
|
126
126
|
# Get a nested hash representing the current url params.
|
|
127
127
|
query_hash = self.query_hash
|
|
128
|
-
|
|
128
|
+
|
|
129
129
|
# Get the params that are in the route
|
|
130
130
|
query_hash.merge!(@router.params_for_path(@path))
|
|
131
|
-
|
|
131
|
+
|
|
132
132
|
# Loop through the .params we already have assigned.
|
|
133
133
|
assign_from_old(@params, query_hash)
|
|
134
134
|
assign_new(@params, query_hash)
|
|
135
135
|
end
|
|
136
|
-
|
|
136
|
+
|
|
137
137
|
# Loop through the old params, and overwrite any existing values,
|
|
138
138
|
# and delete the values that don't exist in the new params. Also
|
|
139
139
|
# remove any assigned to the new params (query_hash)
|
|
140
140
|
def assign_from_old(params, new_params)
|
|
141
141
|
queued_deletes = []
|
|
142
|
-
|
|
142
|
+
|
|
143
143
|
params.cur.attributes.each_pair do |name,old_val|
|
|
144
144
|
# If there is a new value, see if it has [name]
|
|
145
145
|
new_val = new_params ? new_params[name] : nil
|
|
146
|
-
|
|
146
|
+
|
|
147
147
|
if !new_val
|
|
148
148
|
# Queues the delete until after we finish the each_pair loop
|
|
149
149
|
queued_deletes << name
|
|
@@ -157,10 +157,10 @@ class URL
|
|
|
157
157
|
new_params.delete(name)
|
|
158
158
|
end
|
|
159
159
|
end
|
|
160
|
-
|
|
160
|
+
|
|
161
161
|
queued_deletes.each {|name| params.delete(name) }
|
|
162
162
|
end
|
|
163
|
-
|
|
163
|
+
|
|
164
164
|
# Assign any new params, which weren't in the old params.
|
|
165
165
|
def assign_new(params, new_params)
|
|
166
166
|
new_params.each_pair do |name, value|
|
|
@@ -172,19 +172,19 @@ class URL
|
|
|
172
172
|
end
|
|
173
173
|
end
|
|
174
174
|
end
|
|
175
|
-
|
|
175
|
+
|
|
176
176
|
def query_hash
|
|
177
177
|
query_hash = {}
|
|
178
178
|
if @query
|
|
179
179
|
@query.split('&').reject {|v| v == '' }.each do |part|
|
|
180
180
|
parts = part.split('=').reject {|v| v == '' }
|
|
181
|
-
|
|
181
|
+
|
|
182
182
|
# Decode string
|
|
183
183
|
# parts[0] = `decodeURI(parts[0])`
|
|
184
184
|
parts[1] = `decodeURI(parts[1])`
|
|
185
|
-
|
|
185
|
+
|
|
186
186
|
sections = query_key_sections(parts[0])
|
|
187
|
-
|
|
187
|
+
|
|
188
188
|
hash_part = query_hash
|
|
189
189
|
sections.each_with_index do |section,index|
|
|
190
190
|
if index == sections.size-1
|
|
@@ -196,18 +196,18 @@ class URL
|
|
|
196
196
|
end
|
|
197
197
|
end
|
|
198
198
|
end
|
|
199
|
-
|
|
199
|
+
|
|
200
200
|
return query_hash
|
|
201
201
|
end
|
|
202
|
-
|
|
203
|
-
# Splits a key from a ?key=value&... parameter into its nested
|
|
202
|
+
|
|
203
|
+
# Splits a key from a ?key=value&... parameter into its nested
|
|
204
204
|
# parts. It also adds back the _'s used to access them in params.
|
|
205
205
|
# Example:
|
|
206
206
|
# user[name]=Ryan would parse as [:_user, :_name]
|
|
207
207
|
def query_key_sections(key)
|
|
208
208
|
key.split(/\[([^\]]+)\]/).reject(&:empty?).map {|v| :"_#{v}"}
|
|
209
209
|
end
|
|
210
|
-
|
|
210
|
+
|
|
211
211
|
# Generate the key for a nested param attribute
|
|
212
212
|
def query_key(path)
|
|
213
213
|
i = 0
|
|
@@ -221,10 +221,10 @@ class URL
|
|
|
221
221
|
end
|
|
222
222
|
end.join('')
|
|
223
223
|
end
|
|
224
|
-
|
|
224
|
+
|
|
225
225
|
def nested_params_hash(params, path=[])
|
|
226
226
|
results = {}
|
|
227
|
-
|
|
227
|
+
|
|
228
228
|
params.each_pair do |key,value|
|
|
229
229
|
if value.respond_to?(:persistor) && value.persistor && value.persistor.is_a?(Persistors::Params)
|
|
230
230
|
# TODO: Should be a param
|
|
@@ -233,8 +233,8 @@ class URL
|
|
|
233
233
|
results[query_key(path + [key])] = value
|
|
234
234
|
end
|
|
235
235
|
end
|
|
236
|
-
|
|
236
|
+
|
|
237
237
|
return results
|
|
238
238
|
end
|
|
239
|
-
|
|
240
|
-
end
|
|
239
|
+
|
|
240
|
+
end
|
|
@@ -8,12 +8,12 @@ class AttributeBinding < BaseBinding
|
|
|
8
8
|
|
|
9
9
|
@attribute_name = attribute_name
|
|
10
10
|
@getter = getter
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
setup
|
|
13
13
|
end
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
def setup
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
# Find the source for the content binding
|
|
18
18
|
@value = value_from_getter(@getter)
|
|
19
19
|
|
|
@@ -47,7 +47,7 @@ class AttributeBinding < BaseBinding
|
|
|
47
47
|
Element.find('#' + binding_name)
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
def update
|
|
50
|
+
def update
|
|
51
51
|
if @attribute_target
|
|
52
52
|
value = @attribute_target.to_html
|
|
53
53
|
else
|
|
@@ -58,14 +58,14 @@ class AttributeBinding < BaseBinding
|
|
|
58
58
|
update_checked
|
|
59
59
|
return
|
|
60
60
|
end
|
|
61
|
-
|
|
61
|
+
|
|
62
62
|
if value.is_a?(NilMethodCall) || value.nil?
|
|
63
63
|
value = ''
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
self.value = value
|
|
67
67
|
end
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
def value=(val)
|
|
70
70
|
case @attribute_name
|
|
71
71
|
when 'value'
|
|
@@ -78,18 +78,18 @@ class AttributeBinding < BaseBinding
|
|
|
78
78
|
element[@attribute_name] = val
|
|
79
79
|
end
|
|
80
80
|
end
|
|
81
|
-
|
|
81
|
+
|
|
82
82
|
def update_checked
|
|
83
83
|
value = @value.cur
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
if value.is_a?(NilMethodCall) || value.nil?
|
|
86
86
|
value = false
|
|
87
87
|
end
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
element.prop('checked', value)
|
|
90
|
-
|
|
90
|
+
|
|
91
91
|
end
|
|
92
|
-
|
|
92
|
+
|
|
93
93
|
def remove
|
|
94
94
|
# Unbind events, leave the element there since attribute bindings
|
|
95
95
|
# aren't responsible for it being there.
|
|
@@ -99,12 +99,12 @@ class AttributeBinding < BaseBinding
|
|
|
99
99
|
when 'checked'
|
|
100
100
|
element.off('change.attrbind', nil)
|
|
101
101
|
end
|
|
102
|
-
|
|
102
|
+
|
|
103
103
|
if @update_listener
|
|
104
104
|
@update_listener.remove
|
|
105
105
|
@update_listener = nil
|
|
106
106
|
end
|
|
107
|
-
|
|
107
|
+
|
|
108
108
|
# Clear any references
|
|
109
109
|
@target = nil
|
|
110
110
|
@context = nil
|
|
@@ -112,4 +112,4 @@ class AttributeBinding < BaseBinding
|
|
|
112
112
|
end
|
|
113
113
|
|
|
114
114
|
|
|
115
|
-
end
|
|
115
|
+
end
|