any_view 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +47 -0
- data/README.rdoc +369 -0
- data/Rakefile +57 -0
- data/lib/any_view/asset_tag_helpers.rb +103 -0
- data/lib/any_view/core_ext/array.rb +7 -0
- data/lib/any_view/core_ext/hash.rb +41 -0
- data/lib/any_view/core_ext/string.rb +17 -0
- data/lib/any_view/form_builder/abstract_form_builder.rb +128 -0
- data/lib/any_view/form_builder/standard_form_builder.rb +37 -0
- data/lib/any_view/form_helpers.rb +217 -0
- data/lib/any_view/format_helpers.rb +49 -0
- data/lib/any_view/tag_helpers.rb +47 -0
- data/lib/any_view/tilt_base.rb +94 -0
- data/lib/any_view.rb +30 -0
- data/test/fixtures/basic_form_for.erb +3 -0
- data/test/fixtures/builder_type_form_for.erb +3 -0
- data/test/fixtures/capture_concat.erb +14 -0
- data/test/fixtures/capture_concat.haml +13 -0
- data/test/fixtures/content_for.erb +11 -0
- data/test/fixtures/content_for.haml +9 -0
- data/test/fixtures/content_tag.erb +11 -0
- data/test/fixtures/content_tag.haml +9 -0
- data/test/fixtures/delete_form_for.erb +3 -0
- data/test/fixtures/field_set_tag.erb +3 -0
- data/test/fixtures/fields_for.erb +8 -0
- data/test/fixtures/fields_for.haml +6 -0
- data/test/fixtures/fields_for_basic.erb +3 -0
- data/test/fixtures/fields_for_nil.erb +3 -0
- data/test/fixtures/form_for.erb +56 -0
- data/test/fixtures/form_for.haml +47 -0
- data/test/fixtures/form_for_nil.erb +3 -0
- data/test/fixtures/form_tag.erb +57 -0
- data/test/fixtures/form_tag.haml +45 -0
- data/test/fixtures/form_tag_methods.erb +19 -0
- data/test/fixtures/form_tag_methods.haml +15 -0
- data/test/fixtures/link_to.erb +5 -0
- data/test/fixtures/link_to.haml +4 -0
- data/test/fixtures/mail_to.erb +3 -0
- data/test/fixtures/mail_to.haml +3 -0
- data/test/fixtures/multipart.erb +12 -0
- data/test/fixtures/multipart_form_for.erb +3 -0
- data/test/fixtures/put_form_for.erb +3 -0
- data/test/fixtures/standard_form_builder.erb +3 -0
- data/test/helper.rb +121 -0
- data/test/test_asset_tag_helpers.rb +176 -0
- data/test/test_form_builder.rb +607 -0
- data/test/test_form_helpers.rb +453 -0
- data/test/test_format_helpers.rb +59 -0
- data/test/test_tag_helpers.rb +65 -0
- metadata +160 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
Copyright (c) 2009 Daniel Neighman
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
This software is hevily based on the Pardino framework helpers and as such is bound by it's licence agreement reproduced below.
|
23
|
+
|
24
|
+
------------------------------------------------------------------------
|
25
|
+
|
26
|
+
Copyright (c) 2009 Padrino
|
27
|
+
|
28
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
29
|
+
a copy of this software and associated documentation files (the
|
30
|
+
"Software"), to deal in the Software without restriction, including
|
31
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
32
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
33
|
+
permit persons to whom the Software is furnished to do so, subject to
|
34
|
+
the following conditions:
|
35
|
+
|
36
|
+
The above copyright notice and this permission notice shall be
|
37
|
+
included in all copies or substantial portions of the Software.
|
38
|
+
|
39
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
40
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
41
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
42
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
43
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
44
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
45
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
46
|
+
|
47
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,369 @@
|
|
1
|
+
= AnyView
|
2
|
+
|
3
|
+
The AnyView gem provides helpers for common web related view rendering. The AnyView gem is a collection of mixins that work together to provide tags, forms asset paths and more. AnyView is based heavily on the Padrino framework helpers module.
|
4
|
+
|
5
|
+
The requirements of AnyView are kept very small. There's two required methods inside your view context.
|
6
|
+
|
7
|
+
capture_content(*args, &block)
|
8
|
+
|
9
|
+
and
|
10
|
+
|
11
|
+
concat_content(string, opts ={})
|
12
|
+
|
13
|
+
By implementing these two methods on your view context, you're able to get just about all the view helpers in anyview including form_for helpers.
|
14
|
+
|
15
|
+
== Installation
|
16
|
+
|
17
|
+
$ sudo gem install any_view
|
18
|
+
|
19
|
+
This will install the required gems. Next, simply include the AnyView module into your view context
|
20
|
+
|
21
|
+
class ViewContext
|
22
|
+
include AnyView
|
23
|
+
end
|
24
|
+
|
25
|
+
If you're using Tilt, then AnyView can provide the capture_content and concat_content helpers too. These will work for erubis, erb and haml templates.
|
26
|
+
|
27
|
+
class ViewContext
|
28
|
+
include AnyView::TiltBase
|
29
|
+
include AnyView
|
30
|
+
end
|
31
|
+
|
32
|
+
A full setup for a custom class, including rendering the tilt templates might look like this:
|
33
|
+
|
34
|
+
class Renderer
|
35
|
+
def self.path
|
36
|
+
@path ||= File.expand_path(~'./views')
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.template(name)
|
40
|
+
@templates ||= {}
|
41
|
+
@templates[name] ||= Tilt.new(File.join(path, name))
|
42
|
+
@templates[name]
|
43
|
+
end
|
44
|
+
|
45
|
+
def template(name)
|
46
|
+
self.class.template(name)
|
47
|
+
end
|
48
|
+
|
49
|
+
def render(name, locals = {})
|
50
|
+
template(name).render(ViewContext.new, locals)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
Usage would be as simple as
|
56
|
+
Renderer.new.render("my_template.erb")
|
57
|
+
|
58
|
+
== Usage
|
59
|
+
|
60
|
+
=== Tag Helpers
|
61
|
+
|
62
|
+
Tag helpers are the basic building blocks used to construct html 'tags' within a view template. There
|
63
|
+
are three major functions for this category: <tt>tag</tt>, <tt>content_tag</tt> and <tt>input_tag</tt>.
|
64
|
+
|
65
|
+
The tag and content_tag are for building arbitrary html tags with a name and specified options. If
|
66
|
+
the tag contains 'content' within then <tt>content_tag</tt> is used. For example:
|
67
|
+
|
68
|
+
tag(:br, :style => ‘clear:both’) => <br style="clear:both" />
|
69
|
+
content_tag(:p, "demo", :class => ‘light’) => <p class="light">demo</p>
|
70
|
+
|
71
|
+
The input_tag is used to build tags that are related to accepting input from the user:
|
72
|
+
|
73
|
+
input_tag :text, :class => "demo" => <input type='text' class='demo' />
|
74
|
+
input_tag :password, :value => "secret", :class => "demo"
|
75
|
+
|
76
|
+
Note that all of these accept html options and result in returning a string containing html tags.
|
77
|
+
|
78
|
+
The list of defined helpers in the 'tag helpers' category:
|
79
|
+
|
80
|
+
* <tt>tag(name, options={})</tt>
|
81
|
+
* Creates an html tag with the given name and options
|
82
|
+
* <tt>tag(:br, :style => 'clear:both')</tt> => <br style="clear:both" />
|
83
|
+
* <tt>tag(:p, :content => "demo", :class => 'large')</tt> => <p class="large">demo</p>
|
84
|
+
* <tt>content_tag(name, content, options={})</tt>
|
85
|
+
* Creates an html tag with given name, content and options
|
86
|
+
* <tt>content_tag(:p, "demo", :class => 'light')</tt> => <p class="light">demo</p>
|
87
|
+
* <tt>content_tag(:p, :class => 'dark') { ...content... }</tt> => <p class="dark">...content...</p>
|
88
|
+
* <tt>input_tag(type, options = {})</tt>
|
89
|
+
* Creates an html input field with given type and options
|
90
|
+
* <tt>input_tag :text, :class => "demo"</tt>
|
91
|
+
* <tt>input_tag :password, :value => "secret", :class => "demo"</tt>
|
92
|
+
|
93
|
+
=== Asset Helpers
|
94
|
+
|
95
|
+
Asset helpers are intended to help insert useful html onto a view template such as stylesheet link tags ,
|
96
|
+
hyperlinks, mail_to links, images, stylesheets and javascript. An example of their uses would be on a
|
97
|
+
simple view template:
|
98
|
+
|
99
|
+
# app/views/example.haml
|
100
|
+
...
|
101
|
+
%head
|
102
|
+
= stylesheet_link_tag 'layout'
|
103
|
+
= javascript_include_tag 'application'
|
104
|
+
%body
|
105
|
+
...
|
106
|
+
%p= link_to 'Blog', '/blog', :class => 'example'
|
107
|
+
%p Mail me at #{mail_to 'fake@faker.com', "Fake Email Link", :cc => "test@demo.com"}
|
108
|
+
%p= image_tag 'padrino.png', :width => '35', :class => 'logo'
|
109
|
+
|
110
|
+
The list of defined helpers in the 'asset helpers' category:
|
111
|
+
|
112
|
+
* <tt>link_to(*args, &block)</tt>
|
113
|
+
* Creates a link element with given name, url and options
|
114
|
+
* <tt>link_to 'click me', '/dashboard', :class => 'linky'</tt>
|
115
|
+
* <tt>link_to('/dashboard', :class => 'blocky') { ...content... }</tt>
|
116
|
+
* <tt>mail_to(email, caption=nil, mail_options={})</tt>
|
117
|
+
* Creates a mailto link tag to the specified email_address
|
118
|
+
* <tt>mail_to "me@demo.com"</tt>
|
119
|
+
* <tt>mail_to "me@demo.com", "My Email", :subject => "Feedback", :cc => 'test@demo.com'</tt>
|
120
|
+
* <tt>image_tag(url, options={})</tt>
|
121
|
+
* Creates an image element with given url and options
|
122
|
+
* <tt>image_tag('icons/avatar.png')</tt>
|
123
|
+
* <tt>stylesheet_link_tag(*sources)</tt>
|
124
|
+
* Returns a stylesheet link tag for the sources specified as arguments
|
125
|
+
* <tt>stylesheet_link_tag 'style', 'application', 'layout'</tt>
|
126
|
+
* <tt>javascript_include_tag(*sources)</tt>
|
127
|
+
* Returns an html script tag for each of the sources provided.
|
128
|
+
* <tt>javascript_include_tag 'application', 'special'</tt>
|
129
|
+
|
130
|
+
To make use of these in a situation where you're application is in a mounted url space, you should include a method +uri_root+ in your view_context. This allows you to put a uri prifix on the "/stylesheets/my_style.css" relative url
|
131
|
+
|
132
|
+
=== Form Helpers
|
133
|
+
|
134
|
+
Form helpers are the 'standard' form tag helpers you would come to expect when building forms. A simple
|
135
|
+
example of constructing a non-object form would be:
|
136
|
+
|
137
|
+
- form_tag '/destroy', :class => 'destroy-form', :method => :delete do
|
138
|
+
- field_set_tag do
|
139
|
+
%p
|
140
|
+
= label_tag :username, :class => 'first'
|
141
|
+
= text_field_tag :username, :value => params[:username]
|
142
|
+
%p
|
143
|
+
= label_tag :password, :class => 'first'
|
144
|
+
= password_field_tag :password, :value => params[:password]
|
145
|
+
%p
|
146
|
+
= label_tag :strategy
|
147
|
+
= select_tag :strategy, :options => ['delete', 'destroy'], :selected => 'delete'
|
148
|
+
%p
|
149
|
+
= check_box_tag :confirm_delete
|
150
|
+
- field_set_tag(:class => 'buttons') do
|
151
|
+
= submit_tag "Remove"
|
152
|
+
|
153
|
+
The list of defined helpers in the 'form helpers' category:
|
154
|
+
|
155
|
+
* <tt>form_tag(url, options={}, &block)</tt>
|
156
|
+
* Constructs a form without object based on options
|
157
|
+
* Supports form methods 'put' and 'delete' through hidden field
|
158
|
+
* <tt>form_tag('/register', :class => 'example') { ... }</tt>
|
159
|
+
* <tt>field_set_tag(*args, &block)</tt>
|
160
|
+
* Constructs a field_set to group fields with given options
|
161
|
+
* <tt>field_set_tag(:class => 'office-set') { }</tt>
|
162
|
+
* <tt>field_set_tag("Office", :class => 'office-set') { }</tt>
|
163
|
+
* <tt>error_messages_for(record, options={})</tt>
|
164
|
+
* Constructs list html for the errors for a given object
|
165
|
+
* <tt>error_messages_for @user</tt>
|
166
|
+
* <tt>label_tag(name, options={}, &block)</tt>
|
167
|
+
* Constructs a label tag from the given options
|
168
|
+
* <tt>label_tag :username, :class => 'long-label'</tt>
|
169
|
+
* <tt>label_tag(:username, :class => 'blocked-label') { ... }</tt>
|
170
|
+
* <tt>hidden_field_tag(name, options={})</tt>
|
171
|
+
* Constructs a hidden field input from the given options
|
172
|
+
* <tt>hidden_field_tag :session_key, :value => 'secret'</tt>
|
173
|
+
* <tt>text_field_tag(name, options={})</tt>
|
174
|
+
* Constructs a text field input from the given options
|
175
|
+
* <tt>text_field_tag :username, :class => 'long'</tt>
|
176
|
+
* <tt>text_area_tag(name, options={})</tt>
|
177
|
+
* Constructs a text area input from the given options
|
178
|
+
* <tt>text_area_tag :username, :class => 'long'</tt>
|
179
|
+
* <tt>password_field_tag(name, options={})</tt>
|
180
|
+
* Constructs a password field input from the given options
|
181
|
+
* <tt>password_field_tag :password, :class => 'long'</tt>
|
182
|
+
* <tt>check_box_tag(name, options={})</tt>
|
183
|
+
* Constructs a checkbox input from the given options
|
184
|
+
* <tt>check_box_tag :remember_me, :checked => true</tt>
|
185
|
+
* <tt>radio_button_tag(name, options={})</tt>
|
186
|
+
* Constructs a radio button input from the given options
|
187
|
+
* <tt>radio_button_tag :gender, :value => 'male'</tt>
|
188
|
+
* <tt>select_tag(name, settings={})</tt>
|
189
|
+
* Constructs a select tag with options from the given settings
|
190
|
+
* <tt>select_tag(:favorite_color, :options => ['1', '2', '3'], :selected => '1')</tt>
|
191
|
+
* <tt>select_tag(:more_color, :options => [['label', '1'], ['label2', '2']])</tt>
|
192
|
+
* <tt>select_tag(:multiple_color, :options => [...], :multiple => true)</tt>
|
193
|
+
* <tt>file_field_tag(name, options={})</tt>
|
194
|
+
* Constructs a file field input from the given options
|
195
|
+
* <tt>file_field_tag :photo, :class => 'long'</tt>
|
196
|
+
* <tt>submit_tag(caption, options={})</tt>
|
197
|
+
* Constructs a submit button from the given options
|
198
|
+
* <tt>submit_tag "Create", :class => 'success'</tt>
|
199
|
+
* <tt>button_tag(caption, options={})</tt>
|
200
|
+
* Constructs an input (type => 'button') from the given options
|
201
|
+
* <tt>button_tag "Cancel", :class => 'clear'</tt>
|
202
|
+
* <tt>image_submit_tag(source, options={})</tt>
|
203
|
+
* Constructs an image submit button from the given options
|
204
|
+
* <tt>image_submit_tag "submit.png", :class => 'success'</tt>
|
205
|
+
|
206
|
+
=== FormBuilders
|
207
|
+
|
208
|
+
Form builders are full-featured objects allowing the construction of complex object-based forms
|
209
|
+
using a simple, intuitive syntax.
|
210
|
+
|
211
|
+
A form_for using these basic fields might look like:
|
212
|
+
|
213
|
+
- form_for @user, '/register', :id => 'register' do |f|
|
214
|
+
= f.error_messages
|
215
|
+
%p
|
216
|
+
= f.label :username, :caption => "Nickname"
|
217
|
+
= f.text_field :username
|
218
|
+
%p
|
219
|
+
= f.label :email
|
220
|
+
= f.text_field :email
|
221
|
+
%p
|
222
|
+
= f.label :password
|
223
|
+
= f.password_field :password
|
224
|
+
%p
|
225
|
+
= f.label :is_admin, :caption => "Admin User?"
|
226
|
+
= f.check_box :is_admin
|
227
|
+
%p
|
228
|
+
= f.label :color, :caption => "Favorite Color?"
|
229
|
+
= f.select :color, :options => ['red', 'black']
|
230
|
+
%p
|
231
|
+
- fields_for @user.location do |location|
|
232
|
+
= location.text_field :street
|
233
|
+
= location.text_field :city
|
234
|
+
%p
|
235
|
+
= f.submit "Create", :class => 'button'
|
236
|
+
|
237
|
+
The list of defined helpers in the 'form builders' category:
|
238
|
+
|
239
|
+
* <tt>form_for(object, url, settings={}, &block)</tt>
|
240
|
+
* Constructs a form using given or default form_builder
|
241
|
+
* Supports form methods 'put' and 'delete' through hidden field
|
242
|
+
* Defaults to StandardFormBuilder but you can easily create your own!
|
243
|
+
* <tt>form_for(@user, '/register', :id => 'register') { |f| ...field-elements... }</tt>
|
244
|
+
* <tt>fields_for(object, settings={}, &block)</tt>
|
245
|
+
* Constructs fields for a given object for use in an existing form
|
246
|
+
* Defaults to StandardFormBuilder but you can easily create your own!
|
247
|
+
* <tt>fields_for @user.assignment do |assignment| ... end</tt>
|
248
|
+
* <tt>fields_for :assignment do |assigment| ... end</tt>
|
249
|
+
|
250
|
+
The following are fields provided by AbstractFormBuilder that can be used within a form_for or fields_for:
|
251
|
+
|
252
|
+
* <tt>error_messages(options={})</tt>
|
253
|
+
* Displays list html for the errors on form object
|
254
|
+
* <tt>f.errors_messages</tt>
|
255
|
+
* <tt>label(field, options={})</tt>
|
256
|
+
* <tt>f.label :name, :class => 'long'</tt>
|
257
|
+
* <tt>text_field(field, options={})</tt>
|
258
|
+
* <tt>f.text_field :username, :class => 'long'</tt>
|
259
|
+
* <tt>check_box(field, options={})</tt>
|
260
|
+
* Uses hidden field to provide a 'unchecked' value for field
|
261
|
+
* <tt>f.check_box :remember_me, :uncheck_value => 'false'</tt>
|
262
|
+
* <tt>radio_button(field, options={})</tt>
|
263
|
+
* <tt>f.radio_button :gender, :value => 'male'</tt>
|
264
|
+
* <tt>hidden_field(field, options={})</tt>
|
265
|
+
* <tt>f.hidden_field :session_id, :class => 'hidden'</tt>
|
266
|
+
* <tt>text_area(field, options={})</tt>
|
267
|
+
* <tt>f.text_area :summary, :class => 'long'</tt>
|
268
|
+
* <tt>password_field(field, options={})</tt>
|
269
|
+
* <tt>f.password_field :secret, :class => 'long'</tt>
|
270
|
+
* <tt>file_field(field, options={})</tt>
|
271
|
+
* <tt>f.file_field :photo, :class => 'long'</tt>
|
272
|
+
* <tt>select(field, options={})</tt>
|
273
|
+
* <tt>f.select(:state, :options => ['California', 'Texas', 'Wyoming'])</tt>
|
274
|
+
* <tt>f.select(:state, :collection => @states, :fields => [:name, :id])</tt>
|
275
|
+
* <tt>f.select(:state, :options => [...], :include_blank => true)</tt>
|
276
|
+
* <tt>submit(caption, options={})</tt>
|
277
|
+
* <tt>f.submit "Update", :class => 'long'</tt>
|
278
|
+
* <tt>image_submit(source, options={})</tt>
|
279
|
+
* <tt>f.image_submit "submit.png", :class => 'long'</tt>
|
280
|
+
|
281
|
+
There is also an additional StandardFormBuilder which builds on the abstract fields that can be used within a form_for.
|
282
|
+
|
283
|
+
A form_for using these standard fields might be:
|
284
|
+
|
285
|
+
- form_for @user, '/register', :id => 'register' do |f|
|
286
|
+
= f.error_messages
|
287
|
+
= f.text_field_block :name, :caption => "Full name"
|
288
|
+
= f.text_field_block :email
|
289
|
+
= f.check_box_block :remember_me
|
290
|
+
= f.select_block :fav_color, :options => ['red', 'blue']
|
291
|
+
= f.password_field_block :password
|
292
|
+
= f.submit_block "Create", :class => 'button'
|
293
|
+
|
294
|
+
and would generate this html (with each input contained in a paragraph and containing a label):
|
295
|
+
|
296
|
+
<form id="register" action="/register" method="post">
|
297
|
+
<p><label for="user_name">Full name: </label><input type="text" id="user_name" name="user[name]"></p>
|
298
|
+
...omitted...
|
299
|
+
<p><input type="submit" value="Create" class="button"></p>
|
300
|
+
</form>
|
301
|
+
|
302
|
+
The following are fields provided by StandardFormBuilder that can be used within a form_for or fields_for:
|
303
|
+
|
304
|
+
* <tt>text_field_block(field, options={}, label_options={})</tt>
|
305
|
+
* <tt>text_field_block(:nickname, :class => 'big', :caption => "Username")</tt>
|
306
|
+
* <tt>text_area_block(field, options={}, label_options={})</tt>
|
307
|
+
* <tt>text_area_block(:about, :class => 'big')</tt>
|
308
|
+
* <tt>password_field_block(field, options={}, label_options={})</tt>
|
309
|
+
* <tt>password_field_block(:code, :class => 'big')</tt>
|
310
|
+
* <tt>file_field_block(field, options={}, label_options={})</tt>
|
311
|
+
* <tt>file_field_block(:photo, :class => 'big')</tt>
|
312
|
+
* <tt>check_box_block(field, options={}, label_options={})</tt>
|
313
|
+
* <tt>check_box_block(:remember_me, :class => 'big')</tt>
|
314
|
+
* <tt>select_block(field, options={}, label_options={})</tt>
|
315
|
+
* <tt>select_block(:country, :option => ['USA', 'Canada'])</tt>
|
316
|
+
* <tt>submit_block(caption, options={})</tt>
|
317
|
+
* <tt>submit_block(:username, :class => 'big')</tt>
|
318
|
+
* <tt>image_submit_block(source, options={})</tt>
|
319
|
+
* <tt>image_submit_block('submit.png', :class => 'big')</tt>
|
320
|
+
|
321
|
+
You can also easily build your own FormBuilder which allows for customized fields and behavior:
|
322
|
+
|
323
|
+
class MyCustomFormBuilder < AbstractFormBuilder
|
324
|
+
# Here we have access to a number of useful variables
|
325
|
+
#
|
326
|
+
# * view_context (use this to invoke any helpers)(ex. view_context.hidden_field_tag(...))
|
327
|
+
# * object (the record for this form) (ex. object.valid?)
|
328
|
+
# * object_name (object's underscored type) (ex. object_name => 'admin_user')
|
329
|
+
#
|
330
|
+
# We also have access to self.field_types => [:text_field, :text_area, ...]
|
331
|
+
# In addition, we have access to all the existing field tag helpers (text_field, hidden_field, file_field, ...)
|
332
|
+
end
|
333
|
+
|
334
|
+
Once a custom builder is defined, any call to form_for can use the new builder:
|
335
|
+
|
336
|
+
- form_for @user, '/register', :builder => MyCustomFormBuilder, :id => 'register' do |f|
|
337
|
+
...fields here...
|
338
|
+
|
339
|
+
=== Format Helpers
|
340
|
+
|
341
|
+
Format helpers are several useful utilities for manipulating the format of text to achieve a goal.
|
342
|
+
The format helper <tt>escape_html</tt> is also aliased as <tt>h</tt> and <tt>sanitize_html</tt>
|
343
|
+
|
344
|
+
The escape_html function is for taking an html string and escaping certain characters.
|
345
|
+
<tt>escape_html</tt> will escape ampersands, brackets and quotes to their HTML/XML entities. This is useful
|
346
|
+
to sanitize user content before displaying this on a template.
|
347
|
+
|
348
|
+
escape_html('<hello>&<goodbye>') # => <hello>&<goodbye>
|
349
|
+
|
350
|
+
Format helpers also includes a number of useful text manipulation functions such as <tt>simple_format</tt>, and <tt>truncate</tt>.
|
351
|
+
|
352
|
+
simple_format("hello\nworld") # => "<p>hello<br/>world</p>"
|
353
|
+
truncate("Once upon a time in a world far far away", :length => 8) => "Once upon..."
|
354
|
+
|
355
|
+
The list of defined helpers in the 'format helpers' category:
|
356
|
+
|
357
|
+
* <tt>simple_format(text, html_options)</tt>
|
358
|
+
* Returns text transformed into HTML using simple formatting rules.
|
359
|
+
* <tt>simple_format("hello\nworld")</tt> => "<p>hello<br/>world</p>"
|
360
|
+
* <tt>truncate(text, *args)</tt>
|
361
|
+
* Truncates a given text after a given :length if text is longer than :length (defaults to 30).
|
362
|
+
* <tt>truncate("Once upon a time in a world far far away", :length => 8)</tt> => "Once upon..."
|
363
|
+
* <tt>escape_html</tt> (alias <tt>h</tt> and <tt>h!</tt>)
|
364
|
+
* (from RackUtils) Escape ampersands, brackets and quotes to their HTML/XML entities.
|
365
|
+
|
366
|
+
== Copyright
|
367
|
+
|
368
|
+
Copyright (c) 2009 Daniel Neighman. See LICENSE for details.
|
369
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "any_view"
|
8
|
+
gem.summary = %Q{View helpers designed to work just about anywhere}
|
9
|
+
gem.description = %Q{View helpers with an absolute minimum of requirements}
|
10
|
+
gem.email = "has.sox@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/hassox/any_view"
|
12
|
+
gem.authors = ["Daniel Neighman"]
|
13
|
+
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
14
|
+
gem.add_development_dependency "haml", ">= 2.2.1"
|
15
|
+
gem.add_development_dependency "shoulda", ">= 0"
|
16
|
+
gem.add_development_dependency "rack-test", ">= 0.5.0"
|
17
|
+
gem.add_development_dependency "webrat", ">= 0.5.1"
|
18
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
19
|
+
end
|
20
|
+
Jeweler::GemcutterTasks.new
|
21
|
+
rescue LoadError
|
22
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'rake/testtask'
|
26
|
+
Rake::TestTask.new(:test) do |test|
|
27
|
+
test.libs << 'lib' << 'test'
|
28
|
+
test.pattern = 'test/**/test_*.rb'
|
29
|
+
test.verbose = true
|
30
|
+
end
|
31
|
+
|
32
|
+
begin
|
33
|
+
require 'rcov/rcovtask'
|
34
|
+
Rcov::RcovTask.new do |test|
|
35
|
+
test.libs << 'test'
|
36
|
+
test.pattern = 'test/**/test_*.rb'
|
37
|
+
test.verbose = true
|
38
|
+
end
|
39
|
+
rescue LoadError
|
40
|
+
task :rcov do
|
41
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
task :test => :check_dependencies
|
46
|
+
|
47
|
+
task :default => :test
|
48
|
+
|
49
|
+
require 'rake/rdoctask'
|
50
|
+
Rake::RDocTask.new do |rdoc|
|
51
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
52
|
+
|
53
|
+
rdoc.rdoc_dir = 'rdoc'
|
54
|
+
rdoc.title = "any_view #{version}"
|
55
|
+
rdoc.rdoc_files.include('README*')
|
56
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
57
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module AnyView
|
2
|
+
module Helpers
|
3
|
+
module AssetTagHelpers
|
4
|
+
MAIL_ATTRIBUTES = [:cc, :bcc, :subject, :body]
|
5
|
+
|
6
|
+
# Creates a link element with given name, url and options
|
7
|
+
# link_to("/url", :class => "foo"){ "link text" }
|
8
|
+
# link_to 'click me', '/dashboard', :class => 'linky'
|
9
|
+
def link_to(*args, &block)
|
10
|
+
options = args.extract_options!
|
11
|
+
text, url = args
|
12
|
+
if url.nil?
|
13
|
+
url = text
|
14
|
+
text = capture_content(&block)
|
15
|
+
end
|
16
|
+
options.reverse_merge!(:href => url)
|
17
|
+
options[:content] = text
|
18
|
+
result = tag(:a, options)
|
19
|
+
block.nil? ? result : concat_content(result)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Creates a mail link element with given name and caption
|
23
|
+
# mail_to "me@demo.com" => <a href="mailto:me@demo.com">me@demo.com</a>
|
24
|
+
# mail_to "me@demo.com", "My Email" => <a href="mailto:me@demo.com">My Email</a>
|
25
|
+
def mail_to(email, caption=nil, options={})
|
26
|
+
mail_options, options = options.partition{|k,v| MAIL_ATTRIBUTES.include?(k)}
|
27
|
+
mail_options, options = Hash[mail_options], Hash[options]
|
28
|
+
mail_query = Rack::Utils.build_query(mail_options).gsub(/\+/, '%20').gsub('%40', '@')
|
29
|
+
mail_href = "mailto:#{email}"; mail_href << "?#{mail_query}" if mail_query.present?
|
30
|
+
link_to (caption || email), mail_href, options
|
31
|
+
end
|
32
|
+
|
33
|
+
# Creates an image element with given url and options
|
34
|
+
# image_tag('icons/avatar.png')
|
35
|
+
def image_tag(url, options={})
|
36
|
+
options.reverse_merge!(:src => image_path(url))
|
37
|
+
tag(:img, options)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns a stylesheet link tag for the sources specified as arguments
|
41
|
+
# stylesheet_link_tag 'style', 'application', 'layout'
|
42
|
+
def stylesheet_link_tag(*sources)
|
43
|
+
options = sources.extract_options!.symbolize_keys
|
44
|
+
sources.collect { |sheet| stylesheet_tag(sheet, options) }.join("\n")
|
45
|
+
end
|
46
|
+
|
47
|
+
# javascript_include_tag 'application', 'special'
|
48
|
+
def javascript_include_tag(*sources)
|
49
|
+
options = sources.extract_options!.symbolize_keys
|
50
|
+
sources.collect { |script| javascript_tag(script, options) }.join("\n")
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns the path to the image, either relative or absolute
|
54
|
+
def image_path(src)
|
55
|
+
src.gsub!(/\s/, '')
|
56
|
+
src =~ %r{^\s*(/|http)} ? src : uri_root_path('images', src)
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
|
61
|
+
# stylesheet_tag('style', :media => 'screen')
|
62
|
+
def stylesheet_tag(source, options={})
|
63
|
+
options = options.dup.reverse_merge!(:href => stylesheet_path(source), :media => 'screen', :rel => 'stylesheet', :type => 'text/css')
|
64
|
+
tag(:link, options)
|
65
|
+
end
|
66
|
+
|
67
|
+
# javascript_tag 'application', :src => '/javascripts/base/application.js'
|
68
|
+
def javascript_tag(source, options={})
|
69
|
+
options = options.dup.reverse_merge!(:src => javascript_path(source), :type => 'text/javascript', :content => "")
|
70
|
+
tag(:script, options)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns the javascript_path appending the default javascripts path if necessary
|
74
|
+
def javascript_path(source)
|
75
|
+
return source if source =~ /^http/
|
76
|
+
source.gsub!(/\.js$/, '')
|
77
|
+
source_name = source; source_name << ".js" unless source =~ /\.js\w{2,4}$/
|
78
|
+
result_path = source_name if source =~ %r{^/} # absolute path
|
79
|
+
result_path ||= uri_root_path("javascripts", source_name)
|
80
|
+
stamp = File.exist?(result_path) ? File.mtime(result_path) : Time.now.to_i
|
81
|
+
"#{result_path}?#{stamp}"
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns the stylesheet_path appending the default stylesheets path if necessary
|
85
|
+
def stylesheet_path(source)
|
86
|
+
return source if source =~ /^http/
|
87
|
+
source.gsub!(/\.css$/, '')
|
88
|
+
source_name = source; source_name << ".css" unless source =~ /\.css$/
|
89
|
+
result_path = source_name if source =~ %r{^/} # absolute path
|
90
|
+
result_path ||= uri_root_path("stylesheets", source_name)
|
91
|
+
stamp = File.exist?(result_path) ? File.mtime(result_path) : Time.now.to_i
|
92
|
+
"#{result_path}?#{stamp}"
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns the uri root of the application, defaulting to '/'
|
96
|
+
# @example uri_root('javascripts')
|
97
|
+
def uri_root_path(*paths)
|
98
|
+
root_uri = uri_root if self.respond_to?(:uri_root)
|
99
|
+
File.join(root_uri || '/', *paths)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class Hash
|
2
|
+
unless method_defined?(:reverse_merge!)
|
3
|
+
def reverse_merge!(other = {})
|
4
|
+
other.each{|k,v| self[k] ||= v}
|
5
|
+
self
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
unless method_defined?(:slice!)
|
10
|
+
def slice!(*keys)
|
11
|
+
keys = keys.flatten
|
12
|
+
out = {}
|
13
|
+
keys.each{|k| out[k] = self[k]}
|
14
|
+
replace out
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def slice(*keys)
|
19
|
+
out = dup
|
20
|
+
out.slice!(*keys)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
unless method_defined?(:symbolize_keys)
|
25
|
+
def symbolize_keys
|
26
|
+
out = dup
|
27
|
+
out.symbolize_keys!
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
unless method_defined?(:symbolize_keys!)
|
32
|
+
def symbolize_keys!
|
33
|
+
symbolizable_keys = []
|
34
|
+
keys.each{|k| symbolizable_keys << k if k.respond_to?(:to_sym) && !k.is_a?(Symbol)}
|
35
|
+
symbolizable_keys.each do |k|
|
36
|
+
self[k.to_sym] = delete(k)
|
37
|
+
end
|
38
|
+
self
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class String
|
2
|
+
unless method_defined?(:titleize)
|
3
|
+
def titleize
|
4
|
+
gsub("_", " ").gsub(/\b('?[a-z])/){$1.upcase}
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
unless method_defined?(:underscore)
|
9
|
+
def underscore
|
10
|
+
gsub(/::/, '/').
|
11
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
12
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
13
|
+
gsub("-", "_").
|
14
|
+
downcase
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|