ironnails 0.0.1
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.
- data/Rakefile +21 -0
- data/VERSION +1 -0
- data/init.rb +1 -0
- data/ironnails.gemspec +96 -0
- data/lib/iron_nails.rb +1 -0
- data/lib/ironnails/bin/IronNails.Library.dll +0 -0
- data/lib/ironnails/bin/IronRuby.Libraries.Yaml.dll +0 -0
- data/lib/ironnails/bin/IronRuby.Libraries.dll +0 -0
- data/lib/ironnails/bin/IronRuby.dll +0 -0
- data/lib/ironnails/bin/Microsoft.Dynamic.dll +0 -0
- data/lib/ironnails/bin/Microsoft.Scripting.Core.dll +0 -0
- data/lib/ironnails/bin/Microsoft.Scripting.ExtensionAttribute.dll +0 -0
- data/lib/ironnails/bin/Microsoft.Scripting.dll +0 -0
- data/lib/ironnails/config/configuration.rb +141 -0
- data/lib/ironnails/config/initializer.rb +144 -0
- data/lib/ironnails/controller/base.rb +135 -0
- data/lib/ironnails/controller/view_operations.rb +101 -0
- data/lib/ironnails/controller.rb +2 -0
- data/lib/ironnails/core_ext/array.rb +15 -0
- data/lib/ironnails/core_ext/class/attribute_accessors.rb +57 -0
- data/lib/ironnails/core_ext/class.rb +8 -0
- data/lib/ironnails/core_ext/fixnum.rb +22 -0
- data/lib/ironnails/core_ext/hash.rb +32 -0
- data/lib/ironnails/core_ext/kernel.rb +26 -0
- data/lib/ironnails/core_ext/string.rb +58 -0
- data/lib/ironnails/core_ext/symbol.rb +78 -0
- data/lib/ironnails/core_ext/system/net/web_request.rb +110 -0
- data/lib/ironnails/core_ext/system/security/secure_string.rb +18 -0
- data/lib/ironnails/core_ext/system/windows/markup/xaml_reader.rb +6 -0
- data/lib/ironnails/core_ext/system/windows/ui_element.rb +17 -0
- data/lib/ironnails/core_ext/time.rb +28 -0
- data/lib/ironnails/core_ext.rb +12 -0
- data/lib/ironnails/errors.rb +19 -0
- data/lib/ironnails/iron_xml.rb +83 -0
- data/lib/ironnails/logger.rb +4 -0
- data/lib/ironnails/logging/buffered_logger.rb +137 -0
- data/lib/ironnails/logging/class_logger.rb +29 -0
- data/lib/ironnails/models/base.rb +16 -0
- data/lib/ironnails/models/bindable_collection.rb +15 -0
- data/lib/ironnails/models/model_mixin.rb +69 -0
- data/lib/ironnails/models.rb +3 -0
- data/lib/ironnails/nails_engine.rb +398 -0
- data/lib/ironnails/observable.rb +117 -0
- data/lib/ironnails/security/secure_string.rb +61 -0
- data/lib/ironnails/version.rb +11 -0
- data/lib/ironnails/view/collections.rb +117 -0
- data/lib/ironnails/view/commands/add_sub_view_command.rb +33 -0
- data/lib/ironnails/view/commands/behavior_command.rb +29 -0
- data/lib/ironnails/view/commands/command.rb +208 -0
- data/lib/ironnails/view/commands/event_command.rb +32 -0
- data/lib/ironnails/view/commands/timed_command.rb +40 -0
- data/lib/ironnails/view/commands.rb +5 -0
- data/lib/ironnails/view/view.rb +190 -0
- data/lib/ironnails/view/view_model.rb +45 -0
- data/lib/ironnails/view/xaml_proxy.rb +226 -0
- data/lib/ironnails/view.rb +5 -0
- data/lib/ironnails/wpf.rb +113 -0
- data/lib/ironnails/wpf_application.rb +30 -0
- data/lib/ironnails.rb +68 -0
- metadata +133 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# This is an implementation of the observer pattern
|
|
2
|
+
# It serves to mimic the event system that is known
|
|
3
|
+
# in the CLR world.
|
|
4
|
+
# while ruby has a standard observable module that
|
|
5
|
+
# one doesn't allow us to listen for specific events
|
|
6
|
+
module IronNails::Core
|
|
7
|
+
|
|
8
|
+
module Observable
|
|
9
|
+
|
|
10
|
+
#
|
|
11
|
+
# Add +observer+ as an observer on this object. +observer+ will now receive
|
|
12
|
+
# notifications. +observer+ is interest in the specified +event+
|
|
13
|
+
#
|
|
14
|
+
def add_observer(event, &observer)
|
|
15
|
+
@observers = [] unless defined? @observers
|
|
16
|
+
unless observer.respond_to? :call
|
|
17
|
+
raise NoMethodError, "observer needs to respond to 'update'"
|
|
18
|
+
end
|
|
19
|
+
@observers << { :event => event, :observer => observer }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
#
|
|
23
|
+
# Delete +observer+ as an observer on this object. It will no longer receive
|
|
24
|
+
# notifications of the specified +event+.
|
|
25
|
+
#
|
|
26
|
+
def delete_observer(event, &observer)
|
|
27
|
+
evt = { :event => event, :observer => observer }
|
|
28
|
+
@observers.delete evt if defined? @observers
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
#
|
|
32
|
+
# Delete all observers associated with this object.
|
|
33
|
+
#
|
|
34
|
+
def delete_observers
|
|
35
|
+
@observers.clear if defined? @observers
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
#
|
|
39
|
+
# Return the number of observers associated with this object.
|
|
40
|
+
#
|
|
41
|
+
def count_observers
|
|
42
|
+
if defined? @observers
|
|
43
|
+
@observers.size
|
|
44
|
+
else
|
|
45
|
+
0
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
#
|
|
50
|
+
# Notifies the registered observers that some interesting
|
|
51
|
+
# +event+ has occurred. It will notify the interested parties
|
|
52
|
+
# by calling the block and passing it some context
|
|
53
|
+
#
|
|
54
|
+
def notify_observers(event, sender, *args)
|
|
55
|
+
@observers.select {|evt| evt[:event] == event }.each {|evt| evt[:observer].call sender, *args } unless count_observers.zero?
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
module ControllerObservable
|
|
62
|
+
|
|
63
|
+
#
|
|
64
|
+
# Add +observer+ as an observer on this object. +observer+ will now receive
|
|
65
|
+
# notifications. +observer+ is interest in the specified +event+
|
|
66
|
+
# +controller+ is the name of the controller that listens for this event
|
|
67
|
+
#
|
|
68
|
+
def add_observer(event, controller, &observer)
|
|
69
|
+
@controller_observers = [] unless defined? @controller_observers
|
|
70
|
+
unless observer.respond_to? :call
|
|
71
|
+
raise NoMethodError, "observer needs to respond to 'update'"
|
|
72
|
+
end
|
|
73
|
+
@controller_observers << { :event => event.to_sym, :observer => observer, :controller => controller.to_sym }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
#
|
|
77
|
+
# Delete +observer+ as an observer on this object. It will no longer receive
|
|
78
|
+
# notifications of the specified +event+.
|
|
79
|
+
#
|
|
80
|
+
def delete_observer(event, controller, &observer)
|
|
81
|
+
evt = { :event => event.to_sym, :observer => observer, :controller => controller.to_sym }
|
|
82
|
+
@controller_observers.delete evt if defined? @controller_observers
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
#
|
|
86
|
+
# Delete all observers associated with this object.
|
|
87
|
+
#
|
|
88
|
+
def delete_observers
|
|
89
|
+
@controller_observers.clear if defined? @controller_observers
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
#
|
|
93
|
+
# Return the number of observers associated with this object.
|
|
94
|
+
#
|
|
95
|
+
def count_observers
|
|
96
|
+
if defined? @controller_observers
|
|
97
|
+
@controller_observers.size
|
|
98
|
+
else
|
|
99
|
+
0
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
#
|
|
104
|
+
# Notifies the registered observers that some interesting
|
|
105
|
+
# +event+ has occurred. It will notify the interested parties
|
|
106
|
+
# by calling the block and passing it some context
|
|
107
|
+
#
|
|
108
|
+
def notify_observers(event, controller, sender, *args)
|
|
109
|
+
@controller_observers.
|
|
110
|
+
select {|evt| evt[:event] == event.to_sym && evt[:controller] == controller.to_sym }.
|
|
111
|
+
each {|evt| evt[:observer].call sender, *args }
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module IronNails
|
|
2
|
+
|
|
3
|
+
module Security
|
|
4
|
+
|
|
5
|
+
class SecureString
|
|
6
|
+
|
|
7
|
+
ENCRYPTION_SALT = "SailsPasswordSalt".freeze
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@@entropy = System::Text::Encoding.unicode.get_bytes(ENCRYPTION_SALT)
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
include System::Security::Cryptography
|
|
15
|
+
include System::Runtime::InteropServices
|
|
16
|
+
|
|
17
|
+
def encrypt_string(input)
|
|
18
|
+
encrypted_data = ProtectedData.protect(
|
|
19
|
+
System::Text::Encoding.unicode.get_bytes(unsecure_string(input)),
|
|
20
|
+
@@entropy,
|
|
21
|
+
DataProtectionScope.current_user)
|
|
22
|
+
System::Convert.to_base64_string(encrypted_data)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def secure_string(input)
|
|
26
|
+
secure = System::Security::SecureString.new
|
|
27
|
+
input.to_s.to_clr_string.to_char_array.each {|c| secure.append_char c }
|
|
28
|
+
secure.make_read_only
|
|
29
|
+
secure
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def unsecure_string(input)
|
|
33
|
+
result = ""
|
|
34
|
+
ptr = System::Runtime::InteropServices::Marshal.SecureStringToBSTR(input);
|
|
35
|
+
begin
|
|
36
|
+
result = System::Runtime::InteropServices::Marshal.PtrToStringBSTR(ptr);
|
|
37
|
+
ensure
|
|
38
|
+
System::Runtime::InteropServices::Marshal.ZeroFreeBSTR(ptr);
|
|
39
|
+
end
|
|
40
|
+
result.to_s
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def decrypt_string(encrypted_data)
|
|
44
|
+
begin
|
|
45
|
+
decrypted_data = ProtectedData.unprotect(
|
|
46
|
+
Convert.from_base64_string(encrypted_data),
|
|
47
|
+
@@entropy,
|
|
48
|
+
DataProtectionScope.current_user);
|
|
49
|
+
secure_string(System::Text::Encoding.unicode.get_bytes(decrypted_data));
|
|
50
|
+
rescue
|
|
51
|
+
System::Security::SecureString.new
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
module IronNails
|
|
2
|
+
|
|
3
|
+
module Core
|
|
4
|
+
|
|
5
|
+
class Collection
|
|
6
|
+
|
|
7
|
+
include Enumerable
|
|
8
|
+
|
|
9
|
+
def initialize(*items)
|
|
10
|
+
@items = items || []
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def each
|
|
14
|
+
@items.each do |item|
|
|
15
|
+
yield item
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def <<(item)
|
|
20
|
+
@items << item
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def [](value)
|
|
24
|
+
@items[value]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to_a
|
|
28
|
+
@items
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
module View
|
|
37
|
+
|
|
38
|
+
class CommandCollection < Core::Collection
|
|
39
|
+
|
|
40
|
+
def has_command?(command)
|
|
41
|
+
!self.find do |cmd|
|
|
42
|
+
command == cmd
|
|
43
|
+
end.nil?
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class ViewCollection < Core::Collection
|
|
49
|
+
|
|
50
|
+
def has_view?(view)
|
|
51
|
+
find_view(view[:name]).nil?
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def find_view(name)
|
|
55
|
+
self.find { |vw| vw[:name] == name }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class ViewModelCollection < Core::Collection
|
|
61
|
+
|
|
62
|
+
def has_viewmodel?(view_model)
|
|
63
|
+
if view_model.is_a?(String)
|
|
64
|
+
find_viewmodel(view_model).nil?
|
|
65
|
+
else
|
|
66
|
+
find_viewmodel(view_model.__view_model_name_).nil?
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def find_viewmodel(name)
|
|
71
|
+
self.find { |vm| vm.__view_model_name_ == name }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def <<(model)
|
|
75
|
+
@items << model unless has_viewmodel?(model)
|
|
76
|
+
find_viewmodel(model.__view_model_name_)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
class ModelCollection < Core::Collection
|
|
82
|
+
|
|
83
|
+
def has_model?(model)
|
|
84
|
+
!get_model(model).nil?
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def add_model(model)
|
|
88
|
+
key = model.keys[0]
|
|
89
|
+
has_model?(model) ? get_model(model)[key] = model[key] : @items << model
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def get_model(model)
|
|
93
|
+
@items.find do |m|
|
|
94
|
+
model.keys[0] == m.keys[0]
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
class << self
|
|
99
|
+
|
|
100
|
+
# Given a set of +objects+ it will generate
|
|
101
|
+
# a collection of objects for the view model
|
|
102
|
+
def generate_for(objects)
|
|
103
|
+
models = new
|
|
104
|
+
objects.each do |k, v|
|
|
105
|
+
models << { k => v }
|
|
106
|
+
end
|
|
107
|
+
models
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module IronNails
|
|
2
|
+
|
|
3
|
+
module View
|
|
4
|
+
|
|
5
|
+
class AddSubViewCommand < Command
|
|
6
|
+
|
|
7
|
+
# the controller for the subview
|
|
8
|
+
attr_accessor :controller
|
|
9
|
+
|
|
10
|
+
# the target that will contain the view for this controller
|
|
11
|
+
attr_accessor :target
|
|
12
|
+
|
|
13
|
+
alias_method :nails_base_command_read_options, :read_options
|
|
14
|
+
|
|
15
|
+
def read_options(options)
|
|
16
|
+
nails_base_command_read_options options
|
|
17
|
+
raise ArgumentError.new("We need a target to be defined by the :to parameter") if options[:to].nil?
|
|
18
|
+
raise ArgumentError.new("We need a controller instance to be defined in the :controller parameter") if options[:controller].nil? || !options[:controller].respond_to?(:current_view)
|
|
19
|
+
|
|
20
|
+
@controller = options[:controller]
|
|
21
|
+
@target = options[:to]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# executes this command (it calls the action)
|
|
25
|
+
def execute
|
|
26
|
+
view.add_control target, controller.current_view.instance
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module IronNails
|
|
2
|
+
|
|
3
|
+
module View
|
|
4
|
+
|
|
5
|
+
class BehaviorCommand < Command
|
|
6
|
+
|
|
7
|
+
def to_clr_command
|
|
8
|
+
# I have to wrap the method calls into blocks because .to_proc hasn't been implemented yet on method
|
|
9
|
+
# the Func's have to be wrapped in lambda's to preserve the return statement.
|
|
10
|
+
unless asynchronous?
|
|
11
|
+
delegate_command.new(Action.new { execute }, Func[System::Boolean].new(&lambda{ can_execute? } ))
|
|
12
|
+
else
|
|
13
|
+
async_delegate_command.new(Action.new { execute }, Action.new { refresh_view },
|
|
14
|
+
Func[System::Boolean].new(&lambda{ can_execute? }))
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def delegate_command
|
|
19
|
+
IronNails::Library::DelegateCommand
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def async_delegate_command
|
|
23
|
+
IronNails::Library::AsynchronousDelegateCommand
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
module IronNails
|
|
2
|
+
|
|
3
|
+
module View
|
|
4
|
+
|
|
5
|
+
# The base class for view commands in IronNails.
|
|
6
|
+
class Command
|
|
7
|
+
|
|
8
|
+
include IronNails::Logging::ClassLogger
|
|
9
|
+
include IronNails::Core::Observable
|
|
10
|
+
|
|
11
|
+
# the view this command is bound to
|
|
12
|
+
attr_accessor :view
|
|
13
|
+
|
|
14
|
+
# indicates whether to execute this command on the ui thread or on a different thread.
|
|
15
|
+
attr_accessor :mode
|
|
16
|
+
|
|
17
|
+
# the name of this command
|
|
18
|
+
attr_accessor :name
|
|
19
|
+
|
|
20
|
+
# the action that will be triggered
|
|
21
|
+
attr_accessor :action
|
|
22
|
+
|
|
23
|
+
# the predicate that decides whether this command can execute or not
|
|
24
|
+
attr_accessor :condition
|
|
25
|
+
|
|
26
|
+
# the name of the controller that built this command
|
|
27
|
+
attr_accessor :controller
|
|
28
|
+
|
|
29
|
+
# for asynchronous actions this gets executed after the view has been refreshed as a new command
|
|
30
|
+
attr_accessor :callback
|
|
31
|
+
|
|
32
|
+
def initialize(options)
|
|
33
|
+
read_options options
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def read_options(options)
|
|
37
|
+
raise ArgumentError.new("A name is necesary") if options[:name].nil?
|
|
38
|
+
raise ArgumentError.new("An action is necesary") if options[:action].nil?
|
|
39
|
+
options.each do |k, v|
|
|
40
|
+
instance_variable_set "@#{k}", v
|
|
41
|
+
end
|
|
42
|
+
@mode ||= :synchronous
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# flag to indicate whether this command needs a refresh in the view model
|
|
46
|
+
def changed?
|
|
47
|
+
!!@changed
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def can_execute?
|
|
51
|
+
!!(condition.nil?||condition.call)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def asynchronous?
|
|
55
|
+
mode == :asynchronous
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def has_callback?
|
|
59
|
+
!callback.nil?
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def refresh_view
|
|
63
|
+
callback.call if asynchronous? && has_callback?
|
|
64
|
+
notify_observers :refreshing_view, self
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def synchronise_viewmodel_with_controller
|
|
68
|
+
notify_observers :reading_input, self
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def attached?
|
|
72
|
+
!view.nil?
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# executes this command (it calls the action)
|
|
76
|
+
def execute
|
|
77
|
+
#log_on_error do
|
|
78
|
+
puts "calling the action"
|
|
79
|
+
synchronise_viewmodel_with_controller
|
|
80
|
+
action.call
|
|
81
|
+
refresh_view unless asynchronous?
|
|
82
|
+
#end if can_execute?
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def ==(command)
|
|
86
|
+
self.name == command.name
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
alias_method :===, :==
|
|
90
|
+
alias_method :equals, :==
|
|
91
|
+
|
|
92
|
+
def <=>(command)
|
|
93
|
+
self.name <=> command.name
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
alias_method :compare_to, :<=>
|
|
97
|
+
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
class CommandBuilder
|
|
101
|
+
|
|
102
|
+
attr_accessor :controller
|
|
103
|
+
|
|
104
|
+
attr_accessor :command_mapping
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def initialize(controller)
|
|
108
|
+
@controller = controller
|
|
109
|
+
@command_mapping= {
|
|
110
|
+
:event => EventCommand,
|
|
111
|
+
:timed => TimedCommand,
|
|
112
|
+
:behavior => BehaviorCommand
|
|
113
|
+
}
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Given a set of +command_definitions+ it will generate
|
|
117
|
+
# a collection of Command objects for the view model
|
|
118
|
+
def generate_for(cmd_def)
|
|
119
|
+
norm = normalize_command_definitions(cmd_def)
|
|
120
|
+
cmds = generate_command_collection_from_normalized_definitions norm
|
|
121
|
+
cmds
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def view_model
|
|
125
|
+
WpfApplication.current.nails_engine
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Generates the command definitions for our view model.
|
|
129
|
+
def normalize_command_definitions(definitions)
|
|
130
|
+
command_definitions = {}
|
|
131
|
+
|
|
132
|
+
definitions.each do |k, v|
|
|
133
|
+
command_definitions[k] = normalize_command_definition(k, v)
|
|
134
|
+
end unless definitions.nil?
|
|
135
|
+
|
|
136
|
+
command_definitions
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Generates a command definition for our view model.
|
|
140
|
+
# When it can't find a key :action in the options hash for the view_action
|
|
141
|
+
# it will default to using the name as the command as the connected option.
|
|
142
|
+
# It will generate a series of commands for items that have more than one trigger
|
|
143
|
+
def normalize_command_definition(name, options)
|
|
144
|
+
mode = options[:mode]
|
|
145
|
+
act = options[:action]||name
|
|
146
|
+
action = act
|
|
147
|
+
action = controller.method(act) if act.is_a?(Symbol) || act.is_a?(String)
|
|
148
|
+
if options.has_key?(:triggers) && !options[:triggers].nil?
|
|
149
|
+
triggers = options[:triggers]
|
|
150
|
+
|
|
151
|
+
cmd_def =
|
|
152
|
+
if triggers.is_a?(String) || triggers.is_a?(Symbol)
|
|
153
|
+
{
|
|
154
|
+
:element => triggers,
|
|
155
|
+
:event => :click,
|
|
156
|
+
:action => action,
|
|
157
|
+
:mode => mode,
|
|
158
|
+
:type => :event
|
|
159
|
+
}
|
|
160
|
+
elsif triggers.is_a?(Hash)
|
|
161
|
+
{:action => action, :mode => mode, :type => :event }.merge triggers
|
|
162
|
+
elsif triggers.is_a?(Array)
|
|
163
|
+
defs = []
|
|
164
|
+
triggers.each do |trig|
|
|
165
|
+
trig = { :element => trig, :event => :click } unless trig.is_a? Hash
|
|
166
|
+
trig[:event] = :click unless trig.has_key? :event
|
|
167
|
+
defs << { :action => action, :mode => mode, :type => :event }.merge(trig)
|
|
168
|
+
end
|
|
169
|
+
defs
|
|
170
|
+
end
|
|
171
|
+
cmd_def
|
|
172
|
+
else
|
|
173
|
+
exec = options[:execute]
|
|
174
|
+
execute = exec
|
|
175
|
+
execute = controller.method(exec) if exec.is_a?(Symbol) || exec.is_a?(String)
|
|
176
|
+
callback = options[:callback]
|
|
177
|
+
callback = controller.method(callback) if callback.is_a?(Symbol) || callback.is_a?(String)
|
|
178
|
+
controller_action, controller_condition = execute || action, options[:condition]
|
|
179
|
+
res = {
|
|
180
|
+
:action => controller_action,
|
|
181
|
+
:condition => controller_condition,
|
|
182
|
+
:mode => mode,
|
|
183
|
+
:callback => callback,
|
|
184
|
+
:type => options[:type] || :behavior
|
|
185
|
+
}
|
|
186
|
+
res[:interval] = options[:interval] if options.key? :interval
|
|
187
|
+
res
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def generate_command_collection_from_normalized_definitions(definitions)
|
|
192
|
+
commands = CommandCollection.new
|
|
193
|
+
definitions.each do |name, cmd_def|
|
|
194
|
+
cmd = create_command_from(cmd_def.merge({ :view_model => view_model, :name => name, :controller => controller.controller_name }))
|
|
195
|
+
commands << cmd
|
|
196
|
+
end if definitions.is_a?(Hash)
|
|
197
|
+
commands
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def create_command_from(definition)
|
|
201
|
+
command_mapping[definition[:type]||:behavior].new definition
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module IronNails
|
|
2
|
+
|
|
3
|
+
module View
|
|
4
|
+
|
|
5
|
+
# Encapsulates commands that will be attached to elements in the views.
|
|
6
|
+
class EventCommand < Command
|
|
7
|
+
|
|
8
|
+
# the name of the event that will trigger the action
|
|
9
|
+
attr_accessor :trigger
|
|
10
|
+
|
|
11
|
+
# the name of the element that will trigger the action
|
|
12
|
+
attr_accessor :element
|
|
13
|
+
|
|
14
|
+
# the name of the on which this command needs to be invoked
|
|
15
|
+
attr_accessor :affinity
|
|
16
|
+
|
|
17
|
+
alias_method :nails_base_command_read_options, :read_options
|
|
18
|
+
|
|
19
|
+
def read_options(options)
|
|
20
|
+
nails_base_command_read_options options
|
|
21
|
+
raise ArgumentException.new("An element name is necesary") if options[:element].nil?
|
|
22
|
+
|
|
23
|
+
@trigger = options[:event]||:click
|
|
24
|
+
@element = options[:element]
|
|
25
|
+
@affinity = options[:affinity]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module IronNails
|
|
2
|
+
|
|
3
|
+
module View
|
|
4
|
+
|
|
5
|
+
class TimedCommand < Command
|
|
6
|
+
|
|
7
|
+
# gets the name to use for the timer
|
|
8
|
+
attr_reader :timer_name
|
|
9
|
+
|
|
10
|
+
attr_accessor :interval
|
|
11
|
+
|
|
12
|
+
alias_method :nails_base_command_read_options, :read_options
|
|
13
|
+
|
|
14
|
+
def read_options(options)
|
|
15
|
+
nails_base_command_read_options options
|
|
16
|
+
|
|
17
|
+
@timer_name = get_timer_name
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# This stops the timer in the view proxy
|
|
21
|
+
def stop_timer
|
|
22
|
+
view.stop_timer self
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# This starts the timer in the view proxy
|
|
26
|
+
def start_timer
|
|
27
|
+
view.start_timer self
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def get_timer_name
|
|
33
|
+
"__#{name}_ironnails_view_timer"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/commands/command'
|
|
2
|
+
require File.dirname(__FILE__) + '/commands/event_command'
|
|
3
|
+
require File.dirname(__FILE__) + '/commands/timed_command'
|
|
4
|
+
require File.dirname(__FILE__) + '/commands/behavior_command'
|
|
5
|
+
require File.dirname(__FILE__) + '/commands/add_sub_view_command'
|