any_view 0.1.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/.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
|