volt 0.2.3
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 +7 -0
- data/.gitignore +21 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +37 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +22 -0
- data/Rakefile +23 -0
- data/Readme.md +34 -0
- data/VERSION +1 -0
- data/bin/volt +4 -0
- data/docs/GETTING_STARTED.md +7 -0
- data/docs/GUIDE.md +33 -0
- data/lib/volt.rb +15 -0
- data/lib/volt/benchmark/benchmark.rb +25 -0
- data/lib/volt/cli.rb +34 -0
- data/lib/volt/console.rb +19 -0
- data/lib/volt/controllers/model_controller.rb +29 -0
- data/lib/volt/extra_core/array.rb +10 -0
- data/lib/volt/extra_core/blank.rb +88 -0
- data/lib/volt/extra_core/extra_core.rb +7 -0
- data/lib/volt/extra_core/numeric.rb +9 -0
- data/lib/volt/extra_core/object.rb +36 -0
- data/lib/volt/extra_core/string.rb +29 -0
- data/lib/volt/extra_core/stringify_keys.rb +7 -0
- data/lib/volt/extra_core/true_false.rb +44 -0
- data/lib/volt/extra_core/try.rb +31 -0
- data/lib/volt/models.rb +5 -0
- data/lib/volt/models/array_model.rb +37 -0
- data/lib/volt/models/model.rb +210 -0
- data/lib/volt/models/model_wrapper.rb +23 -0
- data/lib/volt/models/params.rb +67 -0
- data/lib/volt/models/url.rb +192 -0
- data/lib/volt/page/url_tracker.rb +36 -0
- data/lib/volt/reactive/array_extensions.rb +13 -0
- data/lib/volt/reactive/event_chain.rb +126 -0
- data/lib/volt/reactive/events.rb +283 -0
- data/lib/volt/reactive/object_tracker.rb +99 -0
- data/lib/volt/reactive/object_tracking.rb +15 -0
- data/lib/volt/reactive/reactive_array.rb +222 -0
- data/lib/volt/reactive/reactive_tags.rb +64 -0
- data/lib/volt/reactive/reactive_value.rb +368 -0
- data/lib/volt/reactive/string_extensions.rb +34 -0
- data/lib/volt/router/routes.rb +83 -0
- data/lib/volt/server.rb +121 -0
- data/lib/volt/server/binding_setup.rb +2 -0
- data/lib/volt/server/channel_handler.rb +31 -0
- data/lib/volt/server/component_handler.rb +88 -0
- data/lib/volt/server/if_binding_setup.rb +29 -0
- data/lib/volt/server/request_handler.rb +16 -0
- data/lib/volt/server/scope.rb +43 -0
- data/lib/volt/server/source_map_server.rb +31 -0
- data/lib/volt/server/template_parser.rb +452 -0
- data/lib/volt/store/mongo.rb +5 -0
- data/lib/volt/templates/attribute_binding.rb +110 -0
- data/lib/volt/templates/base_binding.rb +37 -0
- data/lib/volt/templates/channel.rb +48 -0
- data/lib/volt/templates/content_binding.rb +35 -0
- data/lib/volt/templates/document_events.rb +80 -0
- data/lib/volt/templates/each_binding.rb +115 -0
- data/lib/volt/templates/event_binding.rb +51 -0
- data/lib/volt/templates/if_binding.rb +74 -0
- data/lib/volt/templates/memory_test.rb +26 -0
- data/lib/volt/templates/page.rb +146 -0
- data/lib/volt/templates/reactive_template.rb +38 -0
- data/lib/volt/templates/render_queue.rb +5 -0
- data/lib/volt/templates/sub_context.rb +23 -0
- data/lib/volt/templates/targets/attribute_section.rb +33 -0
- data/lib/volt/templates/targets/attribute_target.rb +18 -0
- data/lib/volt/templates/targets/base_section.rb +14 -0
- data/lib/volt/templates/targets/binding_document/base_node.rb +3 -0
- data/lib/volt/templates/targets/binding_document/component_node.rb +112 -0
- data/lib/volt/templates/targets/binding_document/html_node.rb +11 -0
- data/lib/volt/templates/targets/dom_section.rb +147 -0
- data/lib/volt/templates/targets/dom_target.rb +11 -0
- data/lib/volt/templates/template_binding.rb +159 -0
- data/lib/volt/templates/template_renderer.rb +50 -0
- data/spec/models/event_chain_spec.rb +129 -0
- data/spec/models/model_spec.rb +340 -0
- data/spec/models/old_model_spec.rb +109 -0
- data/spec/models/reactive_array_spec.rb +262 -0
- data/spec/models/reactive_tags_spec.rb +35 -0
- data/spec/models/reactive_value_spec.rb +336 -0
- data/spec/models/string_extensions_spec.rb +57 -0
- data/spec/router/routes_spec.rb +24 -0
- data/spec/server/template_parser_spec.rb +50 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/store/mongo_spec.rb +4 -0
- data/spec/templates/targets/binding_document/component_node_spec.rb +18 -0
- data/spec/templates/template_binding_spec.rb +98 -0
- data/templates/.gitignore +12 -0
- data/templates/Gemfile.tt +8 -0
- data/templates/app/.empty_directory +0 -0
- data/templates/app/home/config/routes.rb +1 -0
- data/templates/app/home/controllers/index_controller.rb +5 -0
- data/templates/app/home/css/.empty_directory +0 -0
- data/templates/app/home/models/.empty_directory +0 -0
- data/templates/app/home/views/index/about.html +9 -0
- data/templates/app/home/views/index/home.html +7 -0
- data/templates/app/home/views/index/index.html +28 -0
- data/templates/config.ru +4 -0
- data/templates/public/css/ansi.css +0 -0
- data/templates/public/css/bootstrap-theme.css +459 -0
- data/templates/public/css/bootstrap.css +7098 -0
- data/templates/public/css/jumbotron.css +79 -0
- data/templates/public/fonts/glyphicons-halflings-regular.eot +0 -0
- data/templates/public/fonts/glyphicons-halflings-regular.svg +229 -0
- data/templates/public/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/templates/public/fonts/glyphicons-halflings-regular.woff +0 -0
- data/templates/public/index.html +25 -0
- data/templates/public/js/bootstrap.js +0 -0
- data/templates/public/js/jquery-2.0.3.js +8829 -0
- data/templates/public/js/sockjs-0.2.1.min.js +27 -0
- data/templates/spec/spec_helper.rb +20 -0
- data/volt.gemspec +41 -0
- metadata +412 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
require 'volt/templates/base_binding'
|
|
2
|
+
require 'volt/templates/targets/attribute_target'
|
|
3
|
+
|
|
4
|
+
class AttributeBinding < BaseBinding
|
|
5
|
+
def initialize(target, context, binding_name, attribute_name, getter)
|
|
6
|
+
# puts "New Attribute Binding: #{binding_name}, #{attribute_name}, #{getter}"
|
|
7
|
+
super(target, context, binding_name)
|
|
8
|
+
|
|
9
|
+
@attribute_name = attribute_name
|
|
10
|
+
@getter = getter
|
|
11
|
+
|
|
12
|
+
setup
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def setup
|
|
16
|
+
|
|
17
|
+
# Find the source for the content binding
|
|
18
|
+
@value = value_from_getter(@getter)
|
|
19
|
+
|
|
20
|
+
# Run the initial update (render)
|
|
21
|
+
update
|
|
22
|
+
|
|
23
|
+
@update_listener = @value.on('changed') { update }
|
|
24
|
+
|
|
25
|
+
# Bind so when this value updates, we update
|
|
26
|
+
case @attribute_name
|
|
27
|
+
when 'value'
|
|
28
|
+
element.on('input.attrbind') { changed }
|
|
29
|
+
when 'checked'
|
|
30
|
+
element.on('change.attrbind') {|event| changed(event) }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def changed(event=nil)
|
|
35
|
+
case @attribute_name
|
|
36
|
+
when 'value'
|
|
37
|
+
current_value = element.value
|
|
38
|
+
# puts "NEW VAL: #{current_value} : #{@value.inspect}"
|
|
39
|
+
else
|
|
40
|
+
current_value = element.is(':checked')
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
@value.cur = current_value
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def element
|
|
47
|
+
Element.find('#' + binding_name)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def update
|
|
51
|
+
if @attribute_target
|
|
52
|
+
value = @attribute_target.to_html
|
|
53
|
+
else
|
|
54
|
+
value = @value.cur
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
if @attribute_name == 'checked'
|
|
58
|
+
update_checked
|
|
59
|
+
return
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
if value.is_a?(NilMethodCall) || value.nil?
|
|
63
|
+
value = ''
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
self.value = value
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def value=(val)
|
|
70
|
+
case @attribute_name
|
|
71
|
+
when 'value'
|
|
72
|
+
element.value = val
|
|
73
|
+
else
|
|
74
|
+
element[@attribute_name] = val
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def update_checked
|
|
79
|
+
value = @value.cur
|
|
80
|
+
|
|
81
|
+
if value.is_a?(NilMethodCall) || value.nil?
|
|
82
|
+
value = false
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
if value
|
|
86
|
+
element['checked'] = 'checked'
|
|
87
|
+
else
|
|
88
|
+
element.remove_attr('checked')
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def remove
|
|
94
|
+
# Unbind events, leave the element there since attribute bindings
|
|
95
|
+
# aren't responsible for it being there.
|
|
96
|
+
case @attribute_name
|
|
97
|
+
when 'value'
|
|
98
|
+
element.off('input.attrbind')
|
|
99
|
+
when 'checked'
|
|
100
|
+
element.off('change.attrbind')
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
if @update_listener
|
|
104
|
+
@update_listener.remove
|
|
105
|
+
@update_listener = nil
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
class BaseBinding
|
|
2
|
+
attr_accessor :target, :context, :binding_name
|
|
3
|
+
|
|
4
|
+
def initialize(target, context, binding_name)
|
|
5
|
+
@target = target
|
|
6
|
+
@context = context
|
|
7
|
+
@binding_name = binding_name
|
|
8
|
+
|
|
9
|
+
@@binding_number ||= 10000
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def section
|
|
13
|
+
@section ||= target.section(@binding_name)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def remove
|
|
17
|
+
section.remove
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def remove_anchors
|
|
21
|
+
section.remove_anchors
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def queue_update
|
|
25
|
+
if Volt.server?
|
|
26
|
+
# Run right away
|
|
27
|
+
update
|
|
28
|
+
else
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def value_from_getter(getter)
|
|
34
|
+
# Evaluate the getter proc in the context
|
|
35
|
+
return @context.instance_eval(&getter)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# The channel is the connection between the front end and the backend.
|
|
2
|
+
|
|
3
|
+
require 'volt/reactive/events'
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
class Channel
|
|
7
|
+
include Events
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@socket = nil
|
|
11
|
+
%x{
|
|
12
|
+
this.socket = new SockJS('http://localhost:3000/channel');//, {reconnect: true});
|
|
13
|
+
|
|
14
|
+
this.socket.onopen = function() {
|
|
15
|
+
console.log('open');
|
|
16
|
+
self['$trigger!']("open");
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
this.socket.onmessage = function(message) {
|
|
20
|
+
console.log('received: ', message);
|
|
21
|
+
self['$message_received'](message.data);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def message_received(message)
|
|
27
|
+
message = JSON.parse(message)
|
|
28
|
+
puts "Got #{message.inspect}"
|
|
29
|
+
|
|
30
|
+
trigger!('message', message)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def send(message)
|
|
34
|
+
# TODO: Temp: wrap message in an array, so we're sure its valid JSON
|
|
35
|
+
message = JSON.dump([message])
|
|
36
|
+
%x{
|
|
37
|
+
//message = window.JSON.parse(message);
|
|
38
|
+
console.log('send: ', message);
|
|
39
|
+
this.socket.send(message);
|
|
40
|
+
}
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def close
|
|
44
|
+
%x{
|
|
45
|
+
this.socket.close();
|
|
46
|
+
}
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'volt/templates/base_binding'
|
|
2
|
+
|
|
3
|
+
class ContentBinding < BaseBinding
|
|
4
|
+
def initialize(target, context, binding_name, getter)
|
|
5
|
+
# puts "new content binding: #{getter}"
|
|
6
|
+
super(target, context, binding_name)
|
|
7
|
+
|
|
8
|
+
# Find the source for the content binding
|
|
9
|
+
@value = value_from_getter(getter)
|
|
10
|
+
|
|
11
|
+
# Run the initial render
|
|
12
|
+
update
|
|
13
|
+
|
|
14
|
+
@changed_listener = @value.on('changed') { update }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def update
|
|
18
|
+
value = @value.cur.or('')
|
|
19
|
+
|
|
20
|
+
# Exception values display the exception as a string
|
|
21
|
+
value = value.to_s
|
|
22
|
+
|
|
23
|
+
# Update the text in this section
|
|
24
|
+
section.text = value
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def remove
|
|
28
|
+
@changed_listener.remove
|
|
29
|
+
@changed_listener = nil
|
|
30
|
+
|
|
31
|
+
super
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
class DocumentEvents
|
|
2
|
+
def initialize
|
|
3
|
+
@events = {}
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def add(event, binding, handler)
|
|
7
|
+
# Track each document event based on the event, element id, then binding.object_id
|
|
8
|
+
unless @events[event]
|
|
9
|
+
# We haven't defined an event of type event yet, lets attach it to the
|
|
10
|
+
# document.
|
|
11
|
+
|
|
12
|
+
@events[event] = {}
|
|
13
|
+
|
|
14
|
+
that = self
|
|
15
|
+
|
|
16
|
+
%x{
|
|
17
|
+
$('body').on(event, function(e) {
|
|
18
|
+
that.$handle(event, e, e.originalEvent.target);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# puts "Register: #{event} - #{binding.binding_name} - #{binding.object_id}"
|
|
25
|
+
|
|
26
|
+
@events[event][binding.binding_name] ||= {}
|
|
27
|
+
@events[event][binding.binding_name][binding.object_id] = handler
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def handle(event_name, event, target)
|
|
31
|
+
# puts "Handle: #{event_name} on #{target}"
|
|
32
|
+
element = Element.find(target)
|
|
33
|
+
|
|
34
|
+
loop do
|
|
35
|
+
# Lookup the handler, make sure to not assume the group
|
|
36
|
+
# exists.
|
|
37
|
+
# TODO: Sometimes the event doesn't exist, but we still get
|
|
38
|
+
# an event.
|
|
39
|
+
handlers = @events[event_name]
|
|
40
|
+
handlers = handlers[element.id] if handlers
|
|
41
|
+
|
|
42
|
+
if handlers
|
|
43
|
+
handlers.values.each do |handler|
|
|
44
|
+
# Call each handler for this object
|
|
45
|
+
handler.call(event)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
if element.size == 0
|
|
50
|
+
break
|
|
51
|
+
else
|
|
52
|
+
element = element.parent
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
nil
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def remove(event, binding)
|
|
60
|
+
# Remove the event binding
|
|
61
|
+
@events[event][binding.binding_name].delete(binding.object_id)
|
|
62
|
+
|
|
63
|
+
# if there are no more handlers for this binding_name (the html id), then
|
|
64
|
+
# we remove the binding name hash
|
|
65
|
+
if @events[event][binding.binding_name].size == 0
|
|
66
|
+
@events[event].delete(binding.binding_name)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# if there are no more handlers in this event, we can unregister the event
|
|
70
|
+
# from the document
|
|
71
|
+
if @events[event].size == 0
|
|
72
|
+
@events.delete(event)
|
|
73
|
+
|
|
74
|
+
# Remove the event from the body
|
|
75
|
+
%x{
|
|
76
|
+
$('body').unbind(event);
|
|
77
|
+
}
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
require 'volt/templates/base_binding'
|
|
2
|
+
|
|
3
|
+
class EachBinding < BaseBinding
|
|
4
|
+
def initialize(target, context, binding_name, getter, variable_name, template_name)
|
|
5
|
+
# puts "New EACH Binding"
|
|
6
|
+
|
|
7
|
+
super(target, context, binding_name)
|
|
8
|
+
|
|
9
|
+
@item_name = variable_name
|
|
10
|
+
@template_name = template_name
|
|
11
|
+
|
|
12
|
+
# Find the source for the content binding
|
|
13
|
+
@value = value_from_getter(getter)
|
|
14
|
+
|
|
15
|
+
@templates = []
|
|
16
|
+
|
|
17
|
+
# Run the initial render
|
|
18
|
+
update
|
|
19
|
+
|
|
20
|
+
@added_listener = @value.on('added') { |position, item| puts "ADDED" ; item_added(position) }
|
|
21
|
+
@changed_listener = @value.on('changed') { puts "CHANGED" ; reload }
|
|
22
|
+
@removed_listener = @value.on('removed') { |position| puts "REMOVED at #{position.inspect}" ; item_removed(position) }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# When a change event comes through, its most likely upstream, so the whole
|
|
26
|
+
# array might have changed. In this case, just reload the whole thing
|
|
27
|
+
# TODO: Track to make sure the changed event isn't being called too often (it is currently)
|
|
28
|
+
def reload
|
|
29
|
+
# Remove all of the current templates
|
|
30
|
+
if @templates
|
|
31
|
+
@templates.each do |template|
|
|
32
|
+
template.remove
|
|
33
|
+
template.remove_anchors
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
@templates = []
|
|
38
|
+
|
|
39
|
+
# Run update again to rebuild
|
|
40
|
+
update
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def item_removed(position)
|
|
44
|
+
position = position.cur
|
|
45
|
+
@templates[position].remove
|
|
46
|
+
@templates[position].remove_anchors
|
|
47
|
+
@templates.delete_at(position)
|
|
48
|
+
|
|
49
|
+
value_obj = @value.cur
|
|
50
|
+
|
|
51
|
+
if value_obj
|
|
52
|
+
size = value_obj.size - 1
|
|
53
|
+
else
|
|
54
|
+
size = 0
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# puts "Position: #{position} to #{size}"
|
|
58
|
+
|
|
59
|
+
# Removed at the position, update context for every item after this position
|
|
60
|
+
position.upto(size) do |index|
|
|
61
|
+
@templates[index].context.locals[:index].cur = index
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def item_added(position)
|
|
66
|
+
# puts "ADDED AT #{position}"
|
|
67
|
+
binding_name = @@binding_number
|
|
68
|
+
@@binding_number += 1
|
|
69
|
+
|
|
70
|
+
# Setup new bindings in the spot we want to insert the item
|
|
71
|
+
section.insert_anchor_before_end(binding_name)
|
|
72
|
+
|
|
73
|
+
index = ReactiveValue.new(position)
|
|
74
|
+
value = @value[index]
|
|
75
|
+
|
|
76
|
+
item_context = SubContext.new({@item_name => value, :index => index, :parent => @value}, @context)
|
|
77
|
+
|
|
78
|
+
@templates << TemplateRenderer.new(@target, item_context, binding_name, @template_name)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def update(item=nil)
|
|
82
|
+
if item
|
|
83
|
+
values = [item]
|
|
84
|
+
else
|
|
85
|
+
values = @value.cur
|
|
86
|
+
return if values.is_a?(Model) || values.is_a?(Exception)
|
|
87
|
+
values = values.attributes
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# TODO: Switch to #each?
|
|
91
|
+
values.each_with_index do |value,index|
|
|
92
|
+
item_added(index)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# When this each_binding is removed, cleanup.
|
|
97
|
+
def remove
|
|
98
|
+
# puts "Remove Each"
|
|
99
|
+
@added_listener.remove
|
|
100
|
+
@added_listener = nil
|
|
101
|
+
|
|
102
|
+
@changed_listener.remove
|
|
103
|
+
@changed_listener = nil
|
|
104
|
+
|
|
105
|
+
@removed_listener.remove
|
|
106
|
+
@removed_listener = nil
|
|
107
|
+
|
|
108
|
+
@templates.each(&:remove)
|
|
109
|
+
@templates = nil
|
|
110
|
+
|
|
111
|
+
super
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'volt/templates/base_binding'
|
|
2
|
+
|
|
3
|
+
# TODO: We need to figure out how we want to wrap JS events
|
|
4
|
+
class JSEvent
|
|
5
|
+
attr_reader :js_event
|
|
6
|
+
def initialize(js_event)
|
|
7
|
+
@js_event = js_event
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def key_code
|
|
11
|
+
`this.js_event.keyCode`
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def stop
|
|
15
|
+
# puts "STOPPING"
|
|
16
|
+
# `this.js_event.stopPropagation();`
|
|
17
|
+
`this.js_event.preventDefault();`
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class EventBinding < BaseBinding
|
|
23
|
+
attr_accessor :context, :binding_name
|
|
24
|
+
def initialize(target, context, binding_name, event_name, call_proc)
|
|
25
|
+
@target = target
|
|
26
|
+
@context = context
|
|
27
|
+
@binding_name = binding_name
|
|
28
|
+
@event_name = event_name
|
|
29
|
+
|
|
30
|
+
handler = Proc.new do |js_event|
|
|
31
|
+
event = JSEvent.new(js_event)
|
|
32
|
+
event.stop if event_name == 'submit'
|
|
33
|
+
|
|
34
|
+
# Call the proc the user setup for the event in context,
|
|
35
|
+
# pass in the wrapper for the JS event
|
|
36
|
+
result = @context.instance_exec(event, &call_proc)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
@listener = $page.events.add(event_name, self, handler)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def element
|
|
43
|
+
Element.find('#' + binding_name)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Remove the event binding
|
|
47
|
+
def remove
|
|
48
|
+
# puts "REMOVE EL FOR #{@event}"
|
|
49
|
+
$page.events.remove(@event_name, self)
|
|
50
|
+
end
|
|
51
|
+
end
|