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
@@ -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 %>
|