ruby_mvc 0.0.3 → 0.0.4
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/lib/ruby_mvc/ar_support.rb +84 -0
- data/lib/ruby_mvc/controllers.rb +1 -0
- data/lib/ruby_mvc/{views/ar_support.rb → controllers/action_provider.rb} +21 -7
- data/lib/ruby_mvc/controllers/app_controller.rb +10 -1
- data/lib/ruby_mvc/controllers/rails_controller.rb +1 -3
- data/lib/ruby_mvc/models/ar_row_model.rb +62 -0
- data/lib/ruby_mvc/models/ar_table_model.rb +4 -4
- data/lib/ruby_mvc/models/model.rb +8 -0
- data/lib/ruby_mvc/models/view_model_template.rb +35 -1
- data/lib/ruby_mvc/renderers/hyperlink_cell_renderer.rb +5 -3
- data/lib/ruby_mvc/toolkit/dialog.rb +8 -0
- data/lib/ruby_mvc/toolkit/peers/wxruby/dialog.rb +16 -1
- data/lib/ruby_mvc/toolkit/peers/wxruby/form_builder.rb +1 -1
- data/lib/ruby_mvc/toolkit/peers/wxruby/grid_view.rb +11 -5
- data/lib/ruby_mvc/toolkit/peers/wxruby/web_view.rb +1 -0
- data/lib/ruby_mvc/toolkit/signal_handler.rb +11 -1
- data/lib/ruby_mvc/toolkit/widget.rb +1 -1
- data/lib/ruby_mvc/views/ar_type_editor.rb +2 -1
- data/lib/ruby_mvc/views/ar_web_model_view.rb +137 -3
- data/lib/ruby_mvc/views/ar_web_type_list.rb +8 -1
- data/lib/ruby_mvc/views/browser_view.rb +4 -4
- data/lib/ruby_mvc/views/grid_table_view.rb +4 -4
- data/lib/ruby_mvc/views/view.rb +7 -10
- data/lib/ruby_mvc/views/web_content_table_view.rb +6 -1
- data/lib/ruby_mvc/views/web_model_view.rb +3 -1
- data/ruby_mvc.gemspec +1 -1
- metadata +54 -52
@@ -0,0 +1,84 @@
|
|
1
|
+
#--
|
2
|
+
######################################################################
|
3
|
+
#
|
4
|
+
# Copyright 2011 Andrew S. Townley
|
5
|
+
#
|
6
|
+
# Permission to use, copy, modify, and disribute this software for
|
7
|
+
# any purpose with or without fee is hereby granted, provided that
|
8
|
+
# the above copyright notices and this permission notice appear in
|
9
|
+
# all copies.
|
10
|
+
#
|
11
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL
|
12
|
+
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
13
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
14
|
+
# AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT OR
|
15
|
+
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
16
|
+
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
17
|
+
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
18
|
+
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
19
|
+
#
|
20
|
+
# File: ar_support.rb
|
21
|
+
# Created: Mon 12 Dec 2011 06:49:00 CST
|
22
|
+
#
|
23
|
+
#####################################################################
|
24
|
+
#++
|
25
|
+
|
26
|
+
require 'active_record'
|
27
|
+
|
28
|
+
require 'ruby_mvc/models/ar_row_model'
|
29
|
+
require 'ruby_mvc/models/ar_table_model'
|
30
|
+
require 'ruby_mvc/views/ar_form_view'
|
31
|
+
require 'ruby_mvc/views/ar_type_editor'
|
32
|
+
require 'ruby_mvc/views/ar_web_type_list'
|
33
|
+
require 'ruby_mvc/views/ar_web_model_view'
|
34
|
+
|
35
|
+
module RubyMVC
|
36
|
+
|
37
|
+
class ActiveRecordModelRegistry < Hash
|
38
|
+
def model(etk, options = {})
|
39
|
+
key = etk
|
40
|
+
key = etk.to_s.to_sym if !etk.is_a? Symbol
|
41
|
+
if has_key? key
|
42
|
+
self[key]
|
43
|
+
else
|
44
|
+
self[key] = Models::ActiveRecordTableModel.new(etk, options)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.model(*args, &block)
|
50
|
+
@ar_models ||= ActiveRecordModelRegistry.new
|
51
|
+
@ar_models.model(etk, options)
|
52
|
+
end
|
53
|
+
|
54
|
+
class ActiveRecordTemplateRegistry < Hash
|
55
|
+
def template(etk, title = nil, options = {}, &block)
|
56
|
+
if title.is_a? Hash
|
57
|
+
options = title
|
58
|
+
title = options[:title]
|
59
|
+
end
|
60
|
+
key = etk
|
61
|
+
key = etk.to_s.to_sym if !etk.is_a? Symbol
|
62
|
+
if block
|
63
|
+
obj = Models::ViewModelTemplate.new(options, &block)
|
64
|
+
obj.title = title || etk.to_s
|
65
|
+
self[key] = obj
|
66
|
+
else
|
67
|
+
self[key]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.template(*args, &block)
|
73
|
+
@ar_templates ||= ActiveRecordTemplateRegistry.new
|
74
|
+
@ar_templates.template(*args, &block)
|
75
|
+
end
|
76
|
+
|
77
|
+
def template(*args, &block)
|
78
|
+
RubyMVC.template(*args, &block)
|
79
|
+
end
|
80
|
+
|
81
|
+
def model(*args, &block)
|
82
|
+
RubyMVC.model(*args, &block)
|
83
|
+
end
|
84
|
+
end
|
data/lib/ruby_mvc/controllers.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#--
|
2
2
|
######################################################################
|
3
3
|
#
|
4
|
-
# Copyright 2011 Andrew S. Townley
|
4
|
+
# Copyright 2011-2012 Andrew S. Townley
|
5
5
|
#
|
6
6
|
# Permission to use, copy, modify, and disribute this software for
|
7
7
|
# any purpose with or without fee is hereby granted, provided that
|
@@ -17,13 +17,27 @@
|
|
17
17
|
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
18
18
|
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
19
19
|
#
|
20
|
-
# File:
|
21
|
-
# Created:
|
20
|
+
# File: action_provider.rb
|
21
|
+
# Created: Sat 14 Jan 2012 13:16:53 GMT
|
22
22
|
#
|
23
23
|
#####################################################################
|
24
24
|
#++
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
module RubyMVC
|
27
|
+
|
28
|
+
# This module is used to provide actions to toolkit widget
|
29
|
+
# implementations for appropriate rendering based on the
|
30
|
+
# widget type.
|
31
|
+
|
32
|
+
module ActionProvider
|
33
|
+
attr_reader :actions
|
34
|
+
|
35
|
+
def action(key, options = {}, &block)
|
36
|
+
@actions ||= ActionGroup.new
|
37
|
+
a = Action.new(key, options, &block)
|
38
|
+
@actions << a
|
39
|
+
a
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -42,7 +42,16 @@ module RubyMVC
|
|
42
42
|
def link_activated(sender, link)
|
43
43
|
puts "#link_activated(#{sender}, #{link})"
|
44
44
|
uri = URI.parse(link)
|
45
|
-
|
45
|
+
|
46
|
+
if uri.query
|
47
|
+
params = CGI.parse(uri.query)
|
48
|
+
params.each do |k, v|
|
49
|
+
if v && v.size == 1
|
50
|
+
params[k] = v.first
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
46
55
|
m = RubyMVC.method_name(uri.path).to_sym
|
47
56
|
if self.respond_to? m
|
48
57
|
self.send(m, sender, link, params)
|
@@ -0,0 +1,62 @@
|
|
1
|
+
#--
|
2
|
+
######################################################################
|
3
|
+
#
|
4
|
+
# Copyright 2011 Andrew S. Townley
|
5
|
+
#
|
6
|
+
# Permission to use, copy, modify, and disribute this software for
|
7
|
+
# any purpose with or without fee is hereby granted, provided that
|
8
|
+
# the above copyright notices and this permission notice appear in
|
9
|
+
# all copies.
|
10
|
+
#
|
11
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL
|
12
|
+
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
13
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
14
|
+
# AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT OR
|
15
|
+
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
16
|
+
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
17
|
+
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
18
|
+
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
19
|
+
#
|
20
|
+
# File: ar_row_model.rb
|
21
|
+
# Created: Thu 12 Jan 2012 16:47:20 GMT
|
22
|
+
#
|
23
|
+
#####################################################################
|
24
|
+
#++
|
25
|
+
|
26
|
+
module RubyMVC
|
27
|
+
module Models
|
28
|
+
|
29
|
+
# This class provides a Model adapter implementation for
|
30
|
+
# ActiveRecordBase class instances.
|
31
|
+
|
32
|
+
class ActiveRecordRowModel < Model
|
33
|
+
def initialize(row, options = {})
|
34
|
+
options[:data] = row
|
35
|
+
super(options)
|
36
|
+
end
|
37
|
+
|
38
|
+
def entity_type
|
39
|
+
@data.class
|
40
|
+
end
|
41
|
+
|
42
|
+
def keys
|
43
|
+
@data.attributes.keys.collect { |k| k.to_sym }
|
44
|
+
end
|
45
|
+
|
46
|
+
# This method provides information about inter-model links
|
47
|
+
# to provide built-in support for master-detail types of
|
48
|
+
# relationships between models.
|
49
|
+
|
50
|
+
def link_labels
|
51
|
+
# FIXME: should probably implement this intelligently to
|
52
|
+
# do some introspection magic
|
53
|
+
{}
|
54
|
+
end
|
55
|
+
|
56
|
+
def size
|
57
|
+
@data.attributes.keys.size
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -33,7 +33,7 @@ module Models
|
|
33
33
|
# the rows matching a particular query.
|
34
34
|
|
35
35
|
class ActiveRecordTableModel < TableModel
|
36
|
-
attr_reader :keys
|
36
|
+
attr_reader :keys, :entity_type
|
37
37
|
|
38
38
|
def initialize(entity_type, options = {})
|
39
39
|
super()
|
@@ -118,18 +118,18 @@ module Models
|
|
118
118
|
end
|
119
119
|
|
120
120
|
def size
|
121
|
-
puts "idx.size: #{@row_idx.size}"
|
121
|
+
# puts "idx.size: #{@row_idx.size}"
|
122
122
|
[_rows.count, @row_idx.size].max
|
123
123
|
end
|
124
124
|
|
125
125
|
protected
|
126
126
|
def _rows
|
127
|
-
if @filter
|
127
|
+
if @filter && !@rows
|
128
128
|
x = @entity_type.where(@filter)
|
129
129
|
else
|
130
130
|
x = @rows || @entity_type.find(:all)
|
131
131
|
end
|
132
|
-
puts "working with #{x.count} rows"
|
132
|
+
# puts "working with #{x.count} rows"
|
133
133
|
x
|
134
134
|
end
|
135
135
|
end
|
@@ -79,6 +79,14 @@ module Models
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
+
# This method provides information about inter-model links
|
83
|
+
# to provide built-in support for master-detail types of
|
84
|
+
# relationships between models.
|
85
|
+
|
86
|
+
def link_labels
|
87
|
+
{}
|
88
|
+
end
|
89
|
+
|
82
90
|
# This method is used to check whether a property key is
|
83
91
|
# editable or not
|
84
92
|
|
@@ -43,6 +43,8 @@ module Models
|
|
43
43
|
# may be accessed.
|
44
44
|
|
45
45
|
class ViewModelTemplate
|
46
|
+
include ActionProvider
|
47
|
+
|
46
48
|
attr_accessor :title
|
47
49
|
|
48
50
|
# When the ViewModelTemplate is initialized, it requires a set
|
@@ -52,8 +54,10 @@ module Models
|
|
52
54
|
def initialize(options = {}, &block)
|
53
55
|
@options = options
|
54
56
|
@labels = []
|
57
|
+
@link_labels = []
|
55
58
|
@options[:editable] ||= {}
|
56
59
|
@options[:properties] ||= []
|
60
|
+
@options[:links] ||= []
|
57
61
|
self.instance_eval(&block) if block
|
58
62
|
end
|
59
63
|
|
@@ -68,6 +72,10 @@ module Models
|
|
68
72
|
@labels
|
69
73
|
end
|
70
74
|
|
75
|
+
def link_labels
|
76
|
+
@link_labels
|
77
|
+
end
|
78
|
+
|
71
79
|
# Implement the Model#is_editable? method in terms of the
|
72
80
|
# template definition. If the template doesn't further
|
73
81
|
# restrict the behavior, the model's definition is used
|
@@ -94,7 +102,7 @@ module Models
|
|
94
102
|
# through the view.
|
95
103
|
|
96
104
|
def property(key, options = {})
|
97
|
-
puts "options: #{options.inspect}"
|
105
|
+
# puts "options: #{options.inspect}"
|
98
106
|
key = key.to_sym
|
99
107
|
|
100
108
|
if false == options[:show]
|
@@ -117,6 +125,32 @@ module Models
|
|
117
125
|
end
|
118
126
|
end
|
119
127
|
|
128
|
+
# This method is used to declare a linked property for the
|
129
|
+
# model and make it available to the view
|
130
|
+
|
131
|
+
def link(key, options = {})
|
132
|
+
key = key.to_sym
|
133
|
+
|
134
|
+
if false == options[:show]
|
135
|
+
show = false
|
136
|
+
else
|
137
|
+
show = true
|
138
|
+
end
|
139
|
+
|
140
|
+
editable(key, false) if false == options[:editable]
|
141
|
+
|
142
|
+
if show && !@options[:links].include?(key)
|
143
|
+
@options[:links] << key
|
144
|
+
l = options[:alias] || key.to_s.capitalize
|
145
|
+
@link_labels << options.merge({ :key => key, :label => l })
|
146
|
+
elsif !show
|
147
|
+
@options[:links].delete(key)
|
148
|
+
@link_labels.delete_if do |k|
|
149
|
+
k[:key] == key
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
120
154
|
# This method is used to apply the template to a specific,
|
121
155
|
# concrete model instance, creating a clone of the
|
122
156
|
# template in the process so that multiple different
|
@@ -33,11 +33,13 @@ module RubyMVC
|
|
33
33
|
|
34
34
|
def render(widget, row, col)
|
35
35
|
lk = col[:hl_label_key] || col[:key]
|
36
|
+
# puts "LK: #{lk.inspect}; row: #{row.inspect}"
|
36
37
|
text = row[lk]
|
37
|
-
|
38
|
+
href = col[:href]
|
39
|
+
val = row[col[:href_key] || col[:key]]
|
38
40
|
tagz {
|
39
|
-
td_ {
|
40
|
-
a_ text, :href => "#{
|
41
|
+
td_(:valign => "top") {
|
42
|
+
a_ text, :href => "#{href}#{val}"
|
41
43
|
}
|
42
44
|
}
|
43
45
|
end
|
@@ -27,6 +27,14 @@ module RubyMVC
|
|
27
27
|
module Toolkit
|
28
28
|
|
29
29
|
class Dialog < Widget
|
30
|
+
# this signal is triggered after the dialog has been
|
31
|
+
# processed modally and will return one of a range of
|
32
|
+
# response codes, depending on the type of the dialog.
|
33
|
+
#
|
34
|
+
# The standard response codes are :accept or :cancel
|
35
|
+
|
36
|
+
signal "response"
|
37
|
+
|
30
38
|
def add(w)
|
31
39
|
# FIXME: this is a cheezy way to do this...
|
32
40
|
if w.is_a? RubyMVC::Views::FormView
|
@@ -27,6 +27,7 @@ module RubyMVC
|
|
27
27
|
module Toolkit
|
28
28
|
module WxRuby
|
29
29
|
class Dialog < Wx::Dialog
|
30
|
+
include SignalHandler
|
30
31
|
include Common
|
31
32
|
Toolkit::Dialog.peer_class = self
|
32
33
|
|
@@ -64,12 +65,26 @@ module RubyMVC
|
|
64
65
|
self.sizer.fit(self)
|
65
66
|
end
|
66
67
|
|
68
|
+
def add_view(view)
|
69
|
+
sizer = Wx::BoxSizer.new(Wx::VERTICAL)
|
70
|
+
view.peer.reparent(self)
|
71
|
+
sizer.add(view.peer, 1, Wx::EXPAND|Wx::ALL, 5)
|
72
|
+
sizer.add(@buttons, 0, Wx::ALIGN_RIGHT|Wx::ALL, 5)
|
73
|
+
self.sizer = sizer
|
74
|
+
layout
|
75
|
+
end
|
76
|
+
|
67
77
|
def show
|
68
78
|
self.centre
|
69
79
|
if @modal
|
70
|
-
|
80
|
+
case self.show_modal()
|
81
|
+
when Wx::ID_OK, Wx::ID_YES
|
71
82
|
@wxform.submit if @wxform
|
83
|
+
resp = :accept
|
84
|
+
else
|
85
|
+
resp = :cancel
|
72
86
|
end
|
87
|
+
signal_emit("response", self, resp)
|
73
88
|
else
|
74
89
|
sel.show()
|
75
90
|
end
|
@@ -51,7 +51,7 @@ module RubyMVC
|
|
51
51
|
def build(parent, form)
|
52
52
|
@form = form
|
53
53
|
form.layout do |key, label, val, editor, disabled|
|
54
|
-
puts "key: #{key}; disabled: #{disabled}"
|
54
|
+
# puts "key: #{key}; disabled: #{disabled}"
|
55
55
|
case(editor)
|
56
56
|
when :textarea
|
57
57
|
w = build_textfield(parent, label, val, true)
|
@@ -32,7 +32,7 @@ module RubyMVC
|
|
32
32
|
Toolkit::GridView.peer_class = self
|
33
33
|
|
34
34
|
def initialize(options = {})
|
35
|
-
puts "options: #{options.inspect}"
|
35
|
+
# puts "options: #{options.inspect}"
|
36
36
|
super(WxRuby.parent(options), options[:id] || -1)
|
37
37
|
if false == options[:show_row_labels]
|
38
38
|
set_row_label_size(0)
|
@@ -58,7 +58,13 @@ module RubyMVC
|
|
58
58
|
# puts "Event alt: #{e.alt_down}; ctrl: #{e.control_down}; brc: #{e.get_bottom_right_coords}; bottom: #{e.get_bottom_row}; left: #{e.get_left_col}; right: #{e.get_right_col}; tlc: #{e.get_top_left_coords}; top: #{e.get_top_row}; meta: #{e.meta_down}; selecting: #{e.selecting}; shift: #{e.shift_down}"
|
59
59
|
top = e.get_top_row
|
60
60
|
bottom = e.get_bottom_row
|
61
|
-
|
61
|
+
if e.meta_down || e.shift_down
|
62
|
+
# extending the selection
|
63
|
+
sel = @selected_rows.clone
|
64
|
+
else
|
65
|
+
# reset the selection
|
66
|
+
sel = []
|
67
|
+
end
|
62
68
|
top.upto(bottom) do |i|
|
63
69
|
sel << i
|
64
70
|
end
|
@@ -80,18 +86,18 @@ module RubyMVC
|
|
80
86
|
# Grid displaying it. Kinda defeats the point...
|
81
87
|
|
82
88
|
@model.signal_connect("rows-inserted") do |s, i, r|
|
83
|
-
puts "refresh rows-inserted"
|
89
|
+
# puts "refresh rows-inserted"
|
84
90
|
@gm = GridModel.new(model)
|
85
91
|
set_table(@gm, Wx::Grid::GridSelectRows, false)
|
86
92
|
end
|
87
93
|
@model.signal_connect("rows-removed") do |s, i, r|
|
88
|
-
puts "refresh rows-removed"
|
94
|
+
# puts "refresh rows-removed"
|
89
95
|
@gm = GridModel.new(model)
|
90
96
|
selected_rows.delete(i)
|
91
97
|
set_table(@gm, Wx::Grid::GridSelectRows, false)
|
92
98
|
end
|
93
99
|
@model.signal_connect("row-changed") do |s, i, r|
|
94
|
-
puts "refresh row-changed"
|
100
|
+
# puts "refresh row-changed"
|
95
101
|
@gm = GridModel.new(model)
|
96
102
|
set_table(@gm, Wx::Grid::GridSelectRows, false)
|
97
103
|
end
|
@@ -137,11 +137,21 @@ module Toolkit
|
|
137
137
|
end
|
138
138
|
|
139
139
|
def signal_emit(signal, *args)
|
140
|
+
# FIXME: there's a few things wrong with this now that
|
141
|
+
# we've changed to support multiple signal handlers.
|
142
|
+
# Registration/deregistration should be cleaner, but
|
143
|
+
# then we'd be using an observer pattern vs the signal
|
144
|
+
# handler. Anyway, with multiple registered handlers,
|
145
|
+
# if the signal is vetoable, then it should throw a veto
|
146
|
+
# exception or something.
|
147
|
+
|
140
148
|
self.class.valid_signal! signal if self.class.respond_to? :signals
|
141
149
|
signals = (@signals ||= {})
|
150
|
+
rval = nil
|
142
151
|
(signals[signal] ||= []).each do |proc|
|
143
|
-
proc.call(*args) if !proc.nil?
|
152
|
+
(rval = proc.call(*args)) if !proc.nil?
|
144
153
|
end
|
154
|
+
rval
|
145
155
|
end
|
146
156
|
end
|
147
157
|
|
@@ -103,7 +103,7 @@ module RubyMVC
|
|
103
103
|
|
104
104
|
def connect_peer_signals
|
105
105
|
self.class.signals.each do |s, opts|
|
106
|
-
puts "connecting signal '#{peer}##{s}' to #{self}"
|
106
|
+
# puts "connecting signal '#{peer}##{s}' to #{self}"
|
107
107
|
peer.signal_connect(s) do |*args|
|
108
108
|
args[0] = self
|
109
109
|
signal_emit(s, *args)
|
@@ -35,7 +35,8 @@ module Views
|
|
35
35
|
super((@template ? @template.apply(@model) : @model), options)
|
36
36
|
signal_connect("row-edit") do |s, m, i, r|
|
37
37
|
app.dialog(:title => options[:editor_title], :parent => parent) do |dlg|
|
38
|
-
|
38
|
+
fm = (@template ? @template.apply(r) : Models::ActiveRecordRowModel.new(r))
|
39
|
+
form = FormView.new(fm, &block)
|
39
40
|
form.signal_connect("form-submit") do |form, d|
|
40
41
|
begin
|
41
42
|
r.save!
|
@@ -27,9 +27,24 @@ module RubyMVC
|
|
27
27
|
module Views
|
28
28
|
|
29
29
|
class ActiveRecordWebModelView < WebModelView
|
30
|
+
signal "add-child"
|
31
|
+
signal "add-child-link"
|
30
32
|
signal "row-edit"
|
31
33
|
signal "row-delete", :vetoable => true
|
32
34
|
|
35
|
+
# This signal is triggered when the view needs to render
|
36
|
+
# an action link for one of the linked models. Currently
|
37
|
+
# supported command keys are:
|
38
|
+
#
|
39
|
+
# - :link_edit - return a hash with the href to edit the
|
40
|
+
# link entries
|
41
|
+
#
|
42
|
+
# In each case, the arguments sent are the view, the
|
43
|
+
# command key, the model and the label entry being
|
44
|
+
# rendered.
|
45
|
+
|
46
|
+
signal "action-link"
|
47
|
+
|
33
48
|
def initialize(row, options = {})
|
34
49
|
super
|
35
50
|
|
@@ -40,18 +55,137 @@ module Views
|
|
40
55
|
# action(:delete, :label => "Delete", :icon => :stock_delete) do
|
41
56
|
# signal_emit("row-delete", self, row)
|
42
57
|
# end
|
58
|
+
|
59
|
+
begin
|
60
|
+
if @model.children
|
61
|
+
action(:add_child, :label => "Add Child", :icon => :stock_new) do
|
62
|
+
signal_emit("add-child", self, row)
|
63
|
+
end
|
64
|
+
|
65
|
+
action(:add_child_link, :label => "Add Child Link", :icon => :stock_new) do
|
66
|
+
signal_emit("add-child-link", self, row)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
rescue NoMethodError
|
70
|
+
# we ignore this on purpose
|
71
|
+
end
|
43
72
|
end
|
44
73
|
|
45
74
|
def render
|
46
|
-
|
75
|
+
# FIXME: this isn't the way to properly test for
|
76
|
+
# ancestry, but we need it right now. Needs to have a
|
77
|
+
# review/revisit of the way things are nested. It's
|
78
|
+
# evolving a little organically at the moment
|
79
|
+
# (2012-01-12: ast)
|
80
|
+
|
47
81
|
tagz {
|
48
|
-
|
49
|
-
|
82
|
+
render_parent
|
83
|
+
super
|
84
|
+
render_links
|
50
85
|
}
|
51
86
|
end
|
52
87
|
|
53
88
|
protected
|
89
|
+
def render_parent
|
90
|
+
# FIXME: this is really screwed up and shouldn't really
|
91
|
+
# work this way
|
92
|
+
# puts "#render_ancestry"
|
93
|
+
begin
|
94
|
+
@model.reload
|
95
|
+
kidz = @model.subtree[1..-1]
|
96
|
+
# puts "Ancestors: " << kidz.inspect
|
97
|
+
tagz {
|
98
|
+
if cmd = signal_emit("action-link", self, :parent_edit, @model, {})
|
99
|
+
cmd2 = signal_emit("action-link", self, :unparent, @model, {})
|
100
|
+
h3_("Parent ") {
|
101
|
+
font_(:size => "2") {
|
102
|
+
a_ cmd.delete(:text), cmd
|
103
|
+
tagz.push " "
|
104
|
+
a_ cmd2.delete(:text), cmd2 if cmd2
|
105
|
+
}
|
106
|
+
}
|
107
|
+
end
|
108
|
+
if parent = @model.parent
|
109
|
+
# puts "parent: #{parent.inspect}"
|
110
|
+
et = parent.class
|
111
|
+
pm = Models::ActiveRecordTableModel.new(et, :rows => [ parent ])
|
112
|
+
if tmpl = RubyMVC.template(et)
|
113
|
+
pm = tmpl.apply(pm)
|
114
|
+
end
|
115
|
+
tagz.push WebContentTableView.new(pm).render
|
116
|
+
end
|
117
|
+
}
|
118
|
+
rescue NoMethodError => e
|
119
|
+
puts "warning: #{e}"
|
120
|
+
# puts e.backtrace
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
54
124
|
def render_links
|
125
|
+
# puts "#render_links"
|
126
|
+
|
127
|
+
tagz {
|
128
|
+
# render children first
|
129
|
+
render_children
|
130
|
+
|
131
|
+
return if @model.link_labels.size == 0
|
132
|
+
|
133
|
+
# render other links
|
134
|
+
@model.link_labels.each do |l|
|
135
|
+
links = @model.send(l[:key], true)
|
136
|
+
edits = []
|
137
|
+
cmds = [ :linked_edit ]
|
138
|
+
if l.has_key? :link_entity
|
139
|
+
cmds.insert(0, :add_link)
|
140
|
+
cmds.insert(0, :add_linked)
|
141
|
+
cmds << :link_edit
|
142
|
+
end
|
143
|
+
|
144
|
+
cmds.each do |cmd|
|
145
|
+
edits << signal_emit("action-link", self, cmd, @model, l)
|
146
|
+
end
|
147
|
+
let = l[:entity_type]
|
148
|
+
h3_("#{let} links (#{links.size})") {
|
149
|
+
if edits.size > 0
|
150
|
+
font_(:size => "2") {
|
151
|
+
edits.each do |cmd|
|
152
|
+
tagz.push " "
|
153
|
+
a_ cmd.delete(:text), cmd
|
154
|
+
end
|
155
|
+
}
|
156
|
+
end
|
157
|
+
}
|
158
|
+
if links.size > 0
|
159
|
+
lm = Models::ActiveRecordTableModel.new(let, :rows => links)
|
160
|
+
if tmpl = RubyMVC.template(let)
|
161
|
+
lm = tmpl.apply(lm)
|
162
|
+
end
|
163
|
+
tagz.push WebContentTableView.new(lm).render
|
164
|
+
end
|
165
|
+
end
|
166
|
+
}
|
167
|
+
end
|
168
|
+
|
169
|
+
def render_children
|
170
|
+
begin
|
171
|
+
# puts "MODEL HAS CHILDREN? #{@model.has_children?}: #{@model.inspect}"
|
172
|
+
if @model.has_children?
|
173
|
+
kidz = @model.children
|
174
|
+
# puts "Children: " << kidz.inspect
|
175
|
+
et = kidz.first.class
|
176
|
+
km = Models::ActiveRecordTableModel.new(et, :rows => kidz)
|
177
|
+
if tmpl = RubyMVC.template(et)
|
178
|
+
km = tmpl.apply(km)
|
179
|
+
end
|
180
|
+
tagz {
|
181
|
+
h3_("Child #{et.to_s.pluralize}")
|
182
|
+
tagz.push WebContentTableView.new(km).render
|
183
|
+
}
|
184
|
+
end
|
185
|
+
rescue NoMethodError => e
|
186
|
+
puts "warning: #{e}"
|
187
|
+
# puts e.backtrace
|
188
|
+
end
|
55
189
|
end
|
56
190
|
end
|
57
191
|
|
@@ -27,6 +27,8 @@ module RubyMVC
|
|
27
27
|
module Views
|
28
28
|
|
29
29
|
class ActiveRecordWebTypeList < WebContentTableView
|
30
|
+
signal "add-row"
|
31
|
+
|
30
32
|
def initialize(entity_type, options = {}, &block)
|
31
33
|
@model = Models::ActiveRecordTableModel.new(entity_type, options)
|
32
34
|
if options.is_a? Hash
|
@@ -36,7 +38,12 @@ module Views
|
|
36
38
|
options = {}
|
37
39
|
end
|
38
40
|
super((@template ? @template.apply(@model) : @model), options)
|
39
|
-
|
41
|
+
|
42
|
+
action(:add, :label => "Add #{entity_type}", :icon => :stock_new) do
|
43
|
+
signal_emit("add-row", self, entity_type)
|
44
|
+
end
|
45
|
+
|
46
|
+
action(:edit, :label => "Edit", :icon => :stock_edit, &block)
|
40
47
|
end
|
41
48
|
end
|
42
49
|
|
@@ -85,7 +85,7 @@ module Views
|
|
85
85
|
widget.signal_connect("navigation-requested") do |s, h, t|
|
86
86
|
puts "BrowserView#navigation-requested: #{h}"
|
87
87
|
if (c = self.controller)
|
88
|
-
puts "forwarding to controller: #{c}"
|
88
|
+
# puts "forwarding to controller: #{c}"
|
89
89
|
c.link_activated(s, h)
|
90
90
|
end
|
91
91
|
end
|
@@ -115,7 +115,7 @@ module Views
|
|
115
115
|
end
|
116
116
|
|
117
117
|
def reload
|
118
|
-
if location && v = location[:view]
|
118
|
+
if location && (v = location[:view])
|
119
119
|
load(v, location[:uri])
|
120
120
|
else
|
121
121
|
super
|
@@ -144,10 +144,10 @@ module Views
|
|
144
144
|
# place)
|
145
145
|
|
146
146
|
if (vc = view.controller) && vc != self.controller
|
147
|
-
puts "assigned new controller from WebContentView: #{vc}"
|
147
|
+
# puts "assigned new controller from WebContentView: #{vc}"
|
148
148
|
self.controller = vc
|
149
149
|
else
|
150
|
-
puts "no controller defined for #{view}"
|
150
|
+
# puts "no controller defined for #{view}"
|
151
151
|
end
|
152
152
|
|
153
153
|
# add any content actions
|
@@ -59,7 +59,7 @@ module Views
|
|
59
59
|
:enable => :select_multi,
|
60
60
|
:icon => :stock_delete
|
61
61
|
) do
|
62
|
-
puts "rows: #{widget.selected_rows.inspect}"
|
62
|
+
# puts "rows: #{widget.selected_rows.inspect}"
|
63
63
|
widget.selected_rows.reverse_each do |i|
|
64
64
|
model.remove_row(i)
|
65
65
|
end
|
@@ -76,7 +76,7 @@ module Views
|
|
76
76
|
end
|
77
77
|
|
78
78
|
widget.signal_connect("row-selection-changed") do |s, m, rows|
|
79
|
-
puts "selection changed: #{rows.inspect}"
|
79
|
+
# puts "selection changed: #{rows.inspect}"
|
80
80
|
@actions.each do |a|
|
81
81
|
a.selection(s, m, rows)
|
82
82
|
end
|
@@ -87,8 +87,8 @@ module Views
|
|
87
87
|
signal_emit("row-edit", self, model, r, row)
|
88
88
|
end
|
89
89
|
|
90
|
-
puts "self.class.signals: #{self.class.signals.keys.inspect}"
|
91
|
-
puts "widget.class.signals: #{widget.class.signals.keys.inspect}"
|
90
|
+
# puts "self.class.signals: #{self.class.signals.keys.inspect}"
|
91
|
+
# puts "widget.class.signals: #{widget.class.signals.keys.inspect}"
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
data/lib/ruby_mvc/views/view.rb
CHANGED
@@ -25,23 +25,20 @@
|
|
25
25
|
|
26
26
|
module RubyMVC
|
27
27
|
module Views
|
28
|
-
|
28
|
+
|
29
29
|
class View < RubyMVC::Toolkit::AbstractWidget
|
30
|
-
|
30
|
+
include ActionProvider
|
31
31
|
attr_accessor :controller
|
32
32
|
|
33
33
|
def initialize(options = {})
|
34
|
-
@actions = ActionGroup.new
|
35
34
|
@options = options
|
36
35
|
self.controller = options[:controller]
|
37
36
|
(options[:actions] || []).each { |a| @actions << a }
|
38
37
|
end
|
39
38
|
|
40
39
|
protected
|
41
|
-
def
|
42
|
-
|
43
|
-
@actions << a
|
44
|
-
a
|
40
|
+
def options
|
41
|
+
@options
|
45
42
|
end
|
46
43
|
end
|
47
44
|
|
@@ -73,7 +70,7 @@ module RubyMVC
|
|
73
70
|
# widgets.
|
74
71
|
|
75
72
|
def widget(*args, &block)
|
76
|
-
puts "Set widget for #{self}: #{args.inspect}"
|
73
|
+
# puts "Set widget for #{self}: #{args.inspect}"
|
77
74
|
@widget_def = { :args => args, :block => block }
|
78
75
|
end
|
79
76
|
end
|
@@ -96,11 +93,11 @@ module RubyMVC
|
|
96
93
|
# appropriately manage signal registration
|
97
94
|
|
98
95
|
def signal_connect(signal, &b)
|
99
|
-
puts "Widget class: #{@widget.class}"
|
96
|
+
# puts "Widget class: #{@widget.class}"
|
100
97
|
if @widget.class.valid_signal? signal
|
101
98
|
@widget.signal_connect(signal, &b)
|
102
99
|
else
|
103
|
-
puts "super"
|
100
|
+
# puts "super"
|
104
101
|
super
|
105
102
|
end
|
106
103
|
end
|
@@ -31,8 +31,13 @@ module Views
|
|
31
31
|
|
32
32
|
class WebContentTableView < WebContentView
|
33
33
|
def render
|
34
|
+
html = ""
|
35
|
+
if t = @options[:title]
|
36
|
+
html << "<h2>" << t << "</h2>"
|
37
|
+
end
|
38
|
+
|
34
39
|
r = @options[:renderer] || Renderers::Html4TableModelRenderer
|
35
|
-
r.render(@model, @options)
|
40
|
+
html << r.render(@model, @options)
|
36
41
|
end
|
37
42
|
end
|
38
43
|
|
@@ -30,6 +30,7 @@ module Views
|
|
30
30
|
include Tagz
|
31
31
|
|
32
32
|
def initialize(row, options = {})
|
33
|
+
@model_type = row.class
|
33
34
|
if options.is_a? Hash
|
34
35
|
@template = options[:template]
|
35
36
|
else
|
@@ -46,7 +47,8 @@ module Views
|
|
46
47
|
protected
|
47
48
|
def render_properties
|
48
49
|
tagz {
|
49
|
-
|
50
|
+
h2_(@model_type)
|
51
|
+
table_(:border => 1, :cellspacing => 0) {
|
50
52
|
@model.labels.each do |l|
|
51
53
|
k = l[:key]
|
52
54
|
tr_ {
|
data/ruby_mvc.gemspec
CHANGED
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: ruby_mvc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.4
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Andrew S. Townley
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-01-
|
13
|
+
date: 2012-01-14 00:00:00 Z
|
14
14
|
dependencies: []
|
15
15
|
|
16
16
|
description: A simple, cross-platform MVC framework for Ruby
|
@@ -22,75 +22,77 @@ extensions: []
|
|
22
22
|
extra_rdoc_files: []
|
23
23
|
|
24
24
|
files:
|
25
|
-
- lib/ruby_mvc/
|
26
|
-
- lib/ruby_mvc/
|
27
|
-
- lib/ruby_mvc/
|
28
|
-
- lib/ruby_mvc/
|
29
|
-
- lib/ruby_mvc/
|
30
|
-
- lib/ruby_mvc/
|
31
|
-
- lib/ruby_mvc/
|
32
|
-
- lib/ruby_mvc/
|
33
|
-
- lib/ruby_mvc/
|
34
|
-
- lib/ruby_mvc/
|
35
|
-
- lib/ruby_mvc/
|
36
|
-
- lib/ruby_mvc/
|
25
|
+
- lib/ruby_mvc/views/ar_type_editor.rb
|
26
|
+
- lib/ruby_mvc/views/ar_web_type_list.rb
|
27
|
+
- lib/ruby_mvc/views/web_content_table_view.rb
|
28
|
+
- lib/ruby_mvc/views/ar_web_model_view.rb
|
29
|
+
- lib/ruby_mvc/views/web_content_view.rb
|
30
|
+
- lib/ruby_mvc/views/table_view.rb
|
31
|
+
- lib/ruby_mvc/views/form_view.rb
|
32
|
+
- lib/ruby_mvc/views/view.rb
|
33
|
+
- lib/ruby_mvc/views/browser_view.rb
|
34
|
+
- lib/ruby_mvc/views/web_model_view.rb
|
35
|
+
- lib/ruby_mvc/views/grid_table_view.rb
|
36
|
+
- lib/ruby_mvc/views/ar_form_view.rb
|
37
|
+
- lib/ruby_mvc/wx.rb
|
38
|
+
- lib/ruby_mvc/toolkit.rb
|
37
39
|
- lib/ruby_mvc/models.rb
|
38
|
-
- lib/ruby_mvc/module.rb
|
39
|
-
- lib/ruby_mvc/renderers/html4_table_model_renderer.rb
|
40
|
-
- lib/ruby_mvc/renderers/hyperlink_cell_renderer.rb
|
41
|
-
- lib/ruby_mvc/renderers.rb
|
42
|
-
- lib/ruby_mvc/toolkit/app.rb
|
43
|
-
- lib/ruby_mvc/toolkit/browser_history.rb
|
44
|
-
- lib/ruby_mvc/toolkit/dialog.rb
|
45
|
-
- lib/ruby_mvc/toolkit/frame.rb
|
46
|
-
- lib/ruby_mvc/toolkit/grid_view.rb
|
47
|
-
- lib/ruby_mvc/toolkit/messagebox.rb
|
48
|
-
- lib/ruby_mvc/toolkit/peers/wxruby/app.rb
|
49
|
-
- lib/ruby_mvc/toolkit/peers/wxruby/box_layout.rb
|
50
40
|
- lib/ruby_mvc/toolkit/peers/wxruby/common.rb
|
41
|
+
- lib/ruby_mvc/toolkit/peers/wxruby/box_layout.rb
|
42
|
+
- lib/ruby_mvc/toolkit/peers/wxruby/grid_view.rb
|
51
43
|
- lib/ruby_mvc/toolkit/peers/wxruby/dialog.rb
|
44
|
+
- lib/ruby_mvc/toolkit/peers/wxruby/app.rb
|
52
45
|
- lib/ruby_mvc/toolkit/peers/wxruby/form_builder.rb
|
53
46
|
- lib/ruby_mvc/toolkit/peers/wxruby/frame.rb
|
54
|
-
- lib/ruby_mvc/toolkit/peers/wxruby/grid_model.rb
|
55
|
-
- lib/ruby_mvc/toolkit/peers/wxruby/grid_view.rb
|
56
|
-
- lib/ruby_mvc/toolkit/peers/wxruby/messagebox.rb
|
57
47
|
- lib/ruby_mvc/toolkit/peers/wxruby/web_view.rb
|
48
|
+
- lib/ruby_mvc/toolkit/peers/wxruby/messagebox.rb
|
49
|
+
- lib/ruby_mvc/toolkit/peers/wxruby/grid_model.rb
|
58
50
|
- lib/ruby_mvc/toolkit/peers/wxruby.rb
|
59
|
-
- lib/ruby_mvc/toolkit/
|
51
|
+
- lib/ruby_mvc/toolkit/grid_view.rb
|
52
|
+
- lib/ruby_mvc/toolkit/dialog.rb
|
53
|
+
- lib/ruby_mvc/toolkit/app.rb
|
60
54
|
- lib/ruby_mvc/toolkit/signal_handler.rb
|
55
|
+
- lib/ruby_mvc/toolkit/frame.rb
|
56
|
+
- lib/ruby_mvc/toolkit/browser_history.rb
|
61
57
|
- lib/ruby_mvc/toolkit/web_view.rb
|
58
|
+
- lib/ruby_mvc/toolkit/messagebox.rb
|
62
59
|
- lib/ruby_mvc/toolkit/widget.rb
|
63
|
-
- lib/ruby_mvc/toolkit.rb
|
64
|
-
- lib/ruby_mvc/
|
65
|
-
- lib/ruby_mvc/
|
66
|
-
- lib/ruby_mvc/
|
67
|
-
- lib/ruby_mvc/
|
68
|
-
- lib/ruby_mvc/
|
69
|
-
- lib/ruby_mvc/
|
70
|
-
- lib/ruby_mvc/
|
71
|
-
- lib/ruby_mvc/
|
72
|
-
- lib/ruby_mvc/
|
73
|
-
- lib/ruby_mvc/
|
74
|
-
- lib/ruby_mvc/
|
75
|
-
- lib/ruby_mvc/
|
76
|
-
- lib/ruby_mvc/
|
60
|
+
- lib/ruby_mvc/toolkit/property_change_notifier.rb
|
61
|
+
- lib/ruby_mvc/controllers/app_controller.rb
|
62
|
+
- lib/ruby_mvc/controllers/action_provider.rb
|
63
|
+
- lib/ruby_mvc/controllers/action_group.rb
|
64
|
+
- lib/ruby_mvc/controllers/action.rb
|
65
|
+
- lib/ruby_mvc/controllers/rails_controller.rb
|
66
|
+
- lib/ruby_mvc/models/view_model_template.rb
|
67
|
+
- lib/ruby_mvc/models/table_model.rb
|
68
|
+
- lib/ruby_mvc/models/keyed_array_table_model.rb
|
69
|
+
- lib/ruby_mvc/models/model.rb
|
70
|
+
- lib/ruby_mvc/models/ar_row_model.rb
|
71
|
+
- lib/ruby_mvc/models/ar_table_model.rb
|
72
|
+
- lib/ruby_mvc/models/array_table_model.rb
|
73
|
+
- lib/ruby_mvc/module.rb
|
74
|
+
- lib/ruby_mvc/ar_support.rb
|
75
|
+
- lib/ruby_mvc/controllers.rb
|
76
|
+
- lib/ruby_mvc/renderers/html4_table_model_renderer.rb
|
77
|
+
- lib/ruby_mvc/renderers/hyperlink_cell_renderer.rb
|
78
|
+
- lib/ruby_mvc/application.rb
|
77
79
|
- lib/ruby_mvc/views.rb
|
78
|
-
- lib/ruby_mvc/
|
80
|
+
- lib/ruby_mvc/renderers.rb
|
79
81
|
- lib/ruby_mvc.rb
|
80
|
-
- sample/browser_view.rb
|
81
|
-
- sample/form.rb
|
82
82
|
- sample/form2.rb
|
83
|
-
- sample/
|
84
|
-
- sample/grid_table_view.rb
|
83
|
+
- sample/test2.html
|
85
84
|
- sample/grid_view.rb
|
86
85
|
- sample/grid_view2.rb
|
86
|
+
- sample/form.rb
|
87
|
+
- sample/frame.rb
|
88
|
+
- sample/web_view.rb
|
87
89
|
- sample/mvc.rb
|
90
|
+
- sample/browser_view.rb
|
88
91
|
- sample/test.html
|
89
|
-
- sample/
|
90
|
-
-
|
92
|
+
- sample/grid_table_view.rb
|
93
|
+
- test/unit/models/test_model.rb
|
91
94
|
- test/unit/models/test_array_table_model.rb
|
92
95
|
- test/unit/models/test_keyed_array_table_model.rb
|
93
|
-
- test/unit/models/test_model.rb
|
94
96
|
- test/unit/test_array_table_model.rb
|
95
97
|
- LICENSE
|
96
98
|
- README.md
|