Commit c224f8a93b63bb7c02398390218daba4303a41d1

Authored by Lucas Melo
1 parent 103b7ebe

custom_forms: use rails nested forms in form partial

AI2780
Showing 36 changed files with 420 additions and 475 deletions   Show diff stats
plugins/custom_forms/controllers/custom_forms_plugin_myprofile_controller.rb
1 class CustomFormsPluginMyprofileController < MyProfileController 1 class CustomFormsPluginMyprofileController < MyProfileController
2 -  
3 protect 'post_content', :profile 2 protect 'post_content', :profile
  3 +
4 def index 4 def index
5 @forms = CustomFormsPlugin::Form.from(profile) 5 @forms = CustomFormsPlugin::Form.from(profile)
6 end 6 end
7 7
  8 + def new
  9 + @form = CustomFormsPlugin::Form.new
  10 +
  11 + respond_to do |format|
  12 + format.html
  13 + end
  14 + end
  15 +
8 def create 16 def create
9 - @form = CustomFormsPlugin::Form.new(:profile => profile)  
10 - @fields = []  
11 - @empty_field = CustomFormsPlugin::Field.new  
12 - if request.post?  
13 - begin  
14 - @form.update_attributes!(params[:form])  
15 - params[:fields] = format_kind(params[:fields])  
16 - params[:fields] = format_choices(params[:fields])  
17 - params[:fields] = set_form_id(params[:fields], @form.id)  
18 - create_fields(new_fields(params))  
19 - session['notice'] = _('Form created')  
20 - redirect_to :action => 'index'  
21 - rescue Exception => exception  
22 - logger.error(exception.to_s)  
23 - session['notice'] = _('Form could not be created') 17 + params[:form][:profile_id] = profile.id
  18 + @form = CustomFormsPlugin::Form.new(params[:form])
  19 +
  20 + respond_to do |format|
  21 + if @form.save
  22 + flash[:notice] = _("Custom form #{@form.name} was successfully created.")
  23 + format.html { redirect_to(:action=>'index') }
  24 + else
  25 + format.html { render :action => 'new' }
24 end 26 end
25 end 27 end
26 end 28 end
27 29
28 def edit 30 def edit
29 @form = CustomFormsPlugin::Form.find(params[:id]) 31 @form = CustomFormsPlugin::Form.find(params[:id])
30 - @fields = @form.fields  
31 - @empty_field = CustomFormsPlugin::TextField.new  
32 - if request.post?  
33 - begin  
34 - @form.update_attributes!(params[:form])  
35 - params[:fields] = format_kind(params[:fields])  
36 - params[:fields] = format_choices(params[:fields])  
37 - remove_fields(params, @form)  
38 - create_fields(new_fields(params))  
39 - update_fields(edited_fields(params))  
40 - session['notice'] = _('Form updated')  
41 - redirect_to :action => 'index'  
42 - rescue Exception => exception  
43 - logger.error(exception.to_s) 32 + end
  33 +
  34 + def update
  35 + @form = CustomFormsPlugin::Form.find(params[:id])
  36 +
  37 + respond_to do |format|
  38 + if @form.update_attributes(params[:form])
  39 + flash[:notice] = _("Custom form #{@form.name} was successfully updated.")
  40 + format.html { redirect_to(:action=>'index') }
  41 + else
44 session['notice'] = _('Form could not be updated') 42 session['notice'] = _('Form could not be updated')
  43 + format.html { render :action => 'edit' }
45 end 44 end
46 end 45 end
47 end 46 end
@@ -67,82 +66,4 @@ class CustomFormsPluginMyprofileController &lt; MyProfileController @@ -67,82 +66,4 @@ class CustomFormsPluginMyprofileController &lt; MyProfileController
67 @form = @submission.form 66 @form = @submission.form
68 end 67 end
69 68
70 - private  
71 -  
72 - def new_fields(params)  
73 - keys = params[:fields].keys.sort{|a, b| a.to_i <=> b.to_i}  
74 - result = keys.map { |id| (hash = params[:fields][id]).has_key?(:real_id) ? nil : hash}.compact  
75 - result.delete_if {|field| field[:name].blank?}  
76 - result  
77 - end  
78 -  
79 - def edited_fields(params)  
80 - params[:fields].map {|id, hash| hash.has_key?(:real_id) ? hash : nil}.compact  
81 - end  
82 -  
83 - def create_fields(fields)  
84 - fields.each do |field|  
85 - case field[:type]  
86 - when 'text_field'  
87 - CustomFormsPlugin::TextField.create!(field)  
88 - when 'select_field'  
89 - CustomFormsPlugin::SelectField.create!(field)  
90 - else  
91 - CustomFormsPlugin::Field.create!(field)  
92 - end  
93 - end  
94 - end  
95 -  
96 - def update_fields(fields)  
97 - fields.each do |field_attrs|  
98 - field = CustomFormsPlugin::Field.find(field_attrs.delete(:real_id))  
99 - field.attributes = field_attrs  
100 - field.save! if field.changed?  
101 - end  
102 - end  
103 -  
104 - def format_kind(fields)  
105 - fields.each do |id, field|  
106 - next if field[:kind].blank?  
107 - kind = field.delete(:kind)  
108 - case kind  
109 - when 'radio'  
110 - field[:list] = false  
111 - field[:multiple] = false  
112 - when 'check_box'  
113 - field[:list] = false  
114 - field[:multiple] = true  
115 - when 'select'  
116 - field[:list] = true  
117 - field[:multiple] = false  
118 - when 'multiple_select'  
119 - field[:list] = true  
120 - field[:multiple] = true  
121 - end  
122 - end  
123 - fields  
124 - end  
125 -  
126 - def format_choices(fields)  
127 - fields.each do |id, field|  
128 - next if !field.has_key?(:choices)  
129 - field[:choices] = field[:choices].map {|key, value| value}.inject({}) do |result, choice|  
130 - hash = (choice[:name].blank? || choice[:value].blank?) ? {} : {choice[:name] => choice[:value]}  
131 - result.merge!(hash)  
132 - end  
133 - end  
134 - fields  
135 - end  
136 -  
137 - def remove_fields(params, form)  
138 - present_fields = params[:fields].map{|id, value| value}.collect {|field| field[:real_id]}.compact  
139 - form.fields.each {|field| field.destroy if !present_fields.include?(field.id.to_s) }  
140 - end  
141 -  
142 - def set_form_id(fields, form_id)  
143 - fields.each do |id, field|  
144 - field[:form_id] = form_id  
145 - end  
146 - fields  
147 - end  
148 end 69 end
plugins/custom_forms/controllers/custom_forms_plugin_profile_controller.rb
1 class CustomFormsPluginProfileController < ProfileController 1 class CustomFormsPluginProfileController < ProfileController
2 -  
3 before_filter :has_access, :show 2 before_filter :has_access, :show
4 3
5 def show 4 def show
  5 + extend(CustomFormsPlugin::Helper)
  6 +
6 @form = CustomFormsPlugin::Form.find(params[:id]) 7 @form = CustomFormsPlugin::Form.find(params[:id])
7 if user 8 if user
8 @submission ||= CustomFormsPlugin::Submission.find_by_form_id_and_profile_id(@form.id,user.id) 9 @submission ||= CustomFormsPlugin::Submission.find_by_form_id_and_profile_id(@form.id,user.id)
@@ -10,22 +11,33 @@ class CustomFormsPluginProfileController &lt; ProfileController @@ -10,22 +11,33 @@ class CustomFormsPluginProfileController &lt; ProfileController
10 else 11 else
11 @submission ||= CustomFormsPlugin::Submission.new(:form_id => @form.id) 12 @submission ||= CustomFormsPlugin::Submission.new(:form_id => @form.id)
12 end 13 end
  14 +
  15 + # build the answers
  16 + @submission.answers.push(*(answers = build_answers(params[:submission], @form))) if params[:submission]
  17 +
13 if request.post? 18 if request.post?
14 begin 19 begin
15 - extend(CustomFormsPlugin::Helper)  
16 - answers = build_answers(params[:submission], @form) 20 + raise 'Submission already present!' if CustomFormsPlugin::Submission.find_by_form_id_and_profile_id(@form.id,user.id)
  21 +
  22 + # @submission.answers for some reason has the same answer twice
17 failed_answers = answers.select {|answer| !answer.valid? } 23 failed_answers = answers.select {|answer| !answer.valid? }
  24 +
18 if failed_answers.empty? 25 if failed_answers.empty?
19 - if !user  
20 - @submission.author_name = params[:author_name]  
21 - @submission.author_email = params[:author_email] 26 + # Save the submission
  27 + ActiveRecord::Base.transaction do
  28 + if !user
  29 + @submission.author_name = params[:author_name]
  30 + @submission.author_email = params[:author_email]
  31 + end
  32 + @submission.save!
22 end 33 end
23 - @submission.save!  
24 - answers.map {|answer| answer.submission = @submission; answer.save!}  
25 else 34 else
26 - @submission.valid? 35 + @submission.errors.clear
27 failed_answers.each do |answer| 36 failed_answers.each do |answer|
28 - @submission.errors.add(answer.field.name.to_sym, answer.errors[answer.field.slug.to_sym]) 37 + answer.valid?
  38 + answer.errors.each do |attribute, msg|
  39 + @submission.errors.add(answer.field.id.to_s.to_sym, msg)
  40 + end
29 end 41 end
30 raise 'Submission failed: answers not valid' 42 raise 'Submission failed: answers not valid'
31 end 43 end
plugins/custom_forms/db/migrate/20130823134700_create_custom_forms_plugin_alternatives.rb 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +class CreateCustomFormsPluginAlternatives < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :custom_forms_plugin_alternatives do |t|
  4 + t.string :label
  5 + t.references :field
  6 + end
  7 + end
  8 +
  9 + def self.down
  10 + drop_table :custom_forms_plugin_alternatives
  11 + end
  12 +end
plugins/custom_forms/db/migrate/20130823135600_add_select_field_type_to_custom_forms_plugin_fields.rb 0 → 100644
@@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
  1 +class AddSelectFieldTypeToCustomFormsPluginFields < ActiveRecord::Migration
  2 + def self.up
  3 + change_table :custom_forms_plugin_fields do |t|
  4 + t.remove :position
  5 + t.string :select_field_type
  6 + end
  7 +
  8 + CustomFormsPlugin::Field.find_each do |f|
  9 + if !f.list && !f.multiple
  10 + f.select_field_type = :radio
  11 + elsif !f.list && f.multiple
  12 + f.select_field_type = :check_box
  13 + elsif f.list && !f.multiple
  14 + f.select_field_type = :select
  15 + else
  16 + f.select_field_type = :multiple_select
  17 + end
  18 + f.save!
  19 + end
  20 +
  21 + change_table :custom_forms_plugin_fields do |t|
  22 + t.remove :multiple, :list
  23 + end
  24 + end
  25 +
  26 + def self.down
  27 + raise ActiveRecord::IrreversibleMigration
  28 + end
  29 +end
plugins/custom_forms/db/migrate/20130823151900_associate_fields_to_alternatives.rb 0 → 100644
@@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
  1 +class AssociateFieldsToAlternatives < ActiveRecord::Migration
  2 + class CustomFormsPlugin::Field < ActiveRecord::Base
  3 + set_table_name :custom_forms_plugin_fields
  4 + has_many :alternatives, :class_name => 'CustomFormsPlugin::Alternative'
  5 + serialize :choices, Hash
  6 + end
  7 +
  8 + def self.up
  9 + CustomFormsPlugin::Field.reset_column_information
  10 +
  11 + CustomFormsPlugin::Field.find_each do |f|
  12 + f.choices.each do |key, value|
  13 + CustomFormsPlugin::Alternative.create!(:label => key, :field_id => f.id)
  14 + end
  15 + end
  16 +
  17 + change_table :custom_forms_plugin_fields do |t|
  18 + t.remove :choices
  19 + end
  20 + end
  21 +
  22 + def self.down
  23 + raise ActiveRecord::IrreversibleMigration
  24 + end
  25 +end
plugins/custom_forms/db/migrate/20131002155900_update_select_field_type_in_custom_forms_plugin_fields.rb 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +class UpdateSelectFieldTypeInCustomFormsPluginFields < ActiveRecord::Migration
  2 + def self.up
  3 + change_column :custom_forms_plugin_fields, :select_field_type, :string, :null => false, :default => 'radio'
  4 + end
  5 +
  6 + def self.down
  7 + raise ActiveRecord::IrreversibleMigration
  8 + end
  9 +end
plugins/custom_forms/db/migrate/20131007120600_add_selected_by_default_to_custom_forms_plugin_alternatives.rb 0 → 100644
@@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
  1 +class AddSelectedByDefaultToCustomFormsPluginAlternatives < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :custom_forms_plugin_alternatives, :selected_by_default, :boolean, :null => false, :default => false
  4 + CustomFormsPlugin::Field.find_each do |f|
  5 + f.alternatives.each do |a|
  6 + a.update_attribute(:selected_by_default, true) if a.label == f.default_value
  7 + end
  8 + end
  9 + end
  10 +
  11 + def self.down
  12 + raise ActiveRecord::IrreversibleMigration
  13 + end
  14 +end
plugins/custom_forms/lib/custom_forms_plugin/alternative.rb 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +class CustomFormsPlugin::Alternative < ActiveRecord::Base
  2 + set_table_name :custom_forms_plugin_alternatives
  3 +
  4 + validates_presence_of :label
  5 +
  6 + belongs_to :field, :class_name => 'CustomFormsPlugin::Field'
  7 +end
  8 +
plugins/custom_forms/lib/custom_forms_plugin/answer.rb
@@ -7,7 +7,7 @@ class CustomFormsPlugin::Answer &lt; Noosfero::Plugin::ActiveRecord @@ -7,7 +7,7 @@ class CustomFormsPlugin::Answer &lt; Noosfero::Plugin::ActiveRecord
7 7
8 def value_mandatory 8 def value_mandatory
9 if field.mandatory && value.blank? 9 if field.mandatory && value.blank?
10 - errors.add(field.slug.to_sym, _("is mandatory.").fix_i18n) 10 + errors.add(:value, _("is mandatory.").fix_i18n)
11 end 11 end
12 end 12 end
13 end 13 end
plugins/custom_forms/lib/custom_forms_plugin/field.rb
1 class CustomFormsPlugin::Field < ActiveRecord::Base 1 class CustomFormsPlugin::Field < ActiveRecord::Base
2 set_table_name :custom_forms_plugin_fields 2 set_table_name :custom_forms_plugin_fields
3 3
4 - validates_presence_of :form, :name  
5 - validates_uniqueness_of :slug, :scope => :form_id 4 + validates_presence_of :name
6 5
7 belongs_to :form, :class_name => 'CustomFormsPlugin::Form' 6 belongs_to :form, :class_name => 'CustomFormsPlugin::Form'
8 has_many :answers, :class_name => 'CustomFormsPlugin::Answer' 7 has_many :answers, :class_name => 'CustomFormsPlugin::Answer'
9 8
10 - serialize :choices, Hash 9 + has_many :alternatives, :class_name => 'CustomFormsPlugin::Alternative'
  10 + accepts_nested_attributes_for :alternatives, :allow_destroy => true
11 11
12 before_validation do |field| 12 before_validation do |field|
13 field.slug = field.name.to_slug if field.name.present? 13 field.slug = field.name.to_slug if field.name.present?
14 end 14 end
15 15
16 - before_create do |field|  
17 - if field.form.fields.exists?  
18 - field.position = field.form.fields.order(:position).last.position + 1  
19 - end  
20 - end 16 + private
21 17
22 - def position  
23 - self[:position] || 0 18 + def attributes_protected_by_default
  19 + super - [self.class.inheritance_column]
24 end 20 end
  21 +
25 end 22 end
26 23
plugins/custom_forms/lib/custom_forms_plugin/form.rb
1 class CustomFormsPlugin::Form < Noosfero::Plugin::ActiveRecord 1 class CustomFormsPlugin::Form < Noosfero::Plugin::ActiveRecord
2 belongs_to :profile 2 belongs_to :profile
3 3
4 - has_many :fields, :class_name => 'CustomFormsPlugin::Field', :dependent => :destroy, :order => 'position' 4 + has_many :fields, :class_name => 'CustomFormsPlugin::Field', :dependent => :destroy
  5 + accepts_nested_attributes_for :fields, :allow_destroy => true
  6 +
5 has_many :submissions, :class_name => 'CustomFormsPlugin::Submission' 7 has_many :submissions, :class_name => 'CustomFormsPlugin::Submission'
6 8
7 serialize :access 9 serialize :access
plugins/custom_forms/lib/custom_forms_plugin/helper.rb
1 module CustomFormsPlugin::Helper 1 module CustomFormsPlugin::Helper
  2 + def html_for_field(builder, association, klass)
  3 + new_object = klass.new
  4 + builder.fields_for(association, new_object, :child_index => "new_#{association}") do |f|
  5 + render(partial_for_class(klass), :f => f)
  6 + end
  7 + end
  8 +
2 def access_text(form) 9 def access_text(form)
3 return _('Public') if form.access.nil? 10 return _('Public') if form.access.nil?
4 return _('Logged users') if form.access == 'logged' 11 return _('Logged users') if form.access == 'logged'
@@ -48,8 +55,8 @@ module CustomFormsPlugin::Helper @@ -48,8 +55,8 @@ module CustomFormsPlugin::Helper
48 55
49 def type_to_label(type) 56 def type_to_label(type)
50 map = { 57 map = {
51 - 'text_field' => _('Text'),  
52 - 'select_field' => _('Select') 58 + 'text_field' => _('Text field'),
  59 + 'select_field' => _('Select field')
53 } 60 }
54 map[type_for_options(type)] 61 map[type_for_options(type)]
55 end 62 end
@@ -61,52 +68,53 @@ module CustomFormsPlugin::Helper @@ -61,52 +68,53 @@ module CustomFormsPlugin::Helper
61 def display_custom_field(field, submission, form) 68 def display_custom_field(field, submission, form)
62 answer = submission.answers.select{|answer| answer.field == field}.first 69 answer = submission.answers.select{|answer| answer.field == field}.first
63 field_tag = send("display_#{type_for_options(field.class)}",field, answer, form) 70 field_tag = send("display_#{type_for_options(field.class)}",field, answer, form)
64 - if field.mandatory? && !radio_button?(field) && !check_box?(field) && submission.id.nil? 71 + if field.mandatory? && submission.id.nil?
65 required(labelled_form_field(field.name, field_tag)) 72 required(labelled_form_field(field.name, field_tag))
66 - else 73 + else
67 labelled_form_field(field.name, field_tag) 74 labelled_form_field(field.name, field_tag)
68 end 75 end
69 end 76 end
70 77
71 def display_text_field(field, answer, form) 78 def display_text_field(field, answer, form)
72 value = answer.present? ? answer.value : field.default_value 79 value = answer.present? ? answer.value : field.default_value
73 - text_field(form, field.name.to_slug, :value => value, :disabled => answer.present?) 80 + text_field(form, "#{field.id}", :value => value, :disabled => answer.present? && answer.id.present?)
74 end 81 end
75 82
76 def display_select_field(field, answer, form) 83 def display_select_field(field, answer, form)
77 - if field.list && field.multiple  
78 - selected = answer.present? ? answer.value.split(',') : []  
79 - select_tag "#{form}[#{field.name.to_slug}]", options_for_select(field.choices.to_a, selected), :multiple => true, :size => field.choices.size, :disabled => answer.present?  
80 - elsif !field.list && field.multiple  
81 - field.choices.map do |name, value|  
82 - default = answer.present? ? answer.value.split(',').include?(value) : false  
83 - labelled_check_box name, "#{form}[#{field.name.to_slug}][#{value}]", '1', default, :disabled => answer.present? 84 + case field.select_field_type
  85 + when 'multiple_select'
  86 + selected = answer.present? ? answer.value.split(',') : field.alternatives.select {|a| a.selected_by_default}.map{|a| a.id.to_s}
  87 + select_tag "submission[#{field.id}]", options_for_select(field.alternatives.map{|a| [a.label, a.id.to_s]}, selected), :multiple => true, :size => field.alternatives.size, :disabled => answer.present? && answer.id.present?
  88 + when 'check_box'
  89 + field.alternatives.map do |alternative|
  90 + default = answer.present? ? answer.value.split(',').include?(alternative.id.to_s) : alternative.selected_by_default
  91 + labelled_check_box alternative.label, "submission[#{field.id}][#{alternative.id}]", '1', default, :disabled => answer.present? && answer.id.present?
84 end.join("\n") 92 end.join("\n")
85 - elsif field.list && !field.multiple  
86 - selected = answer.present? ? answer.value.split(',') : []  
87 - select_tag "#{form}[#{field.name.to_slug}]", options_for_select([['','']] + field.choices.to_a, selected), :disabled => answer.present?  
88 - elsif !field.list && !field.multiple  
89 - field.choices.map do |name, value|  
90 - default = answer.present? ? answer.value == value : true  
91 - labelled_radio_button name, "#{form}[#{field.name.to_slug}]", value, default, :disabled => answer.present? 93 + when 'select'
  94 + selected = answer.present? ? answer.value.split(',') : field.alternatives.select {|a| a.selected_by_default}.map{|a| a.id.to_s}
  95 + select_tag "submission[#{field.id}]", options_for_select([['','']] + field.alternatives.map {|a| [a.label, a.id.to_s]}, selected), :disabled => answer.present? && answer.id.present?
  96 + when 'radio'
  97 + field.alternatives.map do |alternative|
  98 + default = answer.present? ? answer.value == alternative.id.to_s : alternative.selected_by_default
  99 + labelled_radio_button alternative.label, "submission[#{field.id}]", alternative.id, default, :disabled => answer.present? && answer.id.present?
92 end.join("\n") 100 end.join("\n")
93 end 101 end
94 end 102 end
95 103
96 def radio_button?(field) 104 def radio_button?(field)
97 - type_for_options(field.class) == 'select_field' && !field.list && !field.multiple 105 + type_for_options(field.class) == 'select_field' && field.select_field_type == 'radio'
98 end 106 end
99 107
100 def check_box?(field) 108 def check_box?(field)
101 - type_for_options(field.class) == 'select_field' && !field.list && field.multiple 109 + type_for_options(field.class) == 'select_field' && field.select_field_type == 'check_box'
102 end 110 end
103 111
104 def build_answers(submission, form) 112 def build_answers(submission, form)
105 answers = [] 113 answers = []
106 form.fields.each do |field| 114 form.fields.each do |field|
107 final_value = '' 115 final_value = ''
108 - if submission.has_key?(field.slug)  
109 - value = submission[field.slug] 116 + if submission.has_key?(field.id.to_s)
  117 + value = submission[field.id.to_s]
110 if value.kind_of?(String) 118 if value.kind_of?(String)
111 final_value = value 119 final_value = value
112 elsif value.kind_of?(Array) 120 elsif value.kind_of?(Array)
plugins/custom_forms/lib/custom_forms_plugin/select_field.rb
1 class CustomFormsPlugin::SelectField < CustomFormsPlugin::Field 1 class CustomFormsPlugin::SelectField < CustomFormsPlugin::Field
2 set_table_name :custom_forms_plugin_fields 2 set_table_name :custom_forms_plugin_fields
3 - validates_presence_of :choices 3 +
  4 + validates_length_of :select_field_type, :minimum => 1, :allow_nil => false
  5 + validates_inclusion_of :select_field_type, :in => %w(radio check_box select multiple_select)
4 end 6 end
plugins/custom_forms/lib/custom_forms_plugin/submission.rb
@@ -2,11 +2,20 @@ class CustomFormsPlugin::Submission &lt; Noosfero::Plugin::ActiveRecord @@ -2,11 +2,20 @@ class CustomFormsPlugin::Submission &lt; Noosfero::Plugin::ActiveRecord
2 belongs_to :form, :class_name => 'CustomFormsPlugin::Form' 2 belongs_to :form, :class_name => 'CustomFormsPlugin::Form'
3 belongs_to :profile 3 belongs_to :profile
4 4
5 - has_many :answers, :class_name => 'CustomFormsPlugin::Answer' 5 + has_many :answers, :class_name => 'CustomFormsPlugin::Answer', :dependent => :destroy
6 6
7 validates_presence_of :form 7 validates_presence_of :form
8 validates_presence_of :author_name, :author_email, :if => lambda {|submission| submission.profile.nil?} 8 validates_presence_of :author_name, :author_email, :if => lambda {|submission| submission.profile.nil?}
9 validates_uniqueness_of :author_email, :scope => :form_id, :allow_nil => true 9 validates_uniqueness_of :author_email, :scope => :form_id, :allow_nil => true
10 validates_format_of :author_email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda {|submission| !submission.author_email.blank?}) 10 validates_format_of :author_email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda {|submission| !submission.author_email.blank?})
  11 +
  12 + def self.human_attribute_name(attrib)
  13 + if /\d+/ =~ attrib and (f = CustomFormsPlugin::Field.find_by_id(attrib.to_i))
  14 + f.name
  15 + else
  16 + attrib
  17 + end
  18 + end
  19 +
11 end 20 end
12 21
plugins/custom_forms/public/field.js
1 -jQuery('.icon-edit').live('click', function() {  
2 - elem = this;  
3 - jQuery.fn.colorbox({  
4 - overlayClose: false,  
5 - escKey: false,  
6 - inline: true,  
7 - href: function(){  
8 - id = jQuery(elem).attr('field_id');  
9 - type = jQuery('#fields_'+id+'_type').val().split('_')[0];  
10 - selector = '#edit-'+type+'-'+id  
11 - return selector 1 +var customFormsPlugin = {
  2 + removeFieldBox: function (button, confirmMsg) {
  3 + if (confirm(confirmMsg)) {
  4 + fb = jQuery(button).closest('.field-box');
  5 + jQuery('input.destroy-field', fb).val(1);
  6 + jQuery('> div', fb).slideUp({easing:'linear', complete:function(){fb.slideUp({easing:'linear', duration:250})}});
12 } 7 }
13 - });  
14 - return false;  
15 -});  
16 -  
17 -jQuery('.remove-field').live('click', function(){  
18 - id = jQuery(this).attr('field_id');  
19 - jQuery('#field-'+id).slideDown(function(){  
20 - jQuery('#field-'+id).remove();  
21 - });  
22 - return false  
23 -});  
24 -  
25 -jQuery('.remove-option').live('click', function(){  
26 - field_id = jQuery(this).attr('field_id');  
27 - option_id = jQuery(this).attr('option_id');  
28 - selector = '#field-'+field_id+'-option-'+option_id  
29 - jQuery(selector).slideDown(function(){  
30 - jQuery(selector).remove();  
31 - jQuery.colorbox.resize();  
32 - });  
33 - return false  
34 -});  
35 -  
36 -function updateEditText(id){  
37 - new_id = id+1  
38 - jQuery('#edit-text-'+id).attr('id', 'edit-text-'+new_id);  
39 - input = jQuery('#edit-text-'+new_id+' input');  
40 - jQuery('#edit-text-'+new_id+' .colorbox-ok-button').attr('div_id', 'edit-text-'+new_id);  
41 - input.attr('id', input.attr('id').replace(id,new_id));  
42 - input.attr('name', input.attr('name').replace(id,new_id));  
43 - label = jQuery('#edit-text-'+new_id+' label');  
44 - label.attr('for', label.attr('for').replace(id,new_id));  
45 -}  
46 -  
47 -function updateEditSelect(id){  
48 - new_id = id+1  
49 - jQuery('#edit-select-'+id).attr('id', 'edit-select-'+new_id);  
50 - jQuery('#edit-select-'+new_id+' .colorbox-ok-button').attr('div_id', 'edit-select-'+new_id);  
51 - jQuery('tr[id^=field-'+id+'-option').each(function(id, element){  
52 - jQuery(element).attr('id', jQuery(element).attr('id').replace('field-'+id,'field-'+new_id));  
53 - });  
54 - jQuery('#edit-select-'+new_id+' label').each(function(index, element){  
55 - label = jQuery(element);  
56 - label.attr('for', label.attr('for').replace(id,new_id));  
57 - });  
58 - jQuery('#edit-select-'+new_id+' input').each(function(index, element){  
59 - input = jQuery(element);  
60 - input.attr('id', input.attr('id').replace(id,new_id));  
61 - input.attr('name', input.attr('name').replace(id,new_id));  
62 - });  
63 - jQuery('#edit-select-'+new_id+' .remove-option').each(function(index, element){  
64 - jQuery(element).attr('field_id',new_id);  
65 - });  
66 - jQuery('#edit-select-'+new_id+' .new-option').attr('field_id',new_id);  
67 - jQuery('#edit-select-'+new_id+' #empty-option-'+id).attr('id','empty-option-'+new_id);  
68 -}  
69 -  
70 -function updateEmptyField(id){  
71 - id = parseInt(id);  
72 - empty_field = jQuery('#empty-field');  
73 - empty_field.attr('last_id', (id + 1).toString());  
74 - jQuery('#empty-field input').each(function(index, element){  
75 - new_id = jQuery(element).attr('id').replace(id,id+1);  
76 - jQuery(element).attr('id', new_id);  
77 - new_name = jQuery(element).attr('name').replace(id,id+1);  
78 - jQuery(element).attr('name', new_name);  
79 - });  
80 - jQuery('#empty-field select').each(function(index, element){  
81 - new_id = jQuery(element).attr('id').replace(id,id+1);  
82 - jQuery(element).attr('id', new_id);  
83 - new_name = jQuery(element).attr('name').replace(id,id+1);  
84 - jQuery(element).attr('name', new_name);  
85 - });  
86 - jQuery('#empty-field a').each(function(index, element){  
87 - jQuery(element).attr('field_id', id+1);  
88 - });  
89 - updateEditText(id);  
90 - updateEditSelect(id);  
91 -}  
92 -  
93 -function updateEmptyOption(field_id, option_id){  
94 - field_id = parseInt(field_id);  
95 - option_id = parseInt(option_id);  
96 - new_option_id = option_id+1;  
97 - empty_option = jQuery('#empty-option-'+field_id);  
98 - empty_option.attr('option_id',new_option_id);  
99 - jQuery('#empty-option-'+field_id+' .remove-option').attr('option_id', new_option_id); 8 + },
  9 +
  10 + removeAlternative: function (button, confirmMsg) {
  11 + if (confirm(confirmMsg)) {
  12 + alt = jQuery(button).closest('tr.alternative');
  13 + jQuery('input.destroy-field', alt).val(1);
  14 + alt.fadeOut(500, function() {
  15 + customFormsPlugin.checkHeaderDisplay(jQuery(button).closest('table'));
  16 + });
  17 + }
  18 + },
100 19
101 - name_id = ' #fields_'+field_id+'_choices_'+option_id+'_name';  
102 - jQuery('#empty-option-'+field_id+name_id).attr('name', 'fields['+field_id+'][choices]['+new_option_id+'][name]');  
103 - jQuery('#empty-option-'+field_id+name_id).attr('id', 'fields_'+field_id+'_choices_'+new_option_id+'_name'); 20 + addFields: function (button, association, content) {
  21 + var new_id = new Date().getTime();
  22 + var regexp = new RegExp("new_" + association, "g");
  23 + jQuery(content.replace(regexp, new_id)).insertBefore(jQuery(button).closest('.addition-buttons')).hide().slideDown();
104 24
105 - value_id = ' #fields_'+field_id+'_choices_'+option_id+'_value';  
106 - jQuery('#empty-option-'+field_id+value_id).attr('name', 'fields['+field_id+'][choices]['+new_option_id+'][value]');  
107 - jQuery('#empty-option-'+field_id+value_id).attr('id', 'fields_'+field_id+'_choices_'+new_option_id+'_value'); 25 + if(association == 'alternatives') {
  26 + jQuery(button).closest('table').find('tr:first').show();
  27 + }
  28 + },
  29 +
  30 + checkHeaderDisplay: function(table) {
  31 + trs =jQuery('tr:visible', table);
  32 + if (trs.length <= 2) {
  33 + trs[0].style.display = 'none';
  34 + } else {
  35 + trs[0].style.display = 'table-row';
  36 + }
  37 + }
108 } 38 }
109 -  
110 -jQuery('#new-field').live('click', function(){  
111 - empty_field = jQuery('#empty-field');  
112 - id = empty_field.attr('last_id');  
113 - edit_text = jQuery('#edit-text-'+id);  
114 - edit_select = jQuery('#edit-select-'+id);  
115 - new_field = empty_field.clone();  
116 - new_field.attr('id','field-'+id);  
117 - new_field.insertBefore(empty_field).slideDown();  
118 - edit_text.clone().insertAfter(edit_text);  
119 - edit_select.clone().insertAfter(edit_select);  
120 - updateEmptyField(id);  
121 - return false  
122 -});  
123 -  
124 -jQuery('.new-option').live('click', function(){  
125 - field_id = jQuery(this).attr('field_id');  
126 - empty_option = jQuery('#empty-option-'+field_id);  
127 - option_id = empty_option.attr('option_id');  
128 - new_option = empty_option.clone();  
129 - new_option.attr('id','field-'+field_id+'-option-'+option_id);  
130 - new_option.insertBefore(empty_option).slideDown();  
131 - jQuery.colorbox.resize();  
132 - updateEmptyOption(field_id, option_id);  
133 - return false  
134 -});  
135 -  
136 -jQuery('.colorbox-ok-button').live('click', function(){  
137 - jQuery('#'+jQuery(this).attr('div_id')).hide();  
138 - jQuery.colorbox.close();  
139 - return false  
140 -});  
plugins/custom_forms/public/style.css
@@ -31,3 +31,27 @@ @@ -31,3 +31,27 @@
31 #colorbox .edit-information { 31 #colorbox .edit-information {
32 display: block; 32 display: block;
33 } 33 }
  34 +
  35 +.field-box {
  36 + margin: 10px 0;
  37 +}
  38 +
  39 +.field-box > div {
  40 + overflow: hide;
  41 +}
  42 +
  43 +.field-box .button {
  44 + margin-left: 15px;
  45 +}
  46 +
  47 +.field-box .addition-buttons .button {
  48 + margin: 0px;
  49 +}
  50 +
  51 +.field-select-type {
  52 + margin: 10px 0;
  53 +}
  54 +
  55 +.field-text-default {
  56 + margin-top: 10px;
  57 +}
plugins/custom_forms/test/functional/custom_forms_plugin_myprofile_controller_test.rb
@@ -48,21 +48,22 @@ class CustomFormsPluginMyprofileControllerTest &lt; ActionController::TestCase @@ -48,21 +48,22 @@ class CustomFormsPluginMyprofileControllerTest &lt; ActionController::TestCase
48 :access => 'logged', 48 :access => 'logged',
49 :begining => begining, 49 :begining => begining,
50 :ending => ending, 50 :ending => ending,
51 - :description => 'Cool form'},  
52 - :fields => {  
53 - 1 => {  
54 - :name => 'Name',  
55 - :default_value => 'Jack',  
56 - :type => 'text_field'  
57 - },  
58 - 2 => {  
59 - :name => 'Color',  
60 - :list => '1',  
61 - :type => 'select_field',  
62 - :choices => {  
63 - 1 => {:name => 'Red', :value => 'red'},  
64 - 2 => {:name => 'Blue', :value => 'blue'},  
65 - 3 => {:name => 'Black', :value => 'black'} 51 + :description => 'Cool form',
  52 + :fields_attributes => {
  53 + 1 => {
  54 + :name => 'Name',
  55 + :default_value => 'Jack',
  56 + :type => 'CustomFormsPlugin::TextField'
  57 + },
  58 + 2 => {
  59 + :name => 'Color',
  60 + :select_field_type => 'radio',
  61 + :type => 'CustomFormsPlugin::SelectField',
  62 + :alternatives_attributes => {
  63 + 1 => {:label => 'Red'},
  64 + 2 => {:label => 'Blue'},
  65 + 3 => {:label => 'Black'}
  66 + }
66 } 67 }
67 } 68 }
68 } 69 }
@@ -83,10 +84,8 @@ class CustomFormsPluginMyprofileControllerTest &lt; ActionController::TestCase @@ -83,10 +84,8 @@ class CustomFormsPluginMyprofileControllerTest &lt; ActionController::TestCase
83 assert f1.kind_of?(CustomFormsPlugin::TextField) 84 assert f1.kind_of?(CustomFormsPlugin::TextField)
84 85
85 assert_equal 'Color', f2.name 86 assert_equal 'Color', f2.name
86 - assert_equal 'red', f2.choices['Red']  
87 - assert_equal 'blue', f2.choices['Blue']  
88 - assert_equal 'black', f2.choices['Black']  
89 - assert f2.list 87 + assert_equal f2.alternatives.map(&:label).sort, ['Red', 'Blue', 'Black'].sort
  88 + assert_equal f2.select_field_type, 'radio'
90 assert f2.kind_of?(CustomFormsPlugin::SelectField) 89 assert f2.kind_of?(CustomFormsPlugin::SelectField)
91 end 90 end
92 91
@@ -100,7 +99,7 @@ class CustomFormsPluginMyprofileControllerTest &lt; ActionController::TestCase @@ -100,7 +99,7 @@ class CustomFormsPluginMyprofileControllerTest &lt; ActionController::TestCase
100 fields[i.to_s] = { 99 fields[i.to_s] = {
101 :name => i.to_s, 100 :name => i.to_s,
102 :default_value => '', 101 :default_value => '',
103 - :type => 'text_field' 102 + :type => 'CustomFormsPlugin::TextField'
104 } 103 }
105 end 104 end
106 assert_difference CustomFormsPlugin::Form, :count, 1 do 105 assert_difference CustomFormsPlugin::Form, :count, 1 do
@@ -110,29 +109,35 @@ class CustomFormsPluginMyprofileControllerTest &lt; ActionController::TestCase @@ -110,29 +109,35 @@ class CustomFormsPluginMyprofileControllerTest &lt; ActionController::TestCase
110 :access => 'logged', 109 :access => 'logged',
111 :begining => begining, 110 :begining => begining,
112 :ending => ending, 111 :ending => ending,
113 - :description => 'Cool form'},  
114 - :fields => fields 112 + :description => 'Cool form',
  113 + :fields_attributes => fields
  114 + }
115 end 115 end
116 form = CustomFormsPlugin::Form.find_by_name('My Form') 116 form = CustomFormsPlugin::Form.find_by_name('My Form')
117 assert_equal num_fields, form.fields.count 117 assert_equal num_fields, form.fields.count
  118 + lst = -1
118 form.fields.find_each do |f| 119 form.fields.find_each do |f|
119 - assert_equal f.position, f.name.to_i 120 + assert f.name.to_i > lst
  121 + lst = f.name.to_i
120 end 122 end
121 end 123 end
122 124
123 should 'edit a form' do 125 should 'edit a form' do
124 form = CustomFormsPlugin::Form.create!(:profile => profile, :name => 'Free Software') 126 form = CustomFormsPlugin::Form.create!(:profile => profile, :name => 'Free Software')
125 - field = CustomFormsPlugin::TextField.create!(:form => form, :name => 'License')  
126 format = '%Y-%m-%d %H:%M' 127 format = '%Y-%m-%d %H:%M'
127 begining = Time.now.strftime(format) 128 begining = Time.now.strftime(format)
128 ending = (Time.now + 1.day).strftime(format) 129 ending = (Time.now + 1.day).strftime(format)
129 130
130 - post :edit, :profile => profile.identifier, :id => form.id,  
131 - :form => {:name => 'My Form', :access => 'logged', :begining => begining, :ending => ending, :description => 'Cool form'},  
132 - :fields => {1 => {:real_id => field.id.to_s, :name => 'Source'}} 131 + assert_equal form.fields.length, 0
  132 +
  133 + post :update, :profile => profile.identifier, :id => form.id,
  134 + :form => {:name => 'My Form', :access => 'logged', :begining => begining, :ending => ending, :description => 'Cool form',
  135 + :fields_attributes => {1 => {:name => 'Source'}}}
133 136
134 form.reload 137 form.reload
135 - field.reload 138 + assert_equal form.fields.length, 1
  139 +
  140 + field = form.fields.last
136 141
137 assert_equal 'logged', form.access 142 assert_equal 'logged', form.access
138 assert_equal begining, form.begining.strftime(format) 143 assert_equal begining, form.begining.strftime(format)
plugins/custom_forms/test/functional/custom_forms_plugin_profile_controller_test.rb
@@ -23,7 +23,7 @@ class CustomFormsPluginProfileControllerTest &lt; ActionController::TestCase @@ -23,7 +23,7 @@ class CustomFormsPluginProfileControllerTest &lt; ActionController::TestCase
23 field2 = CustomFormsPlugin::TextField.create(:name => 'License', :form => form) 23 field2 = CustomFormsPlugin::TextField.create(:name => 'License', :form => form)
24 24
25 assert_difference CustomFormsPlugin::Submission, :count, 1 do 25 assert_difference CustomFormsPlugin::Submission, :count, 1 do
26 - post :show, :profile => profile.identifier, :id => form.id, :submission => {field1.name.to_slug => 'Noosfero', field2.name.to_slug => 'GPL'} 26 + post :show, :profile => profile.identifier, :id => form.id, :submission => {field1.id.to_s => 'Noosfero', field2.id.to_s => 'GPL'}
27 end 27 end
28 assert !session[:notice].include?('not saved') 28 assert !session[:notice].include?('not saved')
29 assert_redirected_to :action => 'show' 29 assert_redirected_to :action => 'show'
plugins/custom_forms/test/unit/custom_forms_plugin/answer_test.rb
@@ -27,11 +27,11 @@ class CustomFormsPlugin::AnswerTest &lt; ActiveSupport::TestCase @@ -27,11 +27,11 @@ class CustomFormsPlugin::AnswerTest &lt; ActiveSupport::TestCase
27 field = CustomFormsPlugin::Field.create!(:name => 'License', :form => form, :mandatory => true) 27 field = CustomFormsPlugin::Field.create!(:name => 'License', :form => form, :mandatory => true)
28 answer = CustomFormsPlugin::Answer.new(:field => field) 28 answer = CustomFormsPlugin::Answer.new(:field => field)
29 answer.valid? 29 answer.valid?
30 - assert answer.errors.invalid?(field.slug.to_sym) 30 + assert answer.errors.invalid?(:value)
31 31
32 answer.value = "GPL" 32 answer.value = "GPL"
33 answer.valid? 33 answer.valid?
34 - assert !answer.errors.invalid?(field.slug.to_sym) 34 + assert !answer.errors.invalid?(:value)
35 end 35 end
36 36
37 end 37 end
plugins/custom_forms/test/unit/custom_forms_plugin/field_test.rb
1 require File.dirname(__FILE__) + '/../../../../../test/test_helper' 1 require File.dirname(__FILE__) + '/../../../../../test/test_helper'
2 2
3 class CustomFormsPlugin::FieldTest < ActiveSupport::TestCase 3 class CustomFormsPlugin::FieldTest < ActiveSupport::TestCase
4 - should 'validate presence of form' do  
5 - field = CustomFormsPlugin::Field.new  
6 - field.valid?  
7 - assert field.errors.invalid?(:form)  
8 - assert field.errors.invalid?(:name)  
9 -  
10 - form = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => fast_create(Profile))  
11 - field.form = form  
12 - field.name = 'License'  
13 - field.valid?  
14 - assert !field.errors.invalid?(:form)  
15 - assert !field.errors.invalid?(:name)  
16 - end  
17 -  
18 should 'set slug before validation based on name' do 4 should 'set slug before validation based on name' do
19 field = CustomFormsPlugin::Field.new(:name => 'Name') 5 field = CustomFormsPlugin::Field.new(:name => 'Name')
20 field.valid? 6 field.valid?
21 assert_equal field.name.to_slug, field.slug 7 assert_equal field.name.to_slug, field.slug
22 end 8 end
23 9
24 - should 'validate uniqueness of slug scoped on the form' do  
25 - form1 = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => fast_create(Profile))  
26 - form2 = CustomFormsPlugin::Form.create!(:name => 'Open Source', :profile => fast_create(Profile))  
27 - f1 = CustomFormsPlugin::Field.create!(:name => 'License', :form => form1)  
28 - f2 = CustomFormsPlugin::Field.new(:name => 'License', :form => form1)  
29 - f3 = CustomFormsPlugin::Field.new(:name => 'License', :form => form2)  
30 -  
31 - f2.valid?  
32 - f3.valid?  
33 -  
34 - assert f2.errors.invalid?(:slug)  
35 - assert !f3.errors.invalid?(:slug)  
36 - end  
37 -  
38 should 'set mandatory field as false by default' do 10 should 'set mandatory field as false by default' do
39 field = CustomFormsPlugin::Field.new 11 field = CustomFormsPlugin::Field.new
40 assert !field.mandatory 12 assert !field.mandatory
@@ -50,17 +22,6 @@ class CustomFormsPlugin::FieldTest &lt; ActiveSupport::TestCase @@ -50,17 +22,6 @@ class CustomFormsPlugin::FieldTest &lt; ActiveSupport::TestCase
50 assert_includes field.answers, a2 22 assert_includes field.answers, a2
51 end 23 end
52 24
53 - should 'serialize choices into a hash' do  
54 - form = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => fast_create(Profile))  
55 - field = CustomFormsPlugin::Field.create!(:name => 'License', :form => form)  
56 - field.choices = {'First' => 1, 'Second' => 2, 'Third' => 3}  
57 - field.save!  
58 -  
59 - assert_equal 1, field.choices['First']  
60 - assert_equal 2, field.choices['Second']  
61 - assert_equal 3, field.choices['Third']  
62 - end  
63 -  
64 should 'not destroy form after removing a field' do 25 should 'not destroy form after removing a field' do
65 form = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => fast_create(Profile)) 26 form = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => fast_create(Profile))
66 license_field = CustomFormsPlugin::Field.create!(:name => 'License', :form => form) 27 license_field = CustomFormsPlugin::Field.create!(:name => 'License', :form => form)
@@ -71,27 +32,5 @@ class CustomFormsPlugin::FieldTest &lt; ActiveSupport::TestCase @@ -71,27 +32,5 @@ class CustomFormsPlugin::FieldTest &lt; ActiveSupport::TestCase
71 end 32 end
72 assert_equal form.fields, [license_field] 33 assert_equal form.fields, [license_field]
73 end 34 end
74 -  
75 - should 'give positions by creation order' do  
76 - form = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => fast_create(Profile))  
77 - field_0 = CustomFormsPlugin::Field.create!(:name => 'License', :form => form)  
78 - field_1 = CustomFormsPlugin::Field.create!(:name => 'URL', :form => form)  
79 - field_2 = CustomFormsPlugin::Field.create!(:name => 'Wiki', :form => form)  
80 - assert_equal 0, field_0.position  
81 - assert_equal 1, field_1.position  
82 - assert_equal 2, field_2.position  
83 - end  
84 -  
85 - should 'not crash when adding new fields on a form with fields without position' do  
86 - form = CustomFormsPlugin::Form.create(:name => 'Free Software', :profile => fast_create(Profile))  
87 - field_0 = CustomFormsPlugin::Field.create(:name => 'License', :form => form)  
88 - field_0.position = nil  
89 - field_0.save  
90 -  
91 - assert_nothing_raised do  
92 - field_1 = CustomFormsPlugin::Field.create!(:name => 'URL', :form => form)  
93 - end  
94 - end  
95 -  
96 end 35 end
97 36
plugins/custom_forms/test/unit/custom_forms_plugin/membership_survey_test.rb
@@ -16,7 +16,7 @@ class CustomFormsPlugin::MembershipSurveyTest &lt; ActiveSupport::TestCase @@ -16,7 +16,7 @@ class CustomFormsPlugin::MembershipSurveyTest &lt; ActiveSupport::TestCase
16 person = fast_create(Person) 16 person = fast_create(Person)
17 form = CustomFormsPlugin::Form.create!(:name => 'Simple Form', :profile => profile) 17 form = CustomFormsPlugin::Form.create!(:name => 'Simple Form', :profile => profile)
18 field = CustomFormsPlugin::Field.create!(:name => 'Name', :form => form) 18 field = CustomFormsPlugin::Field.create!(:name => 'Name', :form => form)
19 - task = CustomFormsPlugin::MembershipSurvey.create!(:form_id => form.id, :submission => {'name' => 'Jack'}, :target => person, :requestor => profile) 19 + task = CustomFormsPlugin::MembershipSurvey.create!(:form_id => form.id, :submission => {field.id.to_s => 'Jack'}, :target => person, :requestor => profile)
20 20
21 assert_difference CustomFormsPlugin::Submission, :count, 1 do 21 assert_difference CustomFormsPlugin::Submission, :count, 1 do
22 task.finish 22 task.finish
plugins/custom_forms/test/unit/custom_forms_plugin/select_field_test.rb
1 require File.dirname(__FILE__) + '/../../../../../test/test_helper' 1 require File.dirname(__FILE__) + '/../../../../../test/test_helper'
2 2
3 class CustomFormsPlugin::SelectFieldTest < ActiveSupport::TestCase 3 class CustomFormsPlugin::SelectFieldTest < ActiveSupport::TestCase
4 - should 'validate presence of choices, multiple and list' do  
5 - select = CustomFormsPlugin::SelectField.new  
6 - select.valid?  
7 - assert select.errors.invalid?(:choices) 4 + should 'validate type' do
  5 + select = CustomFormsPlugin::SelectField.new(:name => 'select_field001' )
8 6
9 - select.choices = {'label' => 'value'}  
10 - select.valid?  
11 - assert !select.errors.invalid?(:choices) 7 + select.update_attribute(:select_field_type, 'random')
  8 + assert select.invalid?
  9 +
  10 + select.update_attribute(:select_field_type, 'radio')
  11 + assert select.valid?
  12 + select.update_attribute(:select_field_type, 'check_box')
  13 + assert select.valid?
  14 + select.update_attribute(:select_field_type, 'select')
  15 + assert select.valid?
  16 + select.update_attribute(:select_field_type, 'multiple_select')
  17 + assert select.valid?
12 end 18 end
13 end 19 end
plugins/custom_forms/views/custom_forms_plugin_myprofile/_edit_select.html.erb
1 -<% elem_id = "edit-select-#{counter}" %>  
2 -<div id=<%= elem_id %> class='edit-information'> 1 +<div class='edit-information edit-select'>
3 <h2><%= _('Options') %></h2> 2 <h2><%= _('Options') %></h2>
4 <table class='action-table' style='width: 420px'> 3 <table class='action-table' style='width: 420px'>
5 <tr> 4 <tr>
6 <th style='width: 40%'><%= _('Name') %></th> 5 <th style='width: 40%'><%= _('Name') %></th>
7 <th style='width: 40%'><%= _('Value') %></th> 6 <th style='width: 40%'><%= _('Value') %></th>
8 - <th style='width: 20%'><%= _('Actions') %></th> 7 + <th style='width: 20%'><%= _('Delete') %></th>
9 </tr> 8 </tr>
10 <% option_counter = 1 %> 9 <% option_counter = 1 %>
11 <% (field.choices || {}).each do |name, value| %> 10 <% (field.choices || {}).each do |name, value| %>
plugins/custom_forms/views/custom_forms_plugin_myprofile/_edit_text.html.erb
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -<% elem_id = "edit-text-#{counter}" %>  
2 -<div id=<%= elem_id %> class='edit-information'>  
3 - <h2><%= _('Default value') %></h2>  
4 - <%= labelled_form_field _('Default value'), text_field("fields[#{counter}]", :default_value, :value => field.default_value) %>  
5 -  
6 - <% button_bar do %>  
7 - <%= button :ok, _('Ok'), '#', :class => 'colorbox-ok-button', :div_id => elem_id %>  
8 - <% end %>  
9 -</div>  
10 -  
plugins/custom_forms/views/custom_forms_plugin_myprofile/_field.html.erb
1 -<tr id=<%= "field-#{counter}" %>>  
2 - <td style="text-align: left"><%= text_field "fields[#{counter}]", :name, :value => field.name, :size => 25 %></td>  
3 - <td><%= type_to_label(field.type) %></td>  
4 - <%= hidden_field "fields[#{counter}]", :type, :value => type_for_options(field.class) %>  
5 - <td><%= check_box "fields[#{counter}]", :mandatory, :checked => field.mandatory %></td>  
6 - <%= hidden_field "fields[#{counter}]", :real_id, :value => field.id %>  
7 - <%= hidden_field "fields[#{counter}]", :form_id, :value => @form.id %>  
8 - <td class='actions'>  
9 - <%= button_without_text :edit, _('Edit'), '#', :field_id => counter %>  
10 - <%= button_without_text :remove, _('Remove'), '#', :class => 'remove-field', :field_id => counter, :confirm => _('Are you sure you want to remove this field?') %>  
11 - </td>  
12 -</tr> 1 +<fieldset class="field-box" <%='style="display:none"' if f.object._destroy %> >
  2 + <legend><%= type_to_label(f.object.type) %></legend>
  3 + <div>
  4 + <%= f.label :name, _('Name:') %>
  5 + <%= f.text_field :name, :size => 25 %>
  6 +
  7 + <%= f.hidden_field :type %>
  8 +
  9 + <%= f.check_box :mandatory %>
  10 + <%= f.label :mandatory, _('Mandatory') %>
  11 +
  12 + <%= f.hidden_field :_destroy, :class => 'destroy-field' %>
  13 + <%= button_to_function :delete, _('Remove field'), "customFormsPlugin.removeFieldBox(this, #{_('Are you sure you want to remove this field?').to_json})" %>
  14 + <%= yield %>
  15 +</div>
  16 +</fieldset>
plugins/custom_forms/views/custom_forms_plugin_myprofile/_form.html.erb
1 <% self.extend(CustomFormsPlugin::Helper) %> 1 <% self.extend(CustomFormsPlugin::Helper) %>
2 2
3 -<%= error_messages_for :form %>  
4 -  
5 -<% form_for :form, @form do |f| %>  
6 - <%= required labelled_form_field _('Name'), f.text_field(:name) %>  
7 - <%= labelled_form_field(_('Period'), (  
8 - date_range_field('form[begining]', 'form[ending]', @form.begining, @form.ending,  
9 - '%Y-%m-%d %H:%M',  
10 - { :time => true, :change_month => true, :change_year => true,  
11 - :date_format => 'yy-mm-dd', :time_format => 'hh:mm' }, 3 +<%= f.error_messages %>
  4 +<%= required labelled_form_field _('Name'), f.text_field(:name) %>
  5 +<%= labelled_form_field(_('Period'), (
  6 + date_range_field('form[begining]', 'form[ending]', @form.begining, @form.ending,
  7 + '%Y-%m-%d %H:%M',
  8 + { :time => true, :change_month => true, :change_year => true,
  9 + :date_format => 'yy-mm-dd', :time_format => 'hh:mm' },
12 { :size => 14 }) 10 { :size => 14 })
13 - )) %>  
14 - <%= labelled_form_field _('Access'), f.select(:access, access_options(profile))%>  
15 - <% if profile.organization? %>  
16 - <%= labelled_form_field _('Triggered on membership'), f.check_box(:on_membership) %>  
17 - <% end %>  
18 - <%= labelled_form_field _('Description'), f.text_area(:description, :style => 'width: 100%') %> 11 +)) %>
  12 +<%= labelled_form_field _('Access'), f.select(:access, access_options(profile))%>
  13 +<% if profile.organization? %>
  14 + <%= labelled_form_field _('Triggered on membership'), f.check_box(:on_membership) %>
  15 +<% end %>
  16 +<%= labelled_form_field _('Description'), f.text_area(:description, :style => 'width: 100%') %>
19 17
20 - <h2><%= _('Fields') %></h2>  
21 - <table class="action-table" id='fields-table'>  
22 - <tr>  
23 - <th style='width: 40%'><%= _('Name') %></th>  
24 - <th style='width: 30%'><%= _('Type') %></th>  
25 - <th style='width: 10%'><%= _('Mandatory') %></th>  
26 - <th style='width: 20%'><%= _('Actions') %></th>  
27 - </tr>  
28 - <% counter = 1 %>  
29 - <% @fields.each do |field| %>  
30 - <%= render :partial => 'field', :locals => {:field => field, :counter => counter} %>  
31 - <% counter += 1 %>  
32 - <% end %>  
33 - <%= render :partial => 'empty_field', :locals => {:field => @empty_field, :counter => counter} %>  
34 - <tr class='new-item'>  
35 - <td colspan='5'>  
36 - <%= button(:add, _('Add a new field'), '#', :id => 'new-field')%>  
37 - </td>  
38 - </tr>  
39 - </table> 18 +<h2><%= _('Fields') %></h2>
40 19
41 - <% counter = 1 %>  
42 - <% @fields.each do |field| %>  
43 - <%= render :partial => 'edit_text', :locals => {:field => field, :counter => counter} %>  
44 - <%= render :partial => 'edit_select', :locals => {:field => field, :counter => counter} %>  
45 - <% counter += 1 %>  
46 - <% end %> 20 +<% f.fields_for :fields do |builder| %>
  21 + <%= render partial_for_class(builder.object.class), :f => builder %>
  22 +<% end %>
47 23
48 - <%= render :partial => 'edit_text', :locals => {:field => @empty_field, :counter => counter} %>  
49 - <%= render :partial => 'edit_select', :locals => {:field => @empty_field, :counter => counter} %> 24 +<div class="addition-buttons">
  25 + <%= button(:add, _('Add a new text field'), '#', :onclick => "customFormsPlugin.addFields(this, 'fields', #{html_for_field(f, :fields, CustomFormsPlugin::TextField).to_json}); return false")%>
  26 + <%= button(:add, _('Add a new select field'), '#', :onclick => "customFormsPlugin.addFields(this, 'fields', #{html_for_field(f, :fields, CustomFormsPlugin::SelectField).to_json}); return false")%>
  27 +</div>
50 28
51 - <% button_bar do %>  
52 - <%= submit_button :save, _('Save'), :cancel => {:action => 'index'}%>  
53 - <% end %> 29 +<% button_bar do %>
  30 + <%= submit_button :save, _('Save'), :cancel => {:action => 'index'}%>
54 <% end %> 31 <% end %>
55 32
56 <%= javascript_include_tag '../plugins/custom_forms/field' %> 33 <%= javascript_include_tag '../plugins/custom_forms/field' %>
plugins/custom_forms/views/custom_forms_plugin_myprofile/_option.html.erb
@@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
1 -<tr id=<%= "field-#{counter}-option-#{option_counter}" %> style="display: auto;">  
2 - <td><%= text_field_tag("fields[#{counter}][choices][#{option_counter}][name]", name) %></td>  
3 - <td><%= text_field_tag("fields[#{counter}][choices][#{option_counter}][value]", value) %></td>  
4 - <td class='actions'>  
5 - <%= button_without_text :remove, _('Remove'), '#', :class => 'remove-option', :field_id => counter, :option_id => option_counter, :confirm => _('Are you sure you want to remove this option?') %>  
6 - </td>  
7 -</tr>  
plugins/custom_forms/views/custom_forms_plugin_myprofile/create.html.erb
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -<h1><%= _('New form') %></h1>  
2 -<%= render :partial => 'form' %>  
plugins/custom_forms/views/custom_forms_plugin_myprofile/custom_forms_plugin/_alternative.html.erb 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +<tr class="alternative">
  2 + <td> <%= f.text_field(:label) %> </td>
  3 +
  4 + <td> <%= f.check_box(:selected_by_default) %> </td>
  5 +
  6 + <td>
  7 + <%= f.hidden_field :_destroy, :class => 'destroy-field' %>
  8 + <%= button_to_function_without_text :remove, _('Remove alternative'), "customFormsPlugin.removeAlternative(this, #{_('Are you sure you want to remove this alternative?').to_json})", :class => 'remove-field', :title => _('Remove alternative') %>
  9 + </td>
  10 +</div>
plugins/custom_forms/views/custom_forms_plugin_myprofile/custom_forms_plugin/_field.html.erb 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +<%-# Small hack necessary for fields_for when validation fails on #new %>
  2 +<% case f.object.type
  3 + when 'CustomFormsPlugin::SelectField' %>
  4 + <%= render partial_for_class(CustomFormsPlugin::SelectField), :f => f %>
  5 +<% when 'CustomFormsPlugin::TextField' %>
  6 + <%= render partial_for_class(CustomFormsPlugin::TextField), :f => f %>
  7 +<% else %>
  8 + <% raise 'This field has no valid type' %>
  9 +<% end %>
plugins/custom_forms/views/custom_forms_plugin_myprofile/custom_forms_plugin/_select_field.html.erb 0 → 100644
@@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
  1 +<% render :layout => 'field', :locals => { :f => f } do %>
  2 + <div class="field-select-type">
  3 + <%= _('Type:') %>
  4 + <%= f.radio_button(:select_field_type, 'radio') %>
  5 + <%= f.label(:select_field_type, _('Radio'), :value => 'radio') %>
  6 + <%= f.radio_button(:select_field_type, 'check_box') %>
  7 + <%= f.label(:select_field_type, _('Checkbox'), :value => 'check_box') %>
  8 + <%= f.radio_button(:select_field_type, 'select') %>
  9 + <%= f.label(:select_field_type, _('Drop down'), :value => 'select') %>
  10 + <%= f.radio_button(:select_field_type, 'multiple_select') %>
  11 + <%= f.label(:select_field_type, _('Multiple Select'), :value => 'multiple_select') %>
  12 + </div>
  13 +
  14 + <table>
  15 + <tr <%='style="display:none"' if f.object.alternatives.empty? %>>
  16 + <th><%= _('Alternative') %></th>
  17 + <th><%= _('Preselected') %></th>
  18 + <th><%= _('Remove') %></th>
  19 + </tr>
  20 + <% f.fields_for :alternatives do |builder| %>
  21 + <%= render partial_for_class(builder.object.class), :f => builder %>
  22 + <% end %>
  23 + <tr class="addition-buttons">
  24 + <td colspan="3">
  25 + <%= button(:add, _('Add a new alternative'), '#', :onclick => "customFormsPlugin.addFields(this, 'alternatives', #{html_for_field(f, :alternatives, CustomFormsPlugin::Alternative).to_json}); return false") %>
  26 + </td>
  27 + </tr>
  28 + </table>
  29 +
  30 +
  31 +<% end %>
plugins/custom_forms/views/custom_forms_plugin_myprofile/custom_forms_plugin/_text_field.html.erb 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +<% render :layout => 'field', :locals => { :f => f } do %>
  2 + <div class="field-text-default">
  3 + <%= f.label(:default_value, _('Default value:')) %>
  4 + <%= f.text_field(:default_value) %>
  5 + </div>
  6 +<% end %>
plugins/custom_forms/views/custom_forms_plugin_myprofile/edit.html.erb
1 <h1><%= _('Edit form') %></h1> 1 <h1><%= _('Edit form') %></h1>
2 -<%= render :partial => 'form' %> 2 +
  3 +<% form_for :form, @form, :url => { :action => 'update', :id => params[:id] } do |f| %>
  4 + <%= render :partial => 'form', :locals => {:f => f} %>
  5 +<% end %>
plugins/custom_forms/views/custom_forms_plugin_myprofile/index.html.erb
@@ -22,7 +22,7 @@ @@ -22,7 +22,7 @@
22 <% end %> 22 <% end %>
23 <tr id="new-item"> 23 <tr id="new-item">
24 <td colspan='5'> 24 <td colspan='5'>
25 - <%= button(:add, _('Add a new form'), :action => 'create')%> 25 + <%= button(:add, _('Add a new form'), :action => 'new')%>
26 </td> 26 </td>
27 </tr> 27 </tr>
28 </table> 28 </table>
plugins/custom_forms/views/custom_forms_plugin_myprofile/new.html.erb 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +<h1><%= _('New form') %></h1>
  2 +
  3 +<% form_for :form, @form, :url => { :action => 'create', :id => params[:id] } do |f| %>
  4 + <%= render :partial => 'form', :locals => {:f => f} %>
  5 +<% end %>
public/stylesheets/application.css
@@ -2471,11 +2471,11 @@ div#activation_enterprise label, div#activation_enterprise input, div#activation @@ -2471,11 +2471,11 @@ div#activation_enterprise label, div#activation_enterprise input, div#activation
2471 } 2471 }
2472 /*** REQUIRED FIELDS ***/ 2472 /*** REQUIRED FIELDS ***/
2473 2473
2474 -.required-field label { 2474 +.required-field label.formlabel {
2475 font-weight: bold; 2475 font-weight: bold;
2476 color: #c00; 2476 color: #c00;
2477 } 2477 }
2478 -.required-field label:after { 2478 +.required-field label.formlabel:after {
2479 content: ' (*)'; 2479 content: ' (*)';
2480 } 2480 }
2481 .login-box { 2481 .login-box {