Changeset 746
- Timestamp:
- 10/14/07 19:40:35 (1 year ago)
- Files:
-
- plugins/merb_helpers/lib/form_helpers.rb (modified) (9 diffs)
- plugins/merb_helpers/specs/merb_helpers_spec.rb (modified) (17 diffs)
- plugins/merb_helpers/specs/spec_helper.rb (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
plugins/merb_helpers/lib/form_helpers.rb
r732 r746 1 class Hash2 3 def to_html_attributes4 map do |k,v|5 "#{k.to_s.camelize.downcase}=\"#{v}\""6 end.join(" ")7 end8 9 def add_html_class!(html_class)10 if self[:class]11 self[:class] = "#{self[:class]} #{html_class}"12 else13 self[:class] = html_class14 end15 end16 17 end18 19 1 module Merb 20 2 module Helpers … … 36 18 end 37 19 38 def open_tag(name, attrs = nil)39 "<#{name}#{' ' + attrs.to_html_attributes if attrs}>"40 end41 42 def self_closing_tag(name, attrs = nil)43 "<#{name}#{' ' + attrs.to_html_attributes if attrs}/>"44 end45 46 20 def form_tag(attrs = {}, &block) 21 attrs.merge!( :enctype => "multipart/form-data" ) if attrs.delete(:multipart) 22 fake_form_method = set_form_method(attrs) 47 23 concat(open_tag("form", attrs), block.binding) 24 concat(generate_fake_form_method(fake_form_method), block.binding) if fake_form_method 48 25 concat(capture(&block), block.binding) 49 26 concat("</form>", block.binding) 50 27 end 51 28 52 def form_for(obj, attrs=nil, &block) 29 def form_for(obj, attrs={}, &block) 30 fake_form_method = set_form_method(attrs, instance_variable_get("@#{obj}")) 53 31 concat(open_tag("form", attrs), block.binding) 32 concat(generate_fake_form_method(fake_form_method), block.binding) if fake_form_method 54 33 fields_for(obj, attrs, &block) 55 34 concat("</form>", block.binding) … … 58 37 def fields_for(obj, attrs=nil, &block) 59 38 old_obj, @_obj = @_obj, instance_variable_get("@#{obj}") 60 @_object_name = obj39 @_object_name = "#{@_obj.class}".snake_case 61 40 old_block, @_block = @_block, block 62 41 … … 66 45 end 67 46 68 def name(col)47 def control_name(col) 69 48 "#{@_object_name}[#{col}]" 70 49 end 71 50 72 def value(col)51 def control_value(col) 73 52 @_obj.send(col) 74 53 end 75 54 76 def name_value(col, attrs)77 {:name => name(col), :value =>value(col)}.merge(attrs)55 def control_name_value(col, attrs) 56 {:name => control_name(col), :value => control_value(col)}.merge(attrs) 78 57 end 79 58 80 59 def text_control(col, attrs = {}) 81 60 errorify_field(attrs, col) 82 text_field( name_value(col, attrs))61 text_field(control_name_value(col, attrs)) 83 62 end 84 63 85 64 def text_field(attrs = {}) 86 65 attrs.merge!(:type => "text") 87 self_closing_tag("input", attrs)66 add_field_label(attrs){self_closing_tag("input", attrs)} 88 67 end 89 68 … … 93 72 attrs.merge!(:value => val ? "1" : "0") 94 73 attrs.merge!(:checked => "checked") if val 95 checkbox_field( name_value(col, attrs))74 checkbox_field(control_name_value(col, attrs)) 96 75 end 97 76 … … 99 78 attrs.merge!(:type => :checkbox) 100 79 attrs.add_html_class!("checkbox") 101 self_closing_tag("input", attrs)80 add_field_label(attrs){self_closing_tag("input", attrs)} 102 81 end 103 82 104 83 def hidden_control(col, attrs = {}) 84 attrs.delete(:label) 105 85 errorify_field(attrs, col) 106 hidden_field( name_value(col, attrs))86 hidden_field(control_name_value(col, attrs)) 107 87 end 108 88 109 89 def hidden_field(attrs = {}) 90 attrs.delete(:label) 110 91 attrs.merge!(:type => :hidden) 111 92 self_closing_tag("input", attrs) … … 117 98 ret = "" 118 99 options.each do |opt| 119 hash = {:name => "#{@_object_name}[#{col}]", :value => opt }100 hash = {:name => "#{@_object_name}[#{col}]", :value => opt, :label => opt} 120 101 hash.merge!(:selected => "selected") if val.to_s == opt.to_s 121 102 ret << radio_field(hash) … … 127 108 attrs.merge!(:type => "radio") 128 109 attrs.add_html_class!("radio") 129 self_closing_tag("input", attrs)110 add_field_label(attrs){self_closing_tag("input", attrs)} 130 111 end 131 112 132 113 def text_area_control(col, attrs = {}) 114 attrs ||= {} 133 115 errorify_field(attrs, col) 134 text_area_field( value(col), attrs.merge(:name =>name(col)))116 text_area_field(control_value(col), attrs.merge(:name => control_name(col))) 135 117 end 136 118 137 119 def text_area_field(val, attrs = {}) 138 open_tag("textarea", attrs) + 139 val + 140 "</textarea>" 120 val ||="" 121 add_field_label(attrs) do 122 open_tag("textarea", attrs) + 123 val + 124 "</textarea>" 125 end 141 126 end 142 127 … … 147 132 148 133 def errorify_field(attrs, col) 149 attrs.add_html_class!("error") if !@obj.valid? && @obj.errors.on(col) 134 attrs.add_html_class!("error") if !@_obj.valid? && @_obj.errors.on(col) 135 end 136 137 def add_label(label, &block) 138 concat("<label>#{label}", block.binding) 139 yield 140 concat("</label>", block.binding ) 141 end 142 143 144 def add_field_label( attrs, &block ) 145 case attrs 146 when Hash 147 label_name = attrs.delete :label 148 when String, Symbol 149 label_name = attrs.to_s 150 end 151 ret = "" 152 ret << "<label>#{label_name}" if label_name 153 ret << yield 154 ret << "</label>" if label_name 155 ret 156 end 157 158 private 159 # Fake out the browser to send back the method for RESTful stuff. 160 # Fall silently back to post if a method is given that is not supported here 161 def set_form_method(options = {}, obj = nil) 162 options[:method] ||= (!obj || obj.new_record? ? :post : :put) 163 if ![:get,:post].include?(options[:method]) 164 fake_form_method = options[:method] if [:put, :delete].include?(options[:method]) 165 options[:method] = :post 166 end 167 fake_form_method 168 end 169 170 def generate_fake_form_method(fake_form_method) 171 fake_form_method ? hidden_field(:name => "_method", :value => "#{fake_form_method}") : "" 150 172 end 151 173 plugins/merb_helpers/specs/merb_helpers_spec.rb
r734 r746 39 39 it_should_behave_like "FakeBufferConsumer" 40 40 41 it "should use the post method by default" do 42 form_tag do 43 _buffer << "CONTENT" 44 end 45 _buffer.should match_tag(:form, :method => "post") 46 _buffer.should include("CONTENT") 47 end 48 49 it "should use the get method if set" do 50 form_tag :method => :get do 51 _buffer << "CONTENT" 52 end 53 _buffer.should match_tag(:form, :method => "get") 54 _buffer.should include("CONTENT") 55 end 56 57 it "should fake out the put method if set" do 58 form_tag :method => :put do 59 _buffer << "CONTENT" 60 end 61 _buffer.should match_tag(:form, :method => "post") 62 _buffer.should match_tag(:input, :type => "hidden", :name => "_method", :value => "put") 63 end 64 65 it "should fake out the delete method if set" do 66 form_tag :method => :delete do 67 _buffer << "CONTENT" 68 end 69 _buffer.should match_tag(:form, :method => "post") 70 _buffer.should match_tag(:input, :type => "hidden", :name => "_method", :value => "delete") 71 end 72 73 it "should silently set method to post if an unsupported method is used" do 74 form_tag :method => :dodgy do 75 _buffer << "CONTENT" 76 end 77 _buffer.should match_tag(:form, :method => "post") 78 _buffer.should_not match_tag(:input, :type => "hidden", :name => "_method", :value => "dodgy") 79 end 80 41 81 it "should take create a form" do 42 form_tag(:action => "foo", :method => "POST") do82 form_tag(:action => "foo", :method => :post) do 43 83 _buffer << "Hello" 44 84 end 45 _buffer.should match_tag(:form, :action => "foo", :method => " POST")85 _buffer.should match_tag(:form, :action => "foo", :method => "post") 46 86 _buffer.should include("Hello") 87 end 88 89 it "should set a form to be mutlipart" do 90 form_tag( :action => "foo", :method => :post, :multipart => true ) do 91 _buffer << "CONTENT" 92 end 93 _buffer.should match_tag( :form, :action => "foo", :method => "post", :enctype => "multipart/form-data") 94 _buffer.should include("CONTENT") 47 95 end 48 96 end … … 53 101 it "should wrap the contents in a form tag" do 54 102 form_for(:obj) do 55 _buffer("") << "Hello" 56 end 57 _buffer("").should == "<form>Hello</form>" 58 end 103 _buffer << "Hello" 104 end 105 _buffer.should match_tag(:form, :method => "post") 106 _buffer.should match_tag(:input, :type => "hidden", :value => "put", :name => "_method") 107 end 108 109 it "should set the method to post be default" do 110 @obj2 = FakeModel2.new 111 form_for(:obj2) do 112 end 113 _buffer.should match_tag(:form, :method => "post") 114 _buffer.should_not match_tag(:input, :type => "hidden", :name => "_method") 115 end 116 117 it "should support PUT if the object passed in is not a new_record? via a hidden field" do 118 form_for(:obj) do 119 end 120 _buffer.should match_tag(:form, :method => "post") 121 _buffer.should match_tag(:input, :type => "hidden", :value => "put", :name => "_method") 122 end 123 59 124 end 60 125 … … 64 129 it "should dump the contents in the context of the object" do 65 130 fields_for(:obj) do 66 _buffer("") << "Hello" 67 end 68 _buffer("").should == "Hello" 131 text_control(:foo).should match_tag(:input, :type => "text", :value => "foowee") 132 _buffer << "Hello" 133 end 134 _buffer.should == "Hello" 69 135 end 70 136 … … 74 140 text_control(:foo).should match_tag(:input, :type => "text", :value => "foowee") 75 141 fields_for(:obj2) do 76 text_control(:foo).should match_tag(:input, : type => "text", :value => "foowee2")142 text_control(:foo).should match_tag(:input, :name => "fake_model2[foo]", :type => "text", :value => "foowee2") 77 143 end 78 144 text_control(:foo).should match_tag(:input, :type => "text", :value => "foowee") 79 145 end 80 146 end 147 148 it "should handle an explicit nil attribute" do 149 fields_for(:obj, nil) do 150 _buffer << text_control(:foo) 151 end 152 _buffer.should match_tag(:input, :name => "fake_model[foo]", :value => "foowee", :type => "text") 153 end 154 81 155 end 82 156 83 157 describe "text_field (basic)" do 158 it_should_behave_like "FakeBufferConsumer" 159 84 160 it "should return a basic text field based on the values passed in" do 85 161 text_field(:name => "foo", :value => "bar").should match_tag( :input, :type => "text", :name => "foo", :value => "bar") 86 162 end 163 164 it "should wrap the field in a label if the :label option is passed to the text_field" do 165 result = text_field(:label => "LABEL" ) 166 result.should match(/<label>LABEL<input type="text"\s*\/><\/label>/) 167 end 87 168 end 88 169 … … 92 173 it "should take a string object and return a useful text control" do 93 174 f = form_for :obj do 94 text_control(:foo).should match_tag(:input, :type => "text", :name => " obj[foo]", :value => "foowee")175 text_control(:foo).should match_tag(:input, :type => "text", :name => "fake_model[foo]", :value => "foowee") 95 176 end 96 177 end … … 98 179 it "should take additional attributes and use them" do 99 180 form_for :obj do 100 text_control(:foo, :bar => "7").should match_tag(:input, :type => "text", :name => "obj[foo]", :value => "foowee", :bar => "7") 101 end 181 text_control(:foo, :bar => "7").should match_tag(:input, :type => "text", :name => "fake_model[foo]", :value => "foowee", :bar => "7") 182 end 183 end 184 185 it "should wrap the text_control in a label if the :label option is passed in" do 186 form_for :obj do 187 _buffer << text_control(:foo, :label => "LABEL") 188 end 189 _buffer.should match(/<label>LABEL<input/) 190 res = _buffer.scan(/<[^>]*>/) 191 res[2].should_not match_tag(:input, :label => "LABEL") 102 192 end 103 193 end … … 106 196 it "should return a basic checkbox based on the values passed in" do 107 197 checkbox_field(:name => "foo", :checked => "checked").should match_tag(:input, :class => "checkbox", :name => "foo", :checked => "checked") 198 end 199 200 it "should wrap the checkbox_field in a label if the :label option is passed in" do 201 result = checkbox_field(:label => "LABEL" ) 202 result.should match(/<label>LABEL<input/) 203 res = result.scan(/<[^>]*>/) 204 res[2].should_not match_tag(:input, :label => "LABEL") 108 205 end 109 206 end … … 114 211 it "should take a string and return a useful checkbox control" do 115 212 form_for :obj do 116 checkbox_control(:baz).should match_tag(:input, :type =>"checkbox", :name => " obj[baz]", :class => "checkbox", :value => "1", :checked => "checked")117 checkbox_control(:bat).should match_tag(:input, :type =>"checkbox", :name => " obj[bat]", :class => "checkbox", :value => "0")213 checkbox_control(:baz).should match_tag(:input, :type =>"checkbox", :name => "fake_model[baz]", :class => "checkbox", :value => "1", :checked => "checked") 214 checkbox_control(:bat).should match_tag(:input, :type =>"checkbox", :name => "fake_model[bat]", :class => "checkbox", :value => "0") 118 215 end 119 216 end … … 121 218 it "should render controls with errors if their attribute contains an error" do 122 219 form_for :obj do 123 checkbox_control(:bazbad).should match_tag(:input, :type =>"checkbox", :name => " obj[bazbad]",220 checkbox_control(:bazbad).should match_tag(:input, :type =>"checkbox", :name => "fake_model[bazbad]", 124 221 :class => "error checkbox", :value => "1", :checked => "checked") 125 checkbox_control(:batbad).should match_tag(:input, :type =>"checkbox", :name => " obj[batbad]",222 checkbox_control(:batbad).should match_tag(:input, :type =>"checkbox", :name => "fake_model[batbad]", 126 223 :class => "error checkbox", :value => "0") 127 224 end 128 end 129 225 end 226 227 it "should wrap the checkbox_control in a label if the label option is passed in" do 228 form_for :obj do 229 _buffer << checkbox_control(:foo, :label => "LABEL") 230 end 231 _buffer.should match( /<label>LABEL<input/ ) 232 res = _buffer.scan(/<[^>]*>/) 233 res[2].should_not match_tag(:input, :label => "LABEL") 234 end 130 235 end 131 236 … … 135 240 hidden_field(:name => "foo", :value => "bar").should match_tag(:input, :type => "hidden", :name => "foo", :value => "bar") 136 241 end 242 243 it "should not render a label if the :label option is passed in" do 244 res = hidden_field(:label => "LABEL") 245 res.should_not match(/<label>LABEL/) 246 res.should_not match_tag(:input, :label=> "LABEL") 247 end 137 248 end 138 249 … … 141 252 142 253 it "should take a string and return a useful checkbox control" do 143 form_for :obj do 144 hidden_control(:foo).should match_tag(:input, :type =>"hidden", :name => " obj[foo]", :value => "foowee")254 form_for :obj do 255 hidden_control(:foo).should match_tag(:input, :type =>"hidden", :name => "fake_model[foo]", :value => "foowee") 145 256 end 146 257 end … … 148 259 it "should render controls with errors if their attribute contains an error" do 149 260 form_for :obj do 150 hidden_control(:foobad).should match_tag(:input, :type =>"hidden", :name => "obj[foobad]", :value => "foowee", :class => "error") 261 hidden_control(:foobad).should match_tag(:input, :type =>"hidden", :name => "fake_model[foobad]", :value => "foowee", :class => "error") 262 end 263 end 264 265 it "should not render a label if the :label option is passed in" do 266 form_for :obj do 267 res = hidden_control(:foo, :label => "LABEL") 268 res.should_not match(/<label>LABEL/) 269 res.should_not match_tag(:input, :label=> "LABEL") 151 270 end 152 271 end … … 158 277 radio_field(:name => "foo", :value => "bar").should match_tag(:input, :type => "radio", :name => "foo", :value => "bar") 159 278 end 279 280 it "should render a label when the label is passed in" do 281 result = radio_field(:name => "foo", :value => "bar", :label => "LABEL") 282 result.should match(/<label>LABEL<input/) 283 res = result.scan(/<[^>]*>/) 284 res[2].should_not match_tag(:input, :label => "LABEL") 285 end 286 160 287 end 161 288 … … 166 293 form_for :obj do 167 294 radio = radio_group_control(:foo, [:foowee, :baree]).scan(/<[^>]*>/) 168 radio[0].should match_tag(:input, :type => "radio", :name => "obj[foo]", :value => "foowee", :selected => "selected") 169 radio[1].should match_tag(:input, :type => "radio", :name => "obj[foo]", :value => "baree") 170 radio[1].should not_match_tag(:selected => "selected") 295 radio[1].should match_tag(:input, :type => "radio", :name => "fake_model[foo]", :value => "foowee", :selected => "selected") 296 radio[4].should match_tag(:input, :type => "radio", :name => "fake_model[foo]", :value => "baree") 297 radio[2].should not_match_tag(:selected => "selected") 298 end 299 end 300 301 it "should wrap the each radio button in the group in a label corresponding to the options" do 302 form_for :obj do 303 radio = radio_group_control(:foo, [:foowee, :baree]) 304 radio.scan( /<label>(foowee|baree)<input/ ).size.should == 2 305 radio = radio.scan(/<[^>]*>/) 306 radio[1].should_not match_tag(:input, :label => "LABEL") 307 radio[4].should_not match_tag(:input, :label => "LABEL") 171 308 end 172 309 end … … 174 311 175 312 describe "text area (basic)" do 176 # include TagMatchers177 313 it "should should return a basic text area based on the values passed in" do 178 314 text_area_field("foo", :name => "foo").should match_tag(:textarea, :name => "foo") 179 315 end 316 317 it "should handle a nil content" do 318 text_area_field(nil, :name => "foo").should == "<textarea name=\"foo\"></textarea>" 319 end 320 321 it "should handle a nil attributes hash" do 322 text_area_field("CONTENT", nil).should == "<textarea>CONTENT</textarea>" 323 end 324 325 it "should render a label when the label is passed in" do 326 result = text_area_field( "CONTENT", :name => "foo", :value => "bar", :label => "LABEL") 327 result.should match(/<label>LABEL<textarea/) 328 res = result.scan(/<[^>]*>/) 329 res[1].should_not match_tag(:textarea, :label => "LABEL") 330 end 180 331 end 181 332 … … 187 338 ta = text_area_control(:foo) 188 339 tab = text_area_control(:foobad) 189 ta.should match_tag(:textarea, :name => " obj[foo]")190 tab.should match_tag(:textarea, :name => " obj[foobad]", :class => "error")340 ta.should match_tag(:textarea, :name => "fake_model[foo]") 341 tab.should match_tag(:textarea, :name => "fake_model[foobad]", :class => "error") 191 342 ta.should include("foowee") 192 343 end 193 344 end 194 end 195 345 346 it "should handle a nil content value" do 347 @obj.nothing.should be_nil 348 form_for :obj do 349 text_area_control(:nothing).should match_tag(:textarea, :name => "fake_model[nothing]") 350 end 351 end 352 353 it "should handle a nil attribute hash" do 354 form_for :obj do 355 text_area_control(:nothing, nil).should match_tag(:textarea, :name => "fake_model[nothing]") 356 end 357 end 358 359 it "should render a label when the label is passed in" do 360 form_for :obj do 361 result = text_area_control( :foo, :label => "LABEL") 362 result.should match(/<label>LABEL<textarea/) 363 res = result.scan(/<[^>]*>/) 364 res[1].should_not match_tag(:textarea, :label => "LABEL") 365 end 366 end 367 368 end 369 370 describe "form helper supporting methods for controls" do 371 it_should_behave_like "FakeBufferConsumer" 372 373 it "should give class_name[colname] for control_name" do 374 form_for :obj do 375 text_control( :foo ).should match_tag( :input, :type => "text", :name => "fake_model[foo]") 376 end 377 end 378 379 it "should provide value=method_value for the control_value method" do 380 form_for :obj do 381 text_control( :foo ).should match_tag( :input, :type => "text", :value => "foowee") 382 end 383 end 384 385 it "should give name and value for a call to control_name_value" do 386 form_for :obj do 387 control_name_value(:foo, :attribute => "ATTRIBUTE" ).should == { :name => "fake_model[foo]", 388 :value => "foowee", 389 :attribute => "ATTRIBUTE"} 390 end 391 end 392 end 196 393 197 394 describe "submit_button" do … … 202 399 end 203 400 end 401 402 describe "label helpers" do 403 it_should_behave_like "FakeBufferConsumer" 404 405 it "should add a label to arbitrary markup in a template" do 406 result = add_label("Name:"){ _buffer << text_field(:name => "name_value") } 407 result.should == "<label>Name:<input type=\"text\" name=\"name_value\"/></label>" 408 409 end 410 411 it "should add a label to a text returning helper" do 412 form_for(:obj) do 413 _buffer << add_field_label({:label => "LABEL"}){ text_control(:foo) } 414 end 415 _buffer.should match(/<label>LABEL<input .+\/><\/label>/) 416 end 417 418 end 419 plugins/merb_helpers/specs/spec_helper.rb
r734 r746 3 3 require 'rubygems' 4 4 require 'merb' 5 require 'merb/test/rspec'5 # require 'merb/test/rspec' 6 6 7 7 class FakeModel … … 22 22 end 23 23 24 def new_record? 25 false 26 end 27 24 28 def errors 25 29 FakeErrors.new(self) … … 29 33 "foowee" 30 34 end 35 31 36 alias_method :foobad, :foo 32 37 … … 45 50 end 46 51 alias_method :batbad, :bat 52 53 def nothing 54 nil 55 end 47 56 end 48 57 … … 53 62 end 54 63 alias_method :foobad, :foo 64 65 def new_record? 66 true 67 end 55 68 56 69 end
