presenting 1.0.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.
- data/LICENSE +20 -0
- data/README +10 -0
- data/Rakefile +22 -0
- data/app/assets/javascript/grid.js +0 -0
- data/app/assets/javascript/search.js +13 -0
- data/app/assets/stylesheets/details-color.css +7 -0
- data/app/assets/stylesheets/details.css +10 -0
- data/app/assets/stylesheets/form.css +1 -0
- data/app/assets/stylesheets/grid-color.css +71 -0
- data/app/assets/stylesheets/grid.css +64 -0
- data/app/assets/stylesheets/search-color.css +16 -0
- data/app/assets/stylesheets/search.css +45 -0
- data/app/controllers/presentation/assets_controller.rb +42 -0
- data/app/views/presentations/_details.erb +11 -0
- data/app/views/presentations/_field_search.erb +14 -0
- data/app/views/presentations/_form.erb +20 -0
- data/app/views/presentations/_grid.erb +70 -0
- data/app/views/presentations/_search.erb +7 -0
- data/config/routes.rb +3 -0
- data/lib/presentation/base.rb +48 -0
- data/lib/presentation/details.rb +19 -0
- data/lib/presentation/field_search.rb +65 -0
- data/lib/presentation/form.rb +149 -0
- data/lib/presentation/grid.rb +160 -0
- data/lib/presentation/search.rb +9 -0
- data/lib/presenting/attribute.rb +51 -0
- data/lib/presenting/configurable.rb +10 -0
- data/lib/presenting/defaults.rb +10 -0
- data/lib/presenting/field_set.rb +26 -0
- data/lib/presenting/form_helpers.rb +51 -0
- data/lib/presenting/helpers.rb +110 -0
- data/lib/presenting/sanitize.rb +19 -0
- data/lib/presenting/search.rb +185 -0
- data/lib/presenting/sorting.rb +87 -0
- data/lib/presenting/view.rb +3 -0
- data/lib/presenting.rb +9 -0
- data/rails/init.rb +12 -0
- data/test/assets_test.rb +58 -0
- data/test/attribute_test.rb +61 -0
- data/test/configurable_test.rb +20 -0
- data/test/details_test.rb +68 -0
- data/test/field_search_test.rb +102 -0
- data/test/field_set_test.rb +46 -0
- data/test/form_test.rb +287 -0
- data/test/grid_test.rb +219 -0
- data/test/helpers_test.rb +72 -0
- data/test/presenting_test.rb +15 -0
- data/test/rails/app/controllers/application_controller.rb +15 -0
- data/test/rails/app/controllers/users_controller.rb +36 -0
- data/test/rails/app/helpers/application_helper.rb +3 -0
- data/test/rails/app/helpers/users_helper.rb +2 -0
- data/test/rails/app/models/user.rb +2 -0
- data/test/rails/app/views/layouts/application.html.erb +15 -0
- data/test/rails/app/views/users/index.html.erb +10 -0
- data/test/rails/app/views/users/new.html.erb +2 -0
- data/test/rails/app/views/users/show.html.erb +1 -0
- data/test/rails/config/boot.rb +109 -0
- data/test/rails/config/database.yml +17 -0
- data/test/rails/config/environment.rb +13 -0
- data/test/rails/config/environments/development.rb +17 -0
- data/test/rails/config/environments/production.rb +24 -0
- data/test/rails/config/environments/test.rb +22 -0
- data/test/rails/config/locales/en.yml +5 -0
- data/test/rails/config/routes.rb +5 -0
- data/test/rails/db/development.sqlite3 +0 -0
- data/test/rails/db/migrate/20090213085444_create_users.rb +13 -0
- data/test/rails/db/migrate/20090213085607_populate_users.rb +13 -0
- data/test/rails/db/schema.rb +23 -0
- data/test/rails/db/test.sqlite3 +0 -0
- data/test/rails/log/development.log +858 -0
- data/test/rails/public/404.html +30 -0
- data/test/rails/public/422.html +30 -0
- data/test/rails/public/500.html +33 -0
- data/test/rails/public/javascripts/application.js +2 -0
- data/test/rails/public/javascripts/jquery.livequery.min.js +11 -0
- data/test/rails/public/javascripts/prototype.js +4320 -0
- data/test/rails/script/console +3 -0
- data/test/rails/script/dbconsole +3 -0
- data/test/rails/script/destroy +3 -0
- data/test/rails/script/generate +3 -0
- data/test/rails/script/plugin +3 -0
- data/test/rails/script/runner +3 -0
- data/test/rails/script/server +3 -0
- data/test/sanitize_test.rb +15 -0
- data/test/search_conditions_test.rb +137 -0
- data/test/search_test.rb +30 -0
- data/test/sorting_test.rb +63 -0
- data/test/test_helper.rb +66 -0
- metadata +217 -0
data/test/form_test.rb
ADDED
@@ -0,0 +1,287 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class FormTest < Presenting::Test
|
4
|
+
def setup
|
5
|
+
@f = Presentation::Form.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_method_for_new_record
|
9
|
+
@f.presentable = stub('record', :new_record? => true)
|
10
|
+
assert_equal :post, @f.method
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_method_for_existing_record
|
14
|
+
@f.presentable = stub('record', :new_record? => false)
|
15
|
+
assert_equal :put, @f.method
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_button_for_new_record
|
19
|
+
@f.presentable = stub('record', :new_record? => true)
|
20
|
+
assert_equal 'Create', @f.button
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_button_for_existing_record
|
24
|
+
@f.presentable = stub('record', :new_record? => false)
|
25
|
+
assert_equal 'Update', @f.button
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_adding_a_field_by_name
|
29
|
+
@f.fields = [:a]
|
30
|
+
|
31
|
+
assert_equal :a, @f.fields.first.name
|
32
|
+
assert_equal 'A', @f.fields.first.label
|
33
|
+
assert_equal :string, @f.fields.first.type
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_adding_a_field_by_name_and_type
|
37
|
+
@f.fields = [{:b => :boolean}]
|
38
|
+
|
39
|
+
assert_equal :b, @f.fields.first.name
|
40
|
+
assert_equal 'B', @f.fields.first.label
|
41
|
+
assert_equal :boolean, @f.fields.first.type
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_adding_a_field_by_name_and_options
|
45
|
+
@f.fields = [{:foo => {:label => "Foo Bar", :type => :select}}]
|
46
|
+
|
47
|
+
assert_equal :foo, @f.fields.first.name
|
48
|
+
assert_equal 'Foo Bar', @f.fields.first.label
|
49
|
+
assert_equal :select, @f.fields.first.type
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_fields_accessors_are_shortcuts_to_first_group
|
53
|
+
@f.fields = [:a]
|
54
|
+
assert_equal :a, @f.groups.first.fields.first.name
|
55
|
+
assert_equal @f.fields, @f.groups.first.fields
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_adding_an_unnamed_group_of_fields
|
59
|
+
@f.groups = [[:a]]
|
60
|
+
|
61
|
+
assert_nil @f.groups.first.name
|
62
|
+
assert_equal :a, @f.groups.first.fields.first.name
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_adding_a_named_group_of_fields
|
66
|
+
@f.groups = [{"foo" => [:a]}]
|
67
|
+
|
68
|
+
assert_equal "foo", @f.groups.first.name
|
69
|
+
assert_equal :a, @f.groups.first.fields.first.name
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class FormFieldTest < Presenting::Test
|
74
|
+
def setup
|
75
|
+
@f = Presentation::Form::Field.new
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_default_value
|
79
|
+
@f.name = 'foo'
|
80
|
+
assert_equal :foo, @f.value
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_symbol_value
|
84
|
+
@f.value = :foo
|
85
|
+
assert_equal 'bar', @f.value_from(stub('record', :foo => 'bar'))
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_string_value
|
89
|
+
@f.value = 'foo'
|
90
|
+
assert_equal 'foo', @f.value_from(stub('record', :foo => 'bar'))
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_proc_value
|
94
|
+
@f.value = proc{|r| r.foo }
|
95
|
+
assert_equal 'bar', @f.value_from(stub('record', :foo => 'bar'))
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class FormRenderingTest < Presentation::RenderTest
|
100
|
+
def setup
|
101
|
+
@presentation = Presentation::Form.new
|
102
|
+
@presentation.controller = TestController.new
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_rendering_a_string_field
|
106
|
+
@presentation.presentable = User.new(:name => 'bob smith')
|
107
|
+
@presentation.fields = [:name]
|
108
|
+
|
109
|
+
assert_select 'form div.field' do
|
110
|
+
assert_select 'label', 'Name'
|
111
|
+
assert_select "input[type=text][name='user[name]'][value='bob smith']"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_rendering_a_string_field_with_a_custom_value
|
116
|
+
@presentation.presentable = User.new(:name => 'bob smith')
|
117
|
+
@presentation.fields << {:name => {:value => 'test'}}
|
118
|
+
|
119
|
+
assert_select 'form div.field' do
|
120
|
+
assert_select "input[type=text][name='user[name]'][value='test']"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_rendering_a_text_field
|
125
|
+
@presentation.presentable = User.new(:name => 'bob smith')
|
126
|
+
@presentation.fields = [{:name => :text}]
|
127
|
+
|
128
|
+
assert_select 'form div.field' do
|
129
|
+
assert_select 'label', 'Name'
|
130
|
+
assert_select "textarea[name='user[name]']", 'bob smith'
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_rendering_a_text_field_with_a_custom_value
|
135
|
+
@presentation.presentable = User.new(:name => 'bob smith')
|
136
|
+
@presentation.fields << {:name => {:type => :text, :value => 'test'}}
|
137
|
+
|
138
|
+
assert_select 'form div.field' do
|
139
|
+
assert_select "textarea[name='user[name]']", 'test'
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_rendering_a_readonly_field
|
144
|
+
@presentation.presentable = User.new(:name => 'bob smith')
|
145
|
+
@presentation.fields = [{:name => :readonly}]
|
146
|
+
|
147
|
+
assert_select 'form div.field' do
|
148
|
+
assert_select 'label', 'Name'
|
149
|
+
assert_select "input[type=text][disabled=disabled][name='user[name]'][value='bob smith']"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_rendering_a_readonly_field_with_a_custom_value
|
154
|
+
@presentation.presentable = User.new(:name => 'bob smith')
|
155
|
+
@presentation.fields << {:name => {:type => :readonly, :value => 'test'}}
|
156
|
+
|
157
|
+
assert_select 'form div.field' do
|
158
|
+
assert_select "input[type=text][disabled=disabled][name='user[name]'][value='test']"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_rendering_a_password_field
|
163
|
+
@presentation.presentable = User.new(:name => 'bob smith')
|
164
|
+
@presentation.fields = [{:name => :password}]
|
165
|
+
|
166
|
+
assert_select 'form div.field' do
|
167
|
+
assert_select 'label', 'Name'
|
168
|
+
assert_select "input[type=password][name='user[name]'][value='bob smith']"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_rendering_a_boolean_field
|
173
|
+
@presentation.presentable = User.new(:suspended => false, :registered => true)
|
174
|
+
@presentation.fields = [{:suspended => :boolean}, {:registered => :boolean}]
|
175
|
+
|
176
|
+
assert_select 'form div.field:nth-of-type(1)' do
|
177
|
+
assert_select 'label', 'Suspended'
|
178
|
+
assert_select "input[type=checkbox][name='user[suspended]']"
|
179
|
+
end
|
180
|
+
assert_select 'form div.field:nth-of-type(2)' do
|
181
|
+
assert_select 'label', 'Registered'
|
182
|
+
assert_select "input[type=checkbox][name='user[registered]'][checked=checked]"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_rendering_a_hidden_field
|
187
|
+
@presentation.presentable = User.new(:suspended => false)
|
188
|
+
@presentation.fields = [{:suspended => :hidden}]
|
189
|
+
|
190
|
+
assert_select 'form' do
|
191
|
+
assert_select 'label', {:text => 'Suspended', :count => 0}
|
192
|
+
assert_select "input[type=hidden][name='user[suspended]']"
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_rendering_a_dropdown_field
|
197
|
+
@presentation.presentable = User.new(:prefix => 'mr')
|
198
|
+
@presentation.fields = [{:prefix => {:type => :dropdown, :type_options => [['Mr.', 'mr'], ['Mrs.', 'mrs']]}}]
|
199
|
+
|
200
|
+
assert_select 'form div.field' do
|
201
|
+
assert_select 'label', 'Prefix'
|
202
|
+
assert_select "select[name='user[prefix]']" do
|
203
|
+
assert_select "option[value=mr][selected=selected]", "Mr."
|
204
|
+
assert_select "option[value=mrs]", "Mrs."
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_rendering_a_radios_field
|
210
|
+
@presentation.presentable = User.new(:prefix => 'mr')
|
211
|
+
@presentation.fields = [{:prefix => {:type => :radios, :type_options => [['Mr.', 'mr'], ['Mrs.', 'mrs']]}}]
|
212
|
+
|
213
|
+
assert_select 'form div.field' do
|
214
|
+
assert_select 'label', 'Prefix'
|
215
|
+
assert_select "label[for=user_prefix_mr]", "Mr."
|
216
|
+
assert_select "input[type=radio][name='user[prefix]'][value=mr][checked=checked]"
|
217
|
+
assert_select "label[for=user_prefix_mrs]", "Mrs."
|
218
|
+
assert_select "input[type=radio][name='user[prefix]'][value=mrs]"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def test_rendering_a_multi_select_field
|
223
|
+
@presentation.presentable = User.new(:role_ids => [1,3])
|
224
|
+
@presentation.fields = [{:role_ids => {:type => :multi_select, :type_options => [['A', 1], ['B', 2], ['C', 3]], :label => "Roles"}}]
|
225
|
+
|
226
|
+
assert_select 'form div.field' do
|
227
|
+
assert_select 'label', 'Roles'
|
228
|
+
assert_select "select[name='user[role_ids][]'][multiple=multiple]" do
|
229
|
+
assert_select "option[value=1][selected=selected]", "A"
|
230
|
+
assert_select "option[value=2]", "B"
|
231
|
+
assert_select "option[value=3][selected=selected]", "C"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def test_rendering_a_group_of_fields
|
237
|
+
@presentation.presentable = User.new
|
238
|
+
@presentation.groups = [
|
239
|
+
[:name, :email],
|
240
|
+
{"flags" => [:registered, :suspended]}
|
241
|
+
]
|
242
|
+
|
243
|
+
assert_select "form fieldset:nth-of-type(1)" do
|
244
|
+
assert_select "legend", false
|
245
|
+
assert_select "div.field input[name='user[name]']"
|
246
|
+
assert_select "div.field input[name='user[email]']"
|
247
|
+
end
|
248
|
+
assert_select "form fieldset:nth-of-type(2)" do
|
249
|
+
assert_select "legend", "flags"
|
250
|
+
assert_select "div.field input[name='user[registered]']"
|
251
|
+
assert_select "div.field input[name='user[suspended]']"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
class User
|
256
|
+
include Presenting::Configurable
|
257
|
+
|
258
|
+
attr_accessor :prefix
|
259
|
+
attr_accessor :name
|
260
|
+
attr_accessor :email
|
261
|
+
attr_accessor :registered
|
262
|
+
attr_accessor :suspended
|
263
|
+
attr_accessor :role_ids
|
264
|
+
|
265
|
+
##
|
266
|
+
## duck typing
|
267
|
+
##
|
268
|
+
|
269
|
+
def new_record=(val)
|
270
|
+
@new_record = val
|
271
|
+
end
|
272
|
+
|
273
|
+
def new_record?
|
274
|
+
!! @new_record
|
275
|
+
end
|
276
|
+
|
277
|
+
def id
|
278
|
+
@id ||= new_record? ? nil : '12345'
|
279
|
+
end
|
280
|
+
|
281
|
+
def to_param
|
282
|
+
id
|
283
|
+
end
|
284
|
+
|
285
|
+
def self.name; 'User' end
|
286
|
+
end
|
287
|
+
end
|
data/test/grid_test.rb
ADDED
@@ -0,0 +1,219 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class GridTest < Presenting::Test
|
4
|
+
def setup
|
5
|
+
@g = Presentation::Grid.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_default_title
|
9
|
+
@g.id = "something_or_other"
|
10
|
+
assert_equal "Something Or Other", @g.title
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_adding_a_field_by_name
|
14
|
+
@g.fields = ["foo"]
|
15
|
+
assert_equal "foo", @g.fields.first.name, "name is stringified"
|
16
|
+
assert_equal "foo", @g.fields.first.value, "value is assumed to be a method"
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_adding_a_field_by_name_and_value
|
20
|
+
@g.fields = [{"foo" => :bar}]
|
21
|
+
assert_equal "foo", @g.fields.first.name, "key is name"
|
22
|
+
assert_equal :bar, @g.fields.first.value, "value is value"
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_adding_a_field_by_name_and_options
|
26
|
+
@g.fields = [{"foo" => {:value => :bar}}]
|
27
|
+
assert_equal "foo", @g.fields.first.name, "key is name"
|
28
|
+
assert_equal :bar, @g.fields.first.value, "value is found and saved"
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_adding_links_as_strings
|
32
|
+
@g.links = ['<a href="/foo">foo</a>']
|
33
|
+
assert_equal 1, @g.links.size
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_adding_links_as_procs
|
37
|
+
assert_raises ArgumentError do
|
38
|
+
@g.links = [proc{|record| link_to(record.name, record)}]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_adding_record_links_as_procs
|
43
|
+
@g.record_links = [proc{|record| link_to(record.name, record)}]
|
44
|
+
assert_equal 1, @g.record_links.size
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_adding_nil_record_links
|
48
|
+
assert_nothing_raised do
|
49
|
+
# this would happen if a link sometimes did not appear
|
50
|
+
@g.record_links = [nil]
|
51
|
+
end
|
52
|
+
assert @g.record_links.empty?
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_adding_record_links_as_strings
|
56
|
+
assert_raises ArgumentError do
|
57
|
+
@g.record_links = ['<a href="/foo">foo</a>']
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_arrays_do_not_paginate
|
62
|
+
@g.presentable = []
|
63
|
+
assert !@g.paginate?
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_paginated_collections_will_paginate
|
67
|
+
@g.presentable = WillPaginate::Collection.new(1, 1)
|
68
|
+
assert @g.paginate?
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class GridFieldTest < Presenting::Test
|
73
|
+
def setup
|
74
|
+
@f = Presentation::Grid::Field.new
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_default_sorting_for_field
|
78
|
+
@f.name = "First Name"
|
79
|
+
assert @f.sortable?
|
80
|
+
assert_equal "first_name", @f.sort_name
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_sortable_field
|
84
|
+
@f.name = "First Name"
|
85
|
+
@f.sortable = true
|
86
|
+
assert @f.sortable?
|
87
|
+
assert_equal "first_name", @f.sort_name
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_specified_sort_name
|
91
|
+
@f.name = "First Name"
|
92
|
+
@f.sortable = "foo"
|
93
|
+
assert @f.sortable?
|
94
|
+
assert_equal "foo", @f.sort_name
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_unsortable_field
|
98
|
+
@f.sortable = false
|
99
|
+
assert !@f.sortable?
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class GridRenderTest < Presentation::RenderTest
|
104
|
+
def setup
|
105
|
+
@presentation = Presentation::Grid.new(:id => "users", :fields => [:name, :email])
|
106
|
+
@records = [
|
107
|
+
stub('user', :name => 'foo', :email => 'foo@example.com'),
|
108
|
+
stub('user', :name => 'bar', :email => 'bar@example.com')
|
109
|
+
]
|
110
|
+
@presentation.presentable = @records
|
111
|
+
@presentation.controller = TestController.new
|
112
|
+
@presentation.controller.params = {:controller => 'users', :action => 'index'} # WillPaginate reuses existing params
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_rendering_the_title
|
116
|
+
assert_select "#users table caption", 'Users'
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_rendering_links
|
120
|
+
@presentation.links = ['<a href="/foo" class="foo">bar</a>']
|
121
|
+
|
122
|
+
assert_select '#users caption ul.actions' do
|
123
|
+
assert_select 'li a.foo', 'bar'
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_rendering_record_links
|
128
|
+
@presentation.record_links = [proc{|r| "<a href='/foo' class='record-link'>#{r.name}</a>"}]
|
129
|
+
|
130
|
+
assert_select '#users tbody tr td ul.actions' do
|
131
|
+
assert_select 'li a.record-link', 'foo'
|
132
|
+
assert_select 'li a.record-link', 'bar'
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_rendering_column_headers
|
137
|
+
assert_select "#users" do
|
138
|
+
assert_select "thead" do
|
139
|
+
assert_select "th.name", "Name"
|
140
|
+
assert_select "th.email", "Email"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_rendering_rows
|
146
|
+
assert_select "#users tbody" do
|
147
|
+
assert_select "tr:nth-child(1)" do
|
148
|
+
assert_select 'td.name', 'foo'
|
149
|
+
assert_select 'td.email', 'foo@example.com'
|
150
|
+
end
|
151
|
+
assert_select "tr:nth-child(2)" do
|
152
|
+
assert_select 'td.name', 'bar'
|
153
|
+
assert_select 'td.email', 'bar@example.com'
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_rendering_no_rows
|
159
|
+
@presentation.presentable = []
|
160
|
+
assert_select "#users tbody" do
|
161
|
+
assert_select "tr", 1
|
162
|
+
assert_select "tr td", "No records found."
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def test_rendering_sanitized_data
|
167
|
+
@presentation.fields['Name'].sanitize = true
|
168
|
+
@presentation.fields['Email'].sanitize = false
|
169
|
+
@records << stub('row', :name => '&', :email => '&')
|
170
|
+
|
171
|
+
assert_select "#users tbody tr" do
|
172
|
+
assert_select 'td.name', '&'
|
173
|
+
assert_select 'td.email', '&'
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_rendering_sanitized_arrays
|
178
|
+
@records << stub('row', :name => ['bob', '&', 'lucy'], :email => '')
|
179
|
+
|
180
|
+
assert_select "#users tbody tr" do
|
181
|
+
assert_select 'td.name' do
|
182
|
+
assert_select 'ol li:nth-child(2)', '&'
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_rendering_with_pagination
|
188
|
+
@presentation.presentable = WillPaginate::Collection.new(1, 1, 2)
|
189
|
+
assert_select '#users tfoot .pagination'
|
190
|
+
end
|
191
|
+
|
192
|
+
def test_rendering_sortable_columns
|
193
|
+
@presentation.fields.each{|f| f.sortable = true}
|
194
|
+
|
195
|
+
assert_select "#users thead" do
|
196
|
+
assert_select "th a.sortable", "Name"
|
197
|
+
assert_select "th a.sortable", "Email"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_rendering_unsortable_columns
|
202
|
+
@presentation.fields.each{|f| f.sortable = false}
|
203
|
+
|
204
|
+
assert_select "#users thead" do
|
205
|
+
assert_select "th", "Name"
|
206
|
+
assert_select "th", "Email"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def test_rendering_a_sorted_column
|
211
|
+
@presentation.fields.each{|f| f.sortable = true}
|
212
|
+
@presentation.controller.request.query_parameters = {"sort" => {'name' => 'desc'}}
|
213
|
+
|
214
|
+
assert_select "#users thead" do
|
215
|
+
assert_select "th a.sortable[href='/?sort%5Bname%5D=asc']", "Name"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
require 'action_view/test_case'
|
3
|
+
|
4
|
+
class Presenting::HelpersTest < ActionView::TestCase
|
5
|
+
|
6
|
+
def test_presenting_a_boolean
|
7
|
+
assert_equal 'False', present(false)
|
8
|
+
assert_equal 'True', present(true)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_presenting_a_nil
|
12
|
+
assert_equal "", present(nil)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_presenting_an_array_creates_an_ordered_list
|
16
|
+
assert present(['hello', 'world']) =~ %r|^<ol>.*</ol>$|
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_presenting_an_array_presents_the_members
|
20
|
+
assert present([true]).include?("<li>True</li>")
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_presenting_a_hash_creates_a_definition_list
|
24
|
+
assert present({1 => 'a'}) =~ %r|^<dl>.*</dl>$|
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_presenting_a_hash_sorts_by_hash_keys
|
28
|
+
assert present({1 => 'a', 4 => 'd', 3 => 'c', 2 => 'b'}) =~ /^.*a.*b.*c.*d.*$/
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_presenting_a_hash_presents_the_values
|
32
|
+
assert present({1 => true}).include?("<dd>True</dd>")
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_presenting_a_time
|
36
|
+
assert_equal 'Fri, 13 Feb 2009 02:31:00 -0800', present(Time.parse('02/13/2009 02:31 AM').to_time)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_presenting_a_date
|
40
|
+
assert_equal '2009-02-13', present(Time.parse('02/13/2009 02:31 AM').to_date)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_presenting_a_string
|
44
|
+
assert_equal "hello world", present("hello world")
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_presenting_a_named_method
|
48
|
+
assert_equal "<span>hello world</span>", present('hello world', :in_a_span)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_presenting_a_symbol
|
52
|
+
assert_equal "<span></span>", present(:in_a_span)
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_presenting_a_named_presentation
|
56
|
+
self.expects(:controller).returns(TestController.new)
|
57
|
+
Presentation::Grid.any_instance.expects(:render)
|
58
|
+
present('hello', :grid)
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_presenting_an_unknown_presentation
|
62
|
+
assert_raises ArgumentError do
|
63
|
+
present(@users, :unknown)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
|
69
|
+
def present_in_a_span(str, options = {})
|
70
|
+
"<span>#{str}</span>"
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class PresentationTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_rendering
|
6
|
+
# TODO: create a "hello world" test-only setup so i can test rendering
|
7
|
+
@p = Presentation::Grid.new(:id => "hello_world")
|
8
|
+
@p.presentable = []
|
9
|
+
@p.controller = TestController.new
|
10
|
+
assert_nothing_raised do
|
11
|
+
assert @p.render
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Filters added to this controller apply to all controllers in the application.
|
2
|
+
# Likewise, all the methods added will be available for all controllers.
|
3
|
+
|
4
|
+
class ApplicationController < ActionController::Base
|
5
|
+
helper :all # include all helpers, all the time
|
6
|
+
|
7
|
+
# See ActionController::RequestForgeryProtection for details
|
8
|
+
# Uncomment the :secret if you're not using the cookie session store
|
9
|
+
protect_from_forgery # :secret => '0ede37e7d2f6d8445f151b0a38ee0539'
|
10
|
+
|
11
|
+
# See ActionController::Base for details
|
12
|
+
# Uncomment this to filter the contents of submitted sensitive data parameters
|
13
|
+
# from your application log (in this case, all fields with names like "password").
|
14
|
+
# filter_parameter_logging :password
|
15
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class UsersController < ApplicationController
|
2
|
+
def index
|
3
|
+
@users = User.paginate(
|
4
|
+
:page => params[:page],
|
5
|
+
:per_page => 2,
|
6
|
+
:conditions => Presenting::Search.new(:fields => {
|
7
|
+
'first_name' => :equals,
|
8
|
+
'last_name' => :begins_with,
|
9
|
+
'email' => :not_null
|
10
|
+
}).to_sql(params[:search], :field),
|
11
|
+
:order => Presenting::Sorting.new(:fields => [
|
12
|
+
:prefix,
|
13
|
+
:first_name,
|
14
|
+
:last_name,
|
15
|
+
:email
|
16
|
+
]).to_sql(params[:sort])
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
def new
|
21
|
+
@user = User.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def create
|
25
|
+
@user = User.new(params[:user])
|
26
|
+
@user.save!
|
27
|
+
|
28
|
+
redirect_to users_path
|
29
|
+
rescue ActiveRecord::RecordInvalid
|
30
|
+
render :action => :new
|
31
|
+
end
|
32
|
+
|
33
|
+
def show
|
34
|
+
@user = User.find(params[:id])
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
2
|
+
<html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'>
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
5
|
+
<title>Demo Application</title>
|
6
|
+
<%= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" %>
|
7
|
+
<%= javascript_include_tag 'jquery.livequery.min' %>
|
8
|
+
<%= presentation_stylesheets('grid', 'search', 'details', 'grid-color', 'search-color', 'details-color') %>
|
9
|
+
<%= presentation_javascript('search') %>
|
10
|
+
<head>
|
11
|
+
<body>
|
12
|
+
<%= yield %>
|
13
|
+
</body>
|
14
|
+
</html>
|
15
|
+
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<%= present :field_search, :fields => [:first_name, :last_name, {:email => :checkbox}] %>
|
2
|
+
<%= present @users, :grid, :id => "users",
|
3
|
+
:fields => [:prefix, :first_name, :last_name, :email],
|
4
|
+
:links => [link_to('add', new_user_path)],
|
5
|
+
:record_links => [
|
6
|
+
proc{|r| link_to 'edit', edit_user_path(r)},
|
7
|
+
proc{|r| link_to 'delete', user_path(r), :method => :destroy},
|
8
|
+
proc{|r| link_to 'show', user_path(r)}
|
9
|
+
]
|
10
|
+
%>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= present @user, :details, :title => "User ##{@user.id}", :fields => [:prefix, :first_name, :last_name, :email] %>
|