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
@@ -0,0 +1,128 @@
|
|
1
|
+
module AnyView
|
2
|
+
module Helpers
|
3
|
+
module FormBuilder
|
4
|
+
class AbstractFormBuilder
|
5
|
+
attr_accessor :view_context, :object
|
6
|
+
|
7
|
+
def initialize(view_context, object)
|
8
|
+
@view_context = view_context
|
9
|
+
@object = object
|
10
|
+
raise "FormBuilder view_context must be initialized!" unless view_context
|
11
|
+
raise "FormBuilder object must be not be nil value. If there's no object, use a symbol instead! (i.e :user)" unless object
|
12
|
+
end
|
13
|
+
|
14
|
+
# f.error_messages
|
15
|
+
def error_messages(options={})
|
16
|
+
@view_context.error_messages_for(@object, options)
|
17
|
+
end
|
18
|
+
|
19
|
+
# f.label :username, :caption => "Nickname"
|
20
|
+
def label(field, options={})
|
21
|
+
options.reverse_merge!(:caption => field.to_s.titleize)
|
22
|
+
@view_context.label_tag(field_id(field), options)
|
23
|
+
end
|
24
|
+
|
25
|
+
# f.hidden_field :session_id, :value => "45"
|
26
|
+
def hidden_field(field, options={})
|
27
|
+
options.reverse_merge!(:value => field_value(field), :id => field_id(field))
|
28
|
+
@view_context.hidden_field_tag field_name(field), options
|
29
|
+
end
|
30
|
+
|
31
|
+
# f.text_field :username, :value => "(blank)", :id => 'username'
|
32
|
+
def text_field(field, options={})
|
33
|
+
options.reverse_merge!(:value => field_value(field), :id => field_id(field))
|
34
|
+
@view_context.text_field_tag field_name(field), options
|
35
|
+
end
|
36
|
+
|
37
|
+
# f.text_area :summary, :value => "(enter summary)", :id => 'summary'
|
38
|
+
def text_area(field, options={})
|
39
|
+
options.reverse_merge!(:value => field_value(field), :id => field_id(field))
|
40
|
+
@view_context.text_area_tag field_name(field), options
|
41
|
+
end
|
42
|
+
|
43
|
+
# f.password_field :password, :id => 'password'
|
44
|
+
def password_field(field, options={})
|
45
|
+
options.reverse_merge!(:value => field_value(field), :id => field_id(field))
|
46
|
+
@view_context.password_field_tag field_name(field), options
|
47
|
+
end
|
48
|
+
|
49
|
+
# f.select :color, :options => ['red', 'green'], :include_blank => true
|
50
|
+
# f.select :color, :collection => @colors, :fields => [:name, :id]
|
51
|
+
def select(field, options={})
|
52
|
+
options.reverse_merge!(:id => field_id(field), :selected => field_value(field))
|
53
|
+
@view_context.select_tag field_name(field), options
|
54
|
+
end
|
55
|
+
|
56
|
+
# f.check_box :remember_me, :value => 'true', :uncheck_value => '0'
|
57
|
+
def check_box(field, options={})
|
58
|
+
unchecked_value = options.delete(:uncheck_value) || '0'
|
59
|
+
options.reverse_merge!(:id => field_id(field), :value => '1')
|
60
|
+
options.merge!(:checked => true) if values_matches_field?(field, options[:value])
|
61
|
+
html = @view_context.check_box_tag field_name(field), options
|
62
|
+
html << hidden_field(field, :value => unchecked_value, :id => nil)
|
63
|
+
end
|
64
|
+
|
65
|
+
# f.radio_button :gender, :value => 'male'
|
66
|
+
def radio_button(field, options={})
|
67
|
+
options.reverse_merge!(:id => field_id(field, options[:value]))
|
68
|
+
options.merge!(:checked => true) if values_matches_field?(field, options[:value])
|
69
|
+
@view_context.radio_button_tag field_name(field), options
|
70
|
+
end
|
71
|
+
|
72
|
+
# f.file_field :photo, :class => 'avatar'
|
73
|
+
def file_field(field, options={})
|
74
|
+
options.reverse_merge!(:id => field_id(field))
|
75
|
+
@view_context.file_field_tag field_name(field), options
|
76
|
+
end
|
77
|
+
|
78
|
+
# f.submit "Update", :class => 'large'
|
79
|
+
def submit(caption="Submit", options={})
|
80
|
+
@view_context.submit_tag caption, options
|
81
|
+
end
|
82
|
+
|
83
|
+
# f.simage_submitubmit "buttons/submit.png", :class => 'large'
|
84
|
+
def image_submit(source, options={})
|
85
|
+
@view_context.image_submit_tag source, options
|
86
|
+
end
|
87
|
+
|
88
|
+
protected
|
89
|
+
|
90
|
+
# Returns the known field types for a formbuilder
|
91
|
+
def self.field_types
|
92
|
+
[:hidden_field, :text_field, :text_area, :password_field, :file_field, :radio_button, :check_box, :select]
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns the object's models name
|
96
|
+
# => user_assignment
|
97
|
+
def object_name
|
98
|
+
object.is_a?(Symbol) ? object : object.class.to_s.underscore
|
99
|
+
end
|
100
|
+
|
101
|
+
# Returns true if the value matches the value in the field
|
102
|
+
# field_has_value?(:gender, 'male')
|
103
|
+
def values_matches_field?(field, value)
|
104
|
+
value.present? && (field_value(field).to_s == value.to_s || field_value(field).to_s == 'true')
|
105
|
+
end
|
106
|
+
|
107
|
+
# Returns the value for the object's field
|
108
|
+
# field_value(:username) => "Joey"
|
109
|
+
def field_value(field)
|
110
|
+
@object && @object.respond_to?(field) ? @object.send(field) : ""
|
111
|
+
end
|
112
|
+
|
113
|
+
# Returns the name for the given field
|
114
|
+
# field_name(:username) => "user[username]"
|
115
|
+
def field_name(field)
|
116
|
+
"#{object_name}[#{field}]"
|
117
|
+
end
|
118
|
+
|
119
|
+
# Returns the id for the given field
|
120
|
+
# field_id(:username) => "user_username"
|
121
|
+
# field_id(:gender, :male) => "user_gender_male"
|
122
|
+
def field_id(field, value=nil)
|
123
|
+
value.blank? ? "#{object_name}_#{field}" : "#{object_name}_#{field}_#{value}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module AnyView
|
2
|
+
module Helpers
|
3
|
+
module FormBuilder
|
4
|
+
class StandardFormBuilder < AbstractFormBuilder
|
5
|
+
|
6
|
+
# text_field_block(:username, { :class => 'long' }, { :class => 'wide-label' })
|
7
|
+
# text_area_block(:summary, { :class => 'long' }, { :class => 'wide-label' })
|
8
|
+
# password_field_block(:password, { :class => 'long' }, { :class => 'wide-label' })
|
9
|
+
# file_field_block(:photo, { :class => 'long' }, { :class => 'wide-label' })
|
10
|
+
# check_box_block(:remember_me, { :class => 'long' }, { :class => 'wide-label' })
|
11
|
+
# select_block(:color, :options => ['green', 'black'])
|
12
|
+
(self.field_types - [ :hidden_field, :radio_button ]).each do |field_type|
|
13
|
+
class_eval <<-EOF
|
14
|
+
def #{field_type}_block(field, options={}, label_options={})
|
15
|
+
label_options.reverse_merge!(:caption => options.delete(:caption)) if options[:caption]
|
16
|
+
field_html = label(field, label_options)
|
17
|
+
field_html << #{field_type}(field, options)
|
18
|
+
@view_context.content_tag(:p, field_html)
|
19
|
+
end
|
20
|
+
EOF
|
21
|
+
end
|
22
|
+
|
23
|
+
# submit_block("Update")
|
24
|
+
def submit_block(caption, options={})
|
25
|
+
submit_html = self.submit(caption, options)
|
26
|
+
@view_context.content_tag(:p, submit_html)
|
27
|
+
end
|
28
|
+
|
29
|
+
# image_submit_block("submit.png")
|
30
|
+
def image_submit_block(source, options={})
|
31
|
+
submit_html = self.image_submit(source, options)
|
32
|
+
@view_context.content_tag(:p, submit_html)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
module AnyView
|
2
|
+
module Helpers
|
3
|
+
module FormHelpers
|
4
|
+
# Constructs a form for object using given or default form_builder
|
5
|
+
# form_for @user, '/register', :id => 'register' do |f| ... end
|
6
|
+
def form_for(object, url, settings={}, &block)
|
7
|
+
builder_class = configured_form_builder_class(settings[:builder])
|
8
|
+
settings[:builder] = builder_class.new(self, object)
|
9
|
+
form_tag(url, settings, &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Constructs form fields for an object using given or default form_builder
|
13
|
+
# Used within an existing form to allow alternate objects within one form
|
14
|
+
# fields_for @user.assignment do |assignment| ... end
|
15
|
+
# fields_for :assignment do |assigment| ... end
|
16
|
+
def fields_for(object, settings={}, &block)
|
17
|
+
builder_class = configured_form_builder_class(settings[:builder])
|
18
|
+
fields_html = capture_content(builder_class.new(self, object), &block)
|
19
|
+
concat_content fields_html
|
20
|
+
end
|
21
|
+
|
22
|
+
# Constructs a form without object based on options
|
23
|
+
# form_tag '/register' do ... end
|
24
|
+
def form_tag(url, options={}, &block)
|
25
|
+
options.reverse_merge!(:method => 'post', :action => url)
|
26
|
+
|
27
|
+
@_multi_enc_type = options.delete(:multipart)
|
28
|
+
fake_method = hidden_form_method_field(options[:method])
|
29
|
+
real_method = real_method_for_fake(options[:method])
|
30
|
+
options[:method] = real_method
|
31
|
+
builder = options.delete(:builder)
|
32
|
+
|
33
|
+
inner_form_html = fake_method.to_s
|
34
|
+
inner_form_html += if builder
|
35
|
+
capture_content(builder, &block)
|
36
|
+
else
|
37
|
+
capture_content(&block)
|
38
|
+
end
|
39
|
+
|
40
|
+
options[:enctype] = "multipart/form-data" if @_multi_enc_type
|
41
|
+
@_multi_enc_type = nil
|
42
|
+
concat_content content_tag('form', inner_form_html, options)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Constructs a field_set to group fields with given options
|
46
|
+
# field_set_tag("Office", :class => 'office-set')
|
47
|
+
# parameters: legend_text=nil, options={}
|
48
|
+
def field_set_tag(*args, &block)
|
49
|
+
options = args.extract_options!
|
50
|
+
legend_text = args[0].is_a?(String) ? args.first : nil
|
51
|
+
legend_html = legend_text.blank? ? '' : content_tag(:legend, legend_text)
|
52
|
+
field_set_content = legend_html + capture_content(&block)
|
53
|
+
concat_content content_tag('fieldset', field_set_content, options)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Constructs list html for the errors for a given object
|
57
|
+
# error_messages_for @user
|
58
|
+
def error_messages_for(record, options={})
|
59
|
+
return "" if record.blank? or record.errors.none?
|
60
|
+
options.reverse_merge!(:header_message => "The #{record.class.to_s.downcase} could not be saved!")
|
61
|
+
error_messages = record.errors.full_messages
|
62
|
+
error_items = error_messages.collect { |er| content_tag(:li, er) }.join("\n")
|
63
|
+
error_html = content_tag(:p, options.delete(:header_message))
|
64
|
+
error_html << content_tag(:ul, error_items, :class => 'errors-list')
|
65
|
+
content_tag(:div, error_html, :class => 'field-errors')
|
66
|
+
end
|
67
|
+
|
68
|
+
# Constructs a label tag from the given options
|
69
|
+
# label_tag :username, :class => 'long-label'
|
70
|
+
# label_tag :username, :class => 'long-label' do ... end
|
71
|
+
def label_tag(name, options={}, &block)
|
72
|
+
options.reverse_merge!(:caption => name.to_s.titleize, :for => name)
|
73
|
+
caption_text = options.delete(:caption) + ": "
|
74
|
+
if block_given? # label with inner content
|
75
|
+
label_content = caption_text + capture_content(&block)
|
76
|
+
concat_content(content_tag(:label, label_content, options))
|
77
|
+
else # regular label
|
78
|
+
content_tag(:label, caption_text, options)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Constructs a hidden field input from the given options
|
83
|
+
# hidden_field_tag :session_key, :value => "__secret__"
|
84
|
+
def hidden_field_tag(name, options={})
|
85
|
+
options.reverse_merge!(:name => name)
|
86
|
+
input_tag(:hidden, options)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Constructs a text field input from the given options
|
90
|
+
# text_field_tag :username, :class => 'long'
|
91
|
+
def text_field_tag(name, options={})
|
92
|
+
options.reverse_merge!(:name => name)
|
93
|
+
input_tag(:text, options)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Constructs a text area input from the given options
|
97
|
+
# text_area_tag :username, :class => 'long'
|
98
|
+
def text_area_tag(name, options={})
|
99
|
+
options.reverse_merge!(:name => name)
|
100
|
+
content_tag(:textarea, '', options)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Constructs a password field input from the given options
|
104
|
+
# password_field_tag :password, :class => 'long'
|
105
|
+
def password_field_tag(name, options={})
|
106
|
+
options.reverse_merge!(:name => name)
|
107
|
+
input_tag(:password, options)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Constructs a check_box from the given options
|
111
|
+
# options = [['caption', 'value'], ['Green', 'green1'], ['Blue', 'blue1'], ['Black', "black1"]]
|
112
|
+
# options = ['option', 'red', 'yellow' ]
|
113
|
+
# select_tag(:favorite_color, :options => ['red', 'yellow'], :selected => 'green1')
|
114
|
+
# select_tag(:country, :collection => @countries, :fields => [:name, :code])
|
115
|
+
def select_tag(name, options={})
|
116
|
+
options.reverse_merge!(:name => name)
|
117
|
+
collection, fields = options.delete(:collection), options.delete(:fields)
|
118
|
+
options[:options] = options_from_collection(collection, fields) if collection
|
119
|
+
options[:options].unshift('') if options.delete(:include_blank)
|
120
|
+
select_options_html = options_for_select(options.delete(:options), options.delete(:selected)).join
|
121
|
+
options.merge!(:name => "#{options[:name]}[]") if options[:multiple]
|
122
|
+
content_tag(:select, select_options_html, options)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Constructs a check_box from the given options
|
126
|
+
# check_box_tag :remember_me, :value => 'Yes'
|
127
|
+
def check_box_tag(name, options={})
|
128
|
+
options.reverse_merge!(:name => name, :value => '1')
|
129
|
+
input_tag(:checkbox, options)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Constructs a radio_button from the given options
|
133
|
+
# radio_button_tag :remember_me, :value => 'true'
|
134
|
+
def radio_button_tag(name, options={})
|
135
|
+
options.reverse_merge!(:name => name)
|
136
|
+
input_tag(:radio, options)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Constructs a file field input from the given options
|
140
|
+
# file_field_tag :photo, :class => 'long'
|
141
|
+
def file_field_tag(name, options={})
|
142
|
+
@_multi_enc_type = true
|
143
|
+
options.reverse_merge!(:name => name)
|
144
|
+
input_tag(:file, options)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Constructs a submit button from the given options
|
148
|
+
# submit_tag "Create", :class => 'success'
|
149
|
+
def submit_tag(caption="Submit", options={})
|
150
|
+
options.reverse_merge!(:value => caption)
|
151
|
+
input_tag(:submit, options)
|
152
|
+
end
|
153
|
+
|
154
|
+
# Constructs a button input from the given options
|
155
|
+
# button_tag "Cancel", :class => 'clear'
|
156
|
+
def button_tag(caption, options = {})
|
157
|
+
options.reverse_merge!(:value => caption)
|
158
|
+
input_tag(:button, options)
|
159
|
+
end
|
160
|
+
|
161
|
+
# Constructs a submit button from the given options
|
162
|
+
# submit_tag "Create", :class => 'success'
|
163
|
+
def image_submit_tag(source, options={})
|
164
|
+
options.reverse_merge!(:src => image_path(source))
|
165
|
+
input_tag(:image, options)
|
166
|
+
end
|
167
|
+
|
168
|
+
protected
|
169
|
+
|
170
|
+
# Returns an array of option items for a select field based on the given collection
|
171
|
+
# fields is an array containing the fields to display from each item in the collection
|
172
|
+
def options_from_collection(collection, fields)
|
173
|
+
return '' if collection.blank?
|
174
|
+
collection.collect { |item| [ item.send(fields.first), item.send(fields.last) ] }
|
175
|
+
end
|
176
|
+
|
177
|
+
# Returns the options tags for a select based on the given option items
|
178
|
+
def options_for_select(option_items, selected_value=nil)
|
179
|
+
return '' if option_items.blank?
|
180
|
+
option_items.collect do |caption, value|
|
181
|
+
value ||= caption
|
182
|
+
content_tag(:option, caption, :value => value, :selected => selected_value.to_s =~ /#{value}|#{caption}/)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# returns the hidden method field for 'put' and 'delete' forms
|
187
|
+
# Only 'get' and 'post' are allowed within browsers;
|
188
|
+
# 'put' and 'delete' are just specified using hidden fields with form action still 'put'.
|
189
|
+
# hidden_form_method_field('delete') => <input name="_method" value="delete" />
|
190
|
+
def hidden_form_method_field(desired_method)
|
191
|
+
case desired_method
|
192
|
+
when :get, :GET, :POST, :post, /get/i, /post/i
|
193
|
+
''
|
194
|
+
else
|
195
|
+
hidden_field_tag(:_method, :value => desired_method)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def real_method_for_fake(desired_method)
|
200
|
+
case desired_method
|
201
|
+
when :get, :GET, :delete, :DELETE, /get/i, /delete/i
|
202
|
+
'get'
|
203
|
+
else
|
204
|
+
'post'
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Returns the FormBuilder class to use based on all available setting sources
|
209
|
+
# If explicitly defined, returns that, otherwise returns defaults
|
210
|
+
# configured_form_builder_class(nil) => StandardFormBuilder
|
211
|
+
def configured_form_builder_class(explicit_builder=nil)
|
212
|
+
default_builder = self.respond_to?(:options) && self.options.default_builder
|
213
|
+
explicit_builder || default_builder || FormBuilder::StandardFormBuilder
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module AnyView
|
2
|
+
module Helpers
|
3
|
+
module FormatHelpers
|
4
|
+
|
5
|
+
# Returns escaped text to protect against malicious content
|
6
|
+
def escape_html(text)
|
7
|
+
Rack::Utils.escape_html(text)
|
8
|
+
end
|
9
|
+
alias h escape_html
|
10
|
+
alias sanitize_html escape_html
|
11
|
+
|
12
|
+
# Returns escaped text to protect against malicious content
|
13
|
+
# Returns blank if the text is empty
|
14
|
+
def h!(text, blank_text = ' ')
|
15
|
+
return blank_text if text.nil? || text.empty?
|
16
|
+
h text
|
17
|
+
end
|
18
|
+
|
19
|
+
# Truncates a given text after a given :length if text is longer than :length (defaults to 30).
|
20
|
+
# The last characters will be replaced with the :omission (defaults to "…") for a total length not exceeding :length.
|
21
|
+
# truncate("Once upon a time in a world far far away", :length => 8) => "Once upon..."
|
22
|
+
def truncate(text, *args)
|
23
|
+
options = args.extract_options!
|
24
|
+
options = options.dup
|
25
|
+
options.reverse_merge!(:length => 30, :omission => "...")
|
26
|
+
if text
|
27
|
+
len = options[:length] - options[:omission].length
|
28
|
+
chars = text
|
29
|
+
(chars.length > options[:length] ? chars[0...len] + options[:omission] : text).to_s
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# Returns text transformed into HTML using simple formatting rules. Two or more consecutive newlines(\n\n) are considered
|
35
|
+
# as a paragraph and wrapped in <p> tags. One newline (\n) is considered as a linebreak and a <br /> tag is appended.
|
36
|
+
# This method does not remove the newlines from the text.
|
37
|
+
# simple_format("hello\nworld") # => "<p>hello<br/>world</p>"
|
38
|
+
def simple_format(text, html_options={})
|
39
|
+
start_tag = tag('p', html_options.merge(:open => true))
|
40
|
+
text = text.to_s.dup
|
41
|
+
text.gsub!(/\r\n?/, "\n") # \r\n and \r -> \n
|
42
|
+
text.gsub!(/\n\n+/, "</p>\n\n#{start_tag}") # 2+ newline -> paragraph
|
43
|
+
text.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
|
44
|
+
text.insert 0, start_tag
|
45
|
+
text << "</p>"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module AnyView
|
2
|
+
module Helpers
|
3
|
+
module TagHelpers
|
4
|
+
# Creates an html input field with given type and options
|
5
|
+
# input_tag :text, :class => "test"
|
6
|
+
def input_tag(type, options = {})
|
7
|
+
options = options.dup
|
8
|
+
options[:type] = type
|
9
|
+
tag(:input, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Creates an html tag with given name, content and options
|
13
|
+
# @example
|
14
|
+
# content_tag(:p, "hello", :class => 'light')
|
15
|
+
# content_tag(:p, :class => 'dark') do ... end
|
16
|
+
# parameters: content_tag(name, content=nil, options={}, &block)
|
17
|
+
# Writes directly to the buffer
|
18
|
+
def content_tag(*args, &block)
|
19
|
+
name = args.first
|
20
|
+
options = args.extract_options!
|
21
|
+
tag_html = block_given? ? capture_content(options, &block) : args[1]
|
22
|
+
tag_result = tag(name, options.merge(:content => tag_html))
|
23
|
+
block.nil? ? tag_result : concat_content(tag_result)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Creates an html tag with the given name and options
|
27
|
+
# @example
|
28
|
+
# tag(:br, :style => 'clear:both')
|
29
|
+
# tag(:p, :content => "hello", :class => 'large')
|
30
|
+
# @return a string
|
31
|
+
def tag(name, options={})
|
32
|
+
content, open_tag = options.delete(:content), options.delete(:open)
|
33
|
+
identity_tag_attributes.each { |attr| options[attr] = attr.to_s if options[attr] }
|
34
|
+
html_attrs = options.collect { |a, v| v.blank? ? nil : "#{a}=\"#{v}\"" }.compact.join(" ")
|
35
|
+
base_tag = (html_attrs.present? ? "<#{name} #{html_attrs}" : "<#{name}")
|
36
|
+
base_tag << (open_tag ? ">" : (content ? ">#{content}</#{name}>" : " />"))
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
# Returns a list of attributes which can only contain an identity value (i.e selected)
|
42
|
+
def identity_tag_attributes
|
43
|
+
[:checked, :disabled, :selected, :multiple]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'tilt'
|
2
|
+
|
3
|
+
class Tilt::Template
|
4
|
+
def render_with_any_view(scope=Object.new, locals = {}, &blk)
|
5
|
+
scope.template_type = self.class if scope.respond_to?(:template_type=)
|
6
|
+
render_without_any_view(scope, locals, &blk)
|
7
|
+
end
|
8
|
+
alias_method :render_without_any_view, :render
|
9
|
+
alias_method :render, :render_with_any_view
|
10
|
+
end
|
11
|
+
|
12
|
+
module AnyView
|
13
|
+
# Provides capture and concat methods for use inside templates with the Tilt gem.
|
14
|
+
module TiltBase
|
15
|
+
class Error < StandardError; end
|
16
|
+
class CaptureMethodNotFound < Error; end
|
17
|
+
class ContentMethodNotFound < Error; end
|
18
|
+
|
19
|
+
def self.included(base)
|
20
|
+
base.class_eval do
|
21
|
+
attr_writer :template_type unless self.method_defined?(:template_type=)
|
22
|
+
attr_reader :template_type unless self.method_defined?(:template_type)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
# Keeps track of the concatenation methods for each template type.
|
28
|
+
# If you have your own template types, then you should add them here
|
29
|
+
def concat_methods
|
30
|
+
@concat_methods ||= {}
|
31
|
+
end
|
32
|
+
|
33
|
+
def capture_methods
|
34
|
+
@capture_methods ||= {}
|
35
|
+
end
|
36
|
+
|
37
|
+
def capture_method_for(template)
|
38
|
+
capture_methods[template]
|
39
|
+
end
|
40
|
+
|
41
|
+
def concat_method_for(template)
|
42
|
+
concat_methods[template]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
capture_methods[::Tilt::HamlTemplate ] = :_haml_capture
|
47
|
+
capture_methods[::Tilt::ERBTemplate ] = :_erb_capture
|
48
|
+
capture_methods[::Tilt::ErubisTemplate] = :_erb_capture
|
49
|
+
|
50
|
+
concat_methods[ ::Tilt::HamlTemplate ] = :_haml_concat
|
51
|
+
concat_methods[ ::Tilt::ERBTemplate ] = :_erb_concat
|
52
|
+
concat_methods[ ::Tilt::ErubisTemplate] = :_erb_concat
|
53
|
+
|
54
|
+
def capture_content(*args, &blk)
|
55
|
+
opts = args.extract_options!
|
56
|
+
opts[:template_type] ||= template_type
|
57
|
+
capture_method = AnyView::TiltBase.capture_method_for(opts[:template_type])
|
58
|
+
|
59
|
+
raise CaptureMethodNotFound, "Capture Method not found for Template Type: #{opts[:template_type].inspect}" unless capture_method
|
60
|
+
send(capture_method, *args, &blk)
|
61
|
+
end
|
62
|
+
|
63
|
+
def concat_content(string, opts = {})
|
64
|
+
opts[:template_type] ||= template_type
|
65
|
+
concat_method = AnyView::TiltBase.concat_method_for(opts[:template_type])
|
66
|
+
|
67
|
+
raise ConcatMethodNotFound, "Concat Method not found for Template Type: #{opts[:template_type].inspect}" unless concat_method
|
68
|
+
send(concat_method, string)
|
69
|
+
end
|
70
|
+
|
71
|
+
def _haml_capture(*args, &block)
|
72
|
+
with_haml_buffer Haml::Buffer.new(nil, :encoding => "UTF-8") do
|
73
|
+
capture_haml(*args, &block)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def _erb_capture(*args, &block)
|
78
|
+
_out_buf, @_out_buf = @_out_buf, ""
|
79
|
+
block.call(*args)
|
80
|
+
ret = @_out_buf
|
81
|
+
@_out_buf = _out_buf
|
82
|
+
ret
|
83
|
+
end
|
84
|
+
|
85
|
+
def _haml_concat(string)
|
86
|
+
haml_concat(string)
|
87
|
+
end
|
88
|
+
|
89
|
+
def _erb_concat(string)
|
90
|
+
@_out_buf << string
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
data/lib/any_view.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'dirge'
|
2
|
+
require ~'./any_view/core_ext/string'
|
3
|
+
require ~'./any_view/core_ext/hash'
|
4
|
+
require ~'./any_view/core_ext/array'
|
5
|
+
|
6
|
+
module AnyView
|
7
|
+
autoload :TiltBase, ~'./any_view/tilt_base'
|
8
|
+
|
9
|
+
module Helpers
|
10
|
+
autoload :TagHelpers, ~'./any_view/tag_helpers'
|
11
|
+
autoload :AssetTagHelpers, ~'./any_view/asset_tag_helpers'
|
12
|
+
autoload :FormatHelpers, ~'./any_view/format_helpers'
|
13
|
+
autoload :FormHelpers, ~'./any_view/form_helpers'
|
14
|
+
|
15
|
+
module FormBuilder
|
16
|
+
autoload :AbstractFormBuilder, ~'./any_view/form_builder/abstract_form_builder'
|
17
|
+
autoload :StandardFormBuilder, ~'./any_view/form_builder/standard_form_builder'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def self.included(base)
|
23
|
+
ah = AnyView::Helpers
|
24
|
+
base.class_eval do
|
25
|
+
include ah::TagHelpers, ah::AssetTagHelpers, ah::FormHelpers, ah::FormatHelpers
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<% @content = captured_content do %>
|
2
|
+
<span>Captured Line 1</span>
|
3
|
+
<span>Captured Line 2</span>
|
4
|
+
<% end %>
|
5
|
+
<%= @content %>
|
6
|
+
|
7
|
+
<% concat_in_p('Concat Line 3') %>
|
8
|
+
|
9
|
+
<% determine_block_is_template('erb') do %>
|
10
|
+
<span>This is erb</span>
|
11
|
+
<span>This is erb</span>
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<% ruby_not_template_block %>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<% content_for :demo do %>
|
2
|
+
<h1>This is content yielded from a content_for</h1>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<div class='demo'><%= yield_content :demo %></p>
|
6
|
+
|
7
|
+
<% content_for :demo2 do |fname, lname| %>
|
8
|
+
<h1>This is content yielded with name <%= fname + " " + lname %></h1>
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<div class='demo2'><%= yield_content :demo2, "Johnny", "Smith" %></div>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<%= content_tag :p, "Test 1", :class => 'test', :id => "test1" %>
|
2
|
+
|
3
|
+
<%= content_tag :p, "Test 2" %>
|
4
|
+
|
5
|
+
<% content_tag(:p, :class => 'test', :id => 'test3') do %>
|
6
|
+
<span>Test 3</span>
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
<% content_tag(:p) do %>
|
10
|
+
<span>Test 4</span>
|
11
|
+
<% end %>
|