diff --git a/README.rdoc b/README.rdoc index 49cd54b..da23b96 100644 --- a/README.rdoc +++ b/README.rdoc @@ -34,7 +34,7 @@ Features include: Put the following in your application's config block in config/environment.rb - config.gem 'jeffp-wizardly', :lib=>'wizardly' + config.gem 'jeffp-wizardly', :lib=>'wizardly' and run the install gems rake task on your application @@ -44,6 +44,20 @@ For any rails app, run the following to install wizardly rake tasks (optional) ./script/generate wizardly_app +== Recommendations + +Wizardly uses sessions. It is recommended you use a session store other than the +default cookies store to eliminate the 4KB size restriction. To use the active +record store, add this line to your environment.rb + + config.action_controller.session_store = :active_record_store + +And set up the sessions table in the database + + rake db:sessions:create + rake db:migrate + +Use the MemCached session store for higher performance requirements. == Example @@ -69,7 +83,9 @@ Step 3: Generate a 'wizardly' scaffold for your controller. You are ready to go. -General usage and configuration of wizardly follows. +General usage and configuration of wizardly follows. See the examples at + + http://github.com/jeffp/wizardly-examples == Usage @@ -312,6 +328,23 @@ call back for this. end end +=== Completing the Wizard Programmatically + +Perhaps you want to complete a wizard based off of a test instead of a button +click. You can do this in your callbacks by calling the +complete_wizard+ method. + + on_next(:step4) do + if (test_radio_button) + complete_wizard + end + end + +Complete wizard will save the model and redirect to the :completed redirect setting. +You can change the redirect dynamically by passing it to the method. + + complete_wizard(some_model_path) + + === Creating Scaffolds Wizard scaffolds can be created for any wizardly controller (one using the acts_wizardly_for @@ -329,6 +362,11 @@ each page. ./script/generate wizardly_scaffold controller_name --underscore +You can create a scaffold using image_submit_tag by doing the following: + + ./script/generate wizardly_scaffold controller_name --image_submit + +Default button images are provided under the public/images/wizardly/ directory. == Advanced Configuration @@ -336,7 +374,7 @@ To be provided == Testing -Testing uses RSpec and Webrat. Make sure you have those gems installed. Then +Testing uses RSpec and Webrat. Make sure you have the gems installed. Then to test the development code run the following: rake spec:all diff --git a/Rakefile b/Rakefile index 67b82f9..4d1f031 100644 --- a/Rakefile +++ b/Rakefile @@ -39,7 +39,7 @@ require 'spec/rake/spectask' namespace :spec do desc "Run all specs" - task :all=>[:macro, :gen, :scaffold, :callback, :callback2, :callback3, :datamodes, :sandbox, :session] + task :all=>[:macro, :gen, :scaffold, :callback, :callback2, :callback3, :persist, :sandbox, :session] desc "Test the MacroController" Spec::Rake::SpecTask.new(:macro) do |t| t.spec_files = FileList['spec/integrations/macro_spec.rb'] @@ -47,8 +47,15 @@ namespace :spec do t.spec_opts = ['--options', 'spec/spec.opts'] t.rcov = false end + desc "Test the DataModes2Controller" + Spec::Rake::SpecTask.new(:persist2) do |t| + t.spec_files = FileList['spec/integrations/data_modes2_spec.rb'] + t.libs << 'lib' << 'spec' << 'spec/integrations' + t.spec_opts = ['--options', 'spec/spec.opts'] + t.rcov = false + end desc "Test the DataModesController" - Spec::Rake::SpecTask.new(:datamodes) do |t| + Spec::Rake::SpecTask.new(:persist) do |t| t.spec_files = FileList['spec/integrations/data_modes_spec.rb'] t.libs << 'lib' << 'spec' << 'spec/integrations' t.spec_opts = ['--options', 'spec/spec.opts'] diff --git a/app/controllers/data_modes2_controller.rb b/app/controllers/data_modes2_controller.rb new file mode 100644 index 0000000..9e8c821 --- /dev/null +++ b/app/controllers/data_modes2_controller.rb @@ -0,0 +1,7 @@ +class DataModes2Controller < ApplicationController + + act_wizardly_for :user, :persist_model=>:per_page, :form_data=>:sandbox, + :completed=>{:controller=>:main, :action=>:finished}, + :canceled=>{:controller=>:main, :action=>:canceled} + +end diff --git a/app/controllers/generated_controller.rb b/app/controllers/generated_controller.rb index a400461..7f286c8 100644 --- a/app/controllers/generated_controller.rb +++ b/app/controllers/generated_controller.rb @@ -6,6 +6,41 @@ class GeneratedController < ApplicationController before_filter :guard_entry + # finish action method + def finish + begin + @step = :finish + @wizard = wizard_config + @title = 'Finish' + @description = '' + h = (self.wizard_form_data||{}).merge(params[:user] || {}) + @user = build_wizard_model(h) + if request.post? && callback_performs_action?(:on_post_finish_form) + raise CallbackError, "render or redirect not allowed in :on_post_finish_form callback", caller + end + button_id = check_action_for_button + return if performed? + if request.get? + return if callback_performs_action?(:on_get_finish_form) + render_wizard_form + return + end + + # @user.enable_validation_group :finish + unless @user.valid?(:finish) + return if callback_performs_action?(:on_invalid_finish_form) + render_wizard_form + return + end + + callback_performs_action?(:on_finish_form_finish) + complete_wizard + ensure + self.wizard_form_data = h.merge(@user.attributes) if (@user && !@wizard_completed_flag) + end + end + + # second action method def second begin @@ -35,8 +70,7 @@ def second if button_id == :finish callback_performs_action?(:on_second_form_finish) - _on_wizard_finish if button_id == :finish - redirect_to '/main/finished' unless self.performed? + complete_wizard return end @@ -77,8 +111,7 @@ def init if button_id == :finish callback_performs_action?(:on_init_form_finish) - _on_wizard_finish if button_id == :finish - redirect_to '/main/finished' unless self.performed? + complete_wizard return end @@ -89,42 +122,6 @@ def init end end - - # finish action method - def finish - begin - @step = :finish - @wizard = wizard_config - @title = 'Finish' - @description = '' - h = (self.wizard_form_data||{}).merge(params[:user] || {}) - @user = build_wizard_model(h) - if request.post? && callback_performs_action?(:on_post_finish_form) - raise CallbackError, "render or redirect not allowed in :on_post_finish_form callback", caller - end - button_id = check_action_for_button - return if performed? - if request.get? - return if callback_performs_action?(:on_get_finish_form) - render_wizard_form - return - end - - # @user.enable_validation_group :finish - unless @user.valid?(:finish) - return if callback_performs_action?(:on_invalid_finish_form) - render_wizard_form - return - end - - callback_performs_action?(:on_finish_form_finish) - _on_wizard_finish - redirect_to '/main/finished' unless self.performed? - ensure - self.wizard_form_data = h.merge(@user.attributes) if (@user && !@wizard_completed_flag) - end - end - def index redirect_to :action=>:init end @@ -139,7 +136,7 @@ def _on_wizard_finish _wizard_final_redirect_to(:completed) end def _on_wizard_skip - session[:progression] = (session[:progression]||[]) - [@step] + self.progression = self.progression - [@step] redirect_to(:action=>wizard_config.next_page(@step)) unless self.performed? end def _on_wizard_back @@ -148,12 +145,12 @@ def _on_wizard_back def _on_wizard_cancel _wizard_final_redirect_to(:canceled) end - def _wizard_final_redirect_to(type) - initial_referer = (type == :canceled && wizard_config.form_data_keep_in_session?) ? - session[:initial_referer] : + def _wizard_final_redirect_to(type) + init = (type == :canceled && wizard_config.form_data_keep_in_session?) ? + self.initial_referer : reset_wizard_session_vars unless self.performed? - redir = (type == :canceled ? wizard_config.canceled_redirect : wizard_config.completed_redirect) || initial_referer + redir = (type == :canceled ? wizard_config.canceled_redirect : wizard_config.completed_redirect) || init return redirect_to(redir) if redir raise Wizardly::RedirectNotDefinedError, "No redirect was defined for completion or canceling the wizard. Use :completed and :canceled options to define redirects.", caller end @@ -163,35 +160,35 @@ def _wizard_final_redirect_to(type) protected def previous_in_progression_from(step) - po = wizard_config.page_order - p = session[:progression]||[] + po = [:init, :second, :finish] + p = self.progression p -= po[po.index(step)..-1] - session[:progression] = p + self.progression = p p.last end def check_progression - p = session[:progression]||[] + p = self.progression a = params[:action].to_sym return if p.last == a - po = wizard_config.page_order + po = [:init, :second, :finish] return unless (ai = po.index(a)) p -= po[ai..-1] p << a - session[:progression] = p + self.progression = p end # for :form_data=>:session def guard_entry if (r = request.env['HTTP_REFERER']) h = ::ActionController::Routing::Routes.recognize_path(URI.parse(r).path) return check_progression if (h[:controller]||'') == 'generated' - session[:initial_referer] ||= h + self.initial_referer = h unless self.initial_referer end # coming from outside the controller if (params[:action] == 'init' || params[:action] == 'index') return check_progression elsif self.wizard_form_data - p = session[:progression]||[] + p = self.progression return check_progression if p.include?(params[:action].to_sym) return redirect_to(:action=>(p.last||:init)) end @@ -199,40 +196,53 @@ def guard_entry end hide_action :guard_entry - def save_wizard_model! - @user.save_without_validation! - if wizard_config.form_data_keep_in_session? - h = self.wizard_form_data - h['id'] = @user.id - self.wizard_form_data= h - end + def complete_wizard(redirect = nil) + redirect_to redirect if redirect + _on_wizard_finish + redirect_to '/main/finished' unless self.performed? end def build_wizard_model(params) if (wizard_config.persist_model_per_page? && (model_id = params['id'])) - _model = User.find(model_id) - _model.attributes = params - _model - else - User.new(params) + begin + _model = User.find(model_id) + _model.attributes = params + return _model + rescue + end end + User.new(params) end hide_action :build_wizard_model, :save_wizard_model! + def initial_referer + session[:generated_irk] + end + def initial_referer=(val) + session[:generated_irk] = val + end + def progression=(array) + session[:generated_prg] = array + end + def progression + session[:generated_prg]||[] + end + hide_action :progression, :progression= + def wizard_form_data=(hash) if wizard_config.form_data_keep_in_session? - session[:wizardly_generated_user] = hash + session[:generated_dat] = hash else if hash - flash[:wizardly_generated_user] = hash + flash[:generated_dat] = hash else - flash.discard(:wizardly_generated_user) + flash.discard(:generated_dat) end end end def reset_wizard_form_data; self.wizard_form_data = nil; end def wizard_form_data - wizard_config.form_data_keep_in_session? ? session[:wizardly_generated_user] : flash[:wizardly_generated_user] + wizard_config.form_data_keep_in_session? ? session[:generated_dat] : flash[:generated_dat] end hide_action :wizard_form_data, :wizard_form_data=, :reset_wizard_form_data @@ -249,9 +259,9 @@ def underscore_button_name(value) hide_action :underscore_button_name def reset_wizard_session_vars - session[:progression] = nil - init = session[:initial_referer] - session[:initial_referer] = nil + self.progression = nil + init = self.initial_referer + self.initial_referer = nil init end hide_action :reset_wizard_session_vars @@ -277,9 +287,19 @@ def check_action_for_button end hide_action :check_action_for_button - def callback_performs_action?(methId, arg=nil) - return false unless self.methods.include?(methId.to_s) - #self.__send__(methId) + @wizard_callbacks ||= {} + def self.wizard_callbacks; @wizard_callbacks; end + + def callback_performs_action?(methId) + cache = self.class.wizard_callbacks + return false if ((m = cache[methId]) == :none) + unless m == :found + unless self.methods.include?(methId.to_s) + cache[methId] = :none + return false + end + cache[methId] = :found + end self.method(methId).call self.performed? end @@ -338,7 +358,7 @@ def self.on_errors(*args, &block) self.send(:define_method, sprintf("on_invalid_%s_form", form.to_s), &block ) end end - def self.on_back(*args, &block) + def self.on_finish(*args, &block) return if args.empty? all_forms = [:init, :second, :finish] if args.include?(:all) @@ -346,16 +366,16 @@ def self.on_back(*args, &block) else forms = args.map do |fa| unless all_forms.include?(fa) - raise(ArgumentError, ":"+fa.to_s+" in callback on_back is not a form defined for the wizard", caller) + raise(ArgumentError, ":"+fa.to_s+" in callback on_finish is not a form defined for the wizard", caller) end fa end end forms.each do |form| - self.send(:define_method, sprintf("on_%s_form_back", form.to_s), &block ) + self.send(:define_method, sprintf("on_%s_form_finish", form.to_s), &block ) end end - def self.on_skip(*args, &block) + def self.on_cancel(*args, &block) return if args.empty? all_forms = [:init, :second, :finish] if args.include?(:all) @@ -363,16 +383,16 @@ def self.on_skip(*args, &block) else forms = args.map do |fa| unless all_forms.include?(fa) - raise(ArgumentError, ":"+fa.to_s+" in callback on_skip is not a form defined for the wizard", caller) + raise(ArgumentError, ":"+fa.to_s+" in callback on_cancel is not a form defined for the wizard", caller) end fa end end forms.each do |form| - self.send(:define_method, sprintf("on_%s_form_skip", form.to_s), &block ) + self.send(:define_method, sprintf("on_%s_form_cancel", form.to_s), &block ) end end - def self.on_next(*args, &block) + def self.on_skip(*args, &block) return if args.empty? all_forms = [:init, :second, :finish] if args.include?(:all) @@ -380,16 +400,16 @@ def self.on_next(*args, &block) else forms = args.map do |fa| unless all_forms.include?(fa) - raise(ArgumentError, ":"+fa.to_s+" in callback on_next is not a form defined for the wizard", caller) + raise(ArgumentError, ":"+fa.to_s+" in callback on_skip is not a form defined for the wizard", caller) end fa end end forms.each do |form| - self.send(:define_method, sprintf("on_%s_form_next", form.to_s), &block ) + self.send(:define_method, sprintf("on_%s_form_skip", form.to_s), &block ) end end - def self.on_cancel(*args, &block) + def self.on_back(*args, &block) return if args.empty? all_forms = [:init, :second, :finish] if args.include?(:all) @@ -397,16 +417,16 @@ def self.on_cancel(*args, &block) else forms = args.map do |fa| unless all_forms.include?(fa) - raise(ArgumentError, ":"+fa.to_s+" in callback on_cancel is not a form defined for the wizard", caller) + raise(ArgumentError, ":"+fa.to_s+" in callback on_back is not a form defined for the wizard", caller) end fa end end forms.each do |form| - self.send(:define_method, sprintf("on_%s_form_cancel", form.to_s), &block ) + self.send(:define_method, sprintf("on_%s_form_back", form.to_s), &block ) end end - def self.on_finish(*args, &block) + def self.on_next(*args, &block) return if args.empty? all_forms = [:init, :second, :finish] if args.include?(:all) @@ -414,13 +434,13 @@ def self.on_finish(*args, &block) else forms = args.map do |fa| unless all_forms.include?(fa) - raise(ArgumentError, ":"+fa.to_s+" in callback on_finish is not a form defined for the wizard", caller) + raise(ArgumentError, ":"+fa.to_s+" in callback on_next is not a form defined for the wizard", caller) end fa end end forms.each do |form| - self.send(:define_method, sprintf("on_%s_form_finish", form.to_s), &block ) + self.send(:define_method, sprintf("on_%s_form_next", form.to_s), &block ) end end diff --git a/app/controllers/image_submit_controller.rb b/app/controllers/image_submit_controller.rb new file mode 100644 index 0000000..a85386a --- /dev/null +++ b/app/controllers/image_submit_controller.rb @@ -0,0 +1,3 @@ +class ImageSubmitController < ApplicationController + wizard_for_model :user, :redirect=>'/main/index', :skip=>true +end diff --git a/app/controllers/main_controller.rb b/app/controllers/main_controller.rb index 840b98f..8ba291a 100644 --- a/app/controllers/main_controller.rb +++ b/app/controllers/main_controller.rb @@ -14,7 +14,8 @@ def index :sandbox_init=>'/sandbox/init', :sandbox_second=>'/sandbox/second', :sandbox_third=>'/sandbox/third', - :sandbox_finish=>'/sandbox/finish' + :sandbox_finish=>'/sandbox/finish', + :image_submit=>'/image_submit' } end diff --git a/app/helpers/image_submit_helper.rb b/app/helpers/image_submit_helper.rb new file mode 100644 index 0000000..e75aff1 --- /dev/null +++ b/app/helpers/image_submit_helper.rb @@ -0,0 +1,30 @@ +module ImageSubmitHelper + + def wizardly_submit + @@wizardly_submit ||= {} + step_id = "#{controller_name}_#{@step}".to_sym + unless @@wizardly_submit[step_id] + buttons = @wizard.pages[@step].buttons + @@wizardly_submit[step_id] = buttons.inject(StringIO.new) do |io, button| + io << submit_tag(button.name) + end.string + end + @@wizardly_submit[step_id] + end + + def wizardly_image_submit(asset_dir = nil, opts = {}) + @@wizardly_image_submit ||={} + step_id = "#{controller_name}_#{@step}".to_sym + unless @@wizardly_image_submit[step_id] + asset_dir = asset_dir ? "#{asset_dir}/".squeeze("/").sub(/^\//,'') : "wizardly/" + buttons = @wizard.pages[@step].buttons + opts[:name] = 'commit' + @@wizardly_image_submit[step_id] = buttons.inject(StringIO.new) do |io, button| + opts[:value] = button.name + io << image_submit_tag("#{asset_dir}#{button.id}.png", opts) + end.string + end + @@wizardly_image_submit[step_id] + end + +end diff --git a/app/helpers/scaffold_test_helper.rb b/app/helpers/scaffold_test_helper.rb index 74065ba..c66b667 100644 --- a/app/helpers/scaffold_test_helper.rb +++ b/app/helpers/scaffold_test_helper.rb @@ -2,13 +2,29 @@ module ScaffoldTestHelper def wizardly_submit @@wizardly_submit ||= {} - unless @@wizardly_submit[@step] + step_id = "#{controller_name}_#{@step}".to_sym + unless @@wizardly_submit[step_id] buttons = @wizard.pages[@step].buttons - @@wizardly_submit[@step] = buttons.inject(StringIO.new) do |io, button| + @@wizardly_submit[step_id] = buttons.inject(StringIO.new) do |io, button| io << submit_tag(button.name) end.string end - @@wizardly_submit[@step] + @@wizardly_submit[step_id] + end + + def wizardly_image_submit(asset_dir = nil, opts = {}) + @@wizardly_image_submit ||={} + step_id = "#{controller_name}_#{@step}".to_sym + unless @@wizardly_image_submit[step_id] + asset_dir = asset_dir ? "#{asset_dir}/".squeeze("/").sub(/^\//,'') : "wizardly/" + buttons = @wizard.pages[@step].buttons + opts[:name] = 'commit' + @@wizardly_image_submit[step_id] = buttons.inject(StringIO.new) do |io, button| + opts[:value] = button.name + io << image_submit_tag("#{asset_dir}#{button.id}.png", opts) + end.string + end + @@wizardly_image_submit[step_id] end end diff --git a/app/views/data_modes2/_finish.html.erb b/app/views/data_modes2/_finish.html.erb new file mode 100644 index 0000000..eb6a264 --- /dev/null +++ b/app/views/data_modes2/_finish.html.erb @@ -0,0 +1,31 @@ +

Finish

+ + +<%= "

#{flash[:notice]}

" if flash[:notice] %> + +<% form_for :user, :url=>{:action=>:finish} do |f| %> + <%= f.error_messages %> + + +

+ <%= f.label :username %>
+ <%= f.text_field :username %> +

+ +

+ <%= f.label :password %>
+ <%= f.password_field :password %> +

+ +

+ <%= f.label :password_confirmation %>
+ <%= f.password_field :password_confirmation %> +

+

+ <%= wizardly_submit %> +

+<% end %> + + diff --git a/app/views/data_modes2/_init.html.erb b/app/views/data_modes2/_init.html.erb new file mode 100644 index 0000000..6f7d58d --- /dev/null +++ b/app/views/data_modes2/_init.html.erb @@ -0,0 +1,26 @@ +

Init

+ + +<%= "

#{flash[:notice]}

" if flash[:notice] %> + +<% form_for :user, :url=>{:action=>:init} do |f| %> + <%= f.error_messages %> + + +

+ <%= f.label :first_name %>
+ <%= f.text_field :first_name %> +

+ +

+ <%= f.label :last_name %>
+ <%= f.text_field :last_name %> +

+

+ <%= wizardly_submit %> +

+<% end %> + + diff --git a/app/views/data_modes2/_second.html.erb b/app/views/data_modes2/_second.html.erb new file mode 100644 index 0000000..72523a3 --- /dev/null +++ b/app/views/data_modes2/_second.html.erb @@ -0,0 +1,36 @@ +

Second

+ + +<%= "

#{flash[:notice]}

" if flash[:notice] %> + +<% form_for :user, :url=>{:action=>:second} do |f| %> + <%= f.error_messages %> + + +

+ <%= f.label :age %>
+ <%= f.text_field :age %> +

+ +

+ <%= f.label :gender %>
+ <%= f.text_field :gender %> +

+ +

+ <%= f.label :programmer %>
+ <%= f.check_box :programmer %> +

+ +

+ <%= f.label :status %>
+ <%= f.text_field :status %> +

+

+ <%= wizardly_submit %> +

+<% end %> + + diff --git a/app/views/data_modes2/finish.html.erb b/app/views/data_modes2/finish.html.erb new file mode 100644 index 0000000..eb6a264 --- /dev/null +++ b/app/views/data_modes2/finish.html.erb @@ -0,0 +1,31 @@ +

Finish

+ + +<%= "

#{flash[:notice]}

" if flash[:notice] %> + +<% form_for :user, :url=>{:action=>:finish} do |f| %> + <%= f.error_messages %> + + +

+ <%= f.label :username %>
+ <%= f.text_field :username %> +

+ +

+ <%= f.label :password %>
+ <%= f.password_field :password %> +

+ +

+ <%= f.label :password_confirmation %>
+ <%= f.password_field :password_confirmation %> +

+

+ <%= wizardly_submit %> +

+<% end %> + + diff --git a/app/views/data_modes2/init.html.erb b/app/views/data_modes2/init.html.erb new file mode 100644 index 0000000..6f7d58d --- /dev/null +++ b/app/views/data_modes2/init.html.erb @@ -0,0 +1,26 @@ +

Init

+ + +<%= "

#{flash[:notice]}

" if flash[:notice] %> + +<% form_for :user, :url=>{:action=>:init} do |f| %> + <%= f.error_messages %> + + +

+ <%= f.label :first_name %>
+ <%= f.text_field :first_name %> +

+ +

+ <%= f.label :last_name %>
+ <%= f.text_field :last_name %> +

+

+ <%= wizardly_submit %> +

+<% end %> + + diff --git a/app/views/data_modes2/second.html.erb b/app/views/data_modes2/second.html.erb new file mode 100644 index 0000000..72523a3 --- /dev/null +++ b/app/views/data_modes2/second.html.erb @@ -0,0 +1,36 @@ +

Second

+ + +<%= "

#{flash[:notice]}

" if flash[:notice] %> + +<% form_for :user, :url=>{:action=>:second} do |f| %> + <%= f.error_messages %> + + +

+ <%= f.label :age %>
+ <%= f.text_field :age %> +

+ +

+ <%= f.label :gender %>
+ <%= f.text_field :gender %> +

+ +

+ <%= f.label :programmer %>
+ <%= f.check_box :programmer %> +

+ +

+ <%= f.label :status %>
+ <%= f.text_field :status %> +

+

+ <%= wizardly_submit %> +

+<% end %> + + diff --git a/app/views/image_submit/finish.html.erb b/app/views/image_submit/finish.html.erb new file mode 100644 index 0000000..eb3c893 --- /dev/null +++ b/app/views/image_submit/finish.html.erb @@ -0,0 +1,31 @@ +

Finish

+ + +<%= "

#{flash[:notice]}

" if flash[:notice] %> + +<% form_for :user, :url=>{:action=>:finish} do |f| %> + <%= f.error_messages %> + + +

+ <%= f.label :username %>
+ <%= f.text_field :username %> +

+ +

+ <%= f.label :password %>
+ <%= f.password_field :password %> +

+ +

+ <%= f.label :password_confirmation %>
+ <%= f.password_field :password_confirmation %> +

+

+ <%= wizardly_image_submit %> +

+<% end %> + + diff --git a/app/views/image_submit/init.html.erb b/app/views/image_submit/init.html.erb new file mode 100644 index 0000000..3b412d6 --- /dev/null +++ b/app/views/image_submit/init.html.erb @@ -0,0 +1,26 @@ +

Init

+ + +<%= "

#{flash[:notice]}

" if flash[:notice] %> + +<% form_for :user, :url=>{:action=>:init} do |f| %> + <%= f.error_messages %> + + +

+ <%= f.label :first_name %>
+ <%= f.text_field :first_name %> +

+ +

+ <%= f.label :last_name %>
+ <%= f.text_field :last_name %> +

+

+ <%= wizardly_image_submit %> +

+<% end %> + + diff --git a/app/views/image_submit/second.html.erb b/app/views/image_submit/second.html.erb new file mode 100644 index 0000000..4570707 --- /dev/null +++ b/app/views/image_submit/second.html.erb @@ -0,0 +1,36 @@ +

Second

+ + +<%= "

#{flash[:notice]}

" if flash[:notice] %> + +<% form_for :user, :url=>{:action=>:second} do |f| %> + <%= f.error_messages %> + + +

+ <%= f.label :age %>
+ <%= f.text_field :age %> +

+ +

+ <%= f.label :gender %>
+ <%= f.text_field :gender %> +

+ +

+ <%= f.label :programmer %>
+ <%= f.check_box :programmer %> +

+ +

+ <%= f.label :status %>
+ <%= f.text_field :status %> +

+

+ <%= wizardly_image_submit %> +

+<% end %> + + diff --git a/app/views/layouts/image_submit.html.erb b/app/views/layouts/image_submit.html.erb new file mode 100644 index 0000000..12a1337 --- /dev/null +++ b/app/views/layouts/image_submit.html.erb @@ -0,0 +1,15 @@ + + + + + + ImageSubmitController: <%= controller.action_name %> + <%= stylesheet_link_tag 'scaffold' %> + + + +<%= yield %> + + + diff --git a/config/environment.rb b/config/environment.rb index 137d095..61ebb8e 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -19,7 +19,7 @@ # config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net" # config.gem "sqlite3-ruby", :lib => "sqlite3" # config.gem "aws-s3", :lib => "aws/s3" - config.gem "enumerated_attribute" + #config.gem "#{Rails::GemDependency.new("enumerated_attribute").installed? ? "" : "jeffp-"}enumerated_attribute" # Only load the plugins named here, in the order given (default is alphabetical). # :all can be used as a placeholder for all plugins not explicitly named @@ -31,7 +31,8 @@ # Activate observers that should always be running # config.active_record.observers = :cacher, :garbage_collector, :forum_observer - + config.action_controller.session_store = :active_record_store + # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. config.time_zone = 'UTC' diff --git a/db/development.sqlite3 b/db/development.sqlite3 index 147bca1..f1b07b5 100644 Binary files a/db/development.sqlite3 and b/db/development.sqlite3 differ diff --git a/lib/generators/wizardly_controller/wizardly_controller_generator.rb b/lib/generators/wizardly_controller/wizardly_controller_generator.rb index 61e2da5..d1386ca 100644 --- a/lib/generators/wizardly_controller/wizardly_controller_generator.rb +++ b/lib/generators/wizardly_controller/wizardly_controller_generator.rb @@ -5,7 +5,7 @@ class WizardlyControllerGenerator < Rails::Generator::Base def initialize(runtime_args, runtime_options = {}) super - @controller_name = @args[0].sub(/^:/, '').underscore + @controller_name = @args[0].sub(/^:/,'') @model_name = @args[1].sub(/^:/, '').underscore @completed_redirect = @args[2] @canceled_redirect = @args[3] @@ -13,7 +13,7 @@ def initialize(runtime_args, runtime_options = {}) opts[:completed] = @completed_redirect if @completed_redirect opts[:canceled] = @canceled_redirect if @canceled_redirect - @wizard_config = Wizardly::Wizard::Configuration.new(@controller_name.to_sym, opts) + @wizard_config = Wizardly::Wizard::Configuration.new(@controller_name, opts) @wizard_config.inspect_model!(@model_name.to_sym) end diff --git a/lib/generators/wizardly_scaffold/templates/form.html.erb b/lib/generators/wizardly_scaffold/templates/form.html.erb index ed3ef86..080e427 100644 --- a/lib/generators/wizardly_scaffold/templates/form.html.erb +++ b/lib/generators/wizardly_scaffold/templates/form.html.erb @@ -14,7 +14,7 @@

<% end -%>

- <%%= wizardly_submit %> + <%%= <%= submit_tag %> %>

<%% end %> diff --git a/lib/generators/wizardly_scaffold/templates/form.html.haml.erb b/lib/generators/wizardly_scaffold/templates/form.html.haml.erb index 5b0b291..0a1f567 100644 --- a/lib/generators/wizardly_scaffold/templates/form.html.haml.erb +++ b/lib/generators/wizardly_scaffold/templates/form.html.haml.erb @@ -16,7 +16,7 @@ %br = f.<%= field.field_type %> :<%= field.name %> <% end %> - %p= wizardly_submit + %p= <%= submit_tag %> %script{:type=>'text/javascript'} document.getElementById('<%=first_field_id %>').focus() diff --git a/lib/generators/wizardly_scaffold/templates/helper.rb.erb b/lib/generators/wizardly_scaffold/templates/helper.rb.erb index fa551a8..c07aeb9 100644 --- a/lib/generators/wizardly_scaffold/templates/helper.rb.erb +++ b/lib/generators/wizardly_scaffold/templates/helper.rb.erb @@ -2,13 +2,29 @@ module <%=controller_name.camelize %>Helper def wizardly_submit @@wizardly_submit ||= {} - unless @@wizardly_submit[@step] + step_id = "#{controller_name}_#{@step}".to_sym + unless @@wizardly_submit[step_id] buttons = @wizard.pages[@step].buttons - @@wizardly_submit[@step] = buttons.inject(StringIO.new) do |io, button| + @@wizardly_submit[step_id] = buttons.inject(StringIO.new) do |io, button| io << submit_tag(button.name) end.string end - @@wizardly_submit[@step] + @@wizardly_submit[step_id] + end + + def wizardly_image_submit(asset_dir = nil, opts = {}) + @@wizardly_image_submit ||={} + step_id = "#{controller_name}_#{@step}".to_sym + unless @@wizardly_image_submit[step_id] + asset_dir = asset_dir ? "#{asset_dir}/".squeeze("/").sub(/^\//,'') : "wizardly/" + buttons = @wizard.pages[@step].buttons + opts[:name] = 'commit' + @@wizardly_image_submit[step_id] = buttons.inject(StringIO.new) do |io, button| + opts[:value] = button.name + io << image_submit_tag("#{asset_dir}#{button.id}.png", opts) + end.string + end + @@wizardly_image_submit[step_id] end end diff --git a/lib/generators/wizardly_scaffold/templates/images/back.png b/lib/generators/wizardly_scaffold/templates/images/back.png new file mode 100644 index 0000000..6a8c2d7 Binary files /dev/null and b/lib/generators/wizardly_scaffold/templates/images/back.png differ diff --git a/lib/generators/wizardly_scaffold/templates/images/cancel.png b/lib/generators/wizardly_scaffold/templates/images/cancel.png new file mode 100644 index 0000000..202a412 Binary files /dev/null and b/lib/generators/wizardly_scaffold/templates/images/cancel.png differ diff --git a/lib/generators/wizardly_scaffold/templates/images/finish.png b/lib/generators/wizardly_scaffold/templates/images/finish.png new file mode 100644 index 0000000..e6226a1 Binary files /dev/null and b/lib/generators/wizardly_scaffold/templates/images/finish.png differ diff --git a/lib/generators/wizardly_scaffold/templates/images/next.png b/lib/generators/wizardly_scaffold/templates/images/next.png new file mode 100644 index 0000000..f6000f0 Binary files /dev/null and b/lib/generators/wizardly_scaffold/templates/images/next.png differ diff --git a/lib/generators/wizardly_scaffold/templates/images/skip.png b/lib/generators/wizardly_scaffold/templates/images/skip.png new file mode 100644 index 0000000..fd319c4 Binary files /dev/null and b/lib/generators/wizardly_scaffold/templates/images/skip.png differ diff --git a/lib/generators/wizardly_scaffold/wizardly_scaffold_generator.rb b/lib/generators/wizardly_scaffold/wizardly_scaffold_generator.rb index c15ba6a..0f8ea6f 100644 --- a/lib/generators/wizardly_scaffold/wizardly_scaffold_generator.rb +++ b/lib/generators/wizardly_scaffold/wizardly_scaffold_generator.rb @@ -1,7 +1,7 @@ require 'wizardly' class WizardlyScaffoldGenerator < Rails::Generator::Base - attr_reader :wizard_config, :pages + attr_reader :wizard_config, :pages, :submit_tag attr_reader :controller_name, :controller_class_path, :controller_file_path, @@ -17,6 +17,7 @@ def add_options!(opt) opt.on('--haml', 'Generate scaffold for haml wizard') { |v| options[:output] = :haml } opt.on('--ajax', 'Generate scaffold for ajax wizard') { |v| options[:output] = :ajax } opt.on('--underscore', 'Append an underscore to front of each file') { |v| options[:underscore] = true } + opt.on('--image_submit', 'Use image submit tags in forms') {|v| options[:image_submit] = true } end @@ -47,6 +48,7 @@ def initialize(runtime_args, runtime_options = {}) @pages = @wizard_config.pages @model_name = @wizard_config.model + @submit_tag = options[:image_submit] ? "wizardly_image_submit" : "wizardly_submit" #based on options, default is --html, others --ajax, --haml @view_file_ext = ["html.erb", "html.erb"] @@ -60,6 +62,7 @@ def manifest m.directory(File.join('app/helpers', controller_class_path)) m.directory(File.join('app/views', controller_class_path, controller_name)) m.directory(File.join('app/views/layouts', controller_class_path)) + m.directory('public/images/wizardly') if options[:image_submit] #m.directory(File.join('test/functional', controller_class_path)) #m.directory(File.join('public/stylesheets', class_path)) @@ -72,6 +75,12 @@ def manifest ) end + if options[:image_submit] + %w(next skip back cancel finish).each do |fn| + m.file("images/#{fn}.png", "public/images/wizardly/#{fn}.png") + end + end + m.template("helper.rb.erb", File.join('app/helpers', controller_class_path, "#{controller_name}_helper.rb")) # Layout and stylesheet. diff --git a/lib/validation_group.rb b/lib/validation_group.rb index 2c67ade..6e85a51 100644 --- a/lib/validation_group.rb +++ b/lib/validation_group.rb @@ -44,7 +44,7 @@ def validation_group(name, options={}) module InstanceMethods # included in every model which calls validation_group #needs testing -# def reset_validation_group(group) +# def reset_fields_for_validation_group(group) # group_classes = self.class.validation_group_classes # found = ValidationGroup::Util.current_and_ancestors(self.class).find do |klass| # group_classes[klass] && group_classes[klass].include?(group) diff --git a/lib/wizardly/wizard/configuration.rb b/lib/wizardly/wizard/configuration.rb index 857810f..b09f194 100644 --- a/lib/wizardly/wizard/configuration.rb +++ b/lib/wizardly/wizard/configuration.rb @@ -7,12 +7,15 @@ module Wizardly module Wizard class Configuration - attr_reader :pages, :completed_redirect, :canceled_redirect, :controller_name, :page_order + attr_reader :pages, :completed_redirect, :canceled_redirect, :controller_path, :controller_class_name, :controller_name, :page_order #enum_attr :persistance, %w(sandbox session database) - def initialize(controller_name, opts) #completed_redirect = nil, canceled_redirect = nil) - @controller_name = controller_name + def initialize(controller, opts) #completed_redirect = nil, canceled_redirect = nil) + @controller_class_name = controller.to_s.camelcase + @controller_class_name += 'Controller' unless @controller_class_name =~ /Controller$/ + @controller_path = @controller_class_name.sub(/Controller$/,'').underscore + @controller_name = @controller_class_name.demodulize.sub(/Controller$/,'').underscore @completed_redirect = opts[:redirect] || opts[:completed] || opts[:when_completed] #format_redirect(completed_redirect) @canceled_redirect = opts[:redirect] || opts[:canceled] || opts[:when_canceled] @allow_skipping = opts[:skip] || opts[:allow_skip] || opts[:allow_skipping] || false @@ -59,7 +62,7 @@ def buttons end def self.create(controller_name, model_name, opts={}, &block) - controller_name = controller_name.to_s.underscore.sub(/_controller$/, '').to_sym + # controller_name = controller_name.to_s.underscore.sub(/_controller$/, '').to_sym model_name = model_name.to_s.underscore.to_sym config = Wizardly::Wizard::Configuration.new(controller_name, opts) config.inspect_model!(model_name) diff --git a/lib/wizardly/wizard/configuration/methods.rb b/lib/wizardly/wizard/configuration/methods.rb index 217d507..be68ff4 100644 --- a/lib/wizardly/wizard/configuration/methods.rb +++ b/lib/wizardly/wizard/configuration/methods.rb @@ -53,16 +53,22 @@ def index INDEX mb.string end - - def persist_key; - @persist_key ||= "wizardly_#{controller_name.to_s.underscore}_#{model}".to_sym - end - + + def initial_referer_key + @initial_referer_key ||= "#{self.controller_path.sub(/\//, '')}_irk".to_sym + end + def persist_key; + @persist_key ||= "#{self.controller_path.sub(/\//, '')}_dat".to_sym + end + def progression_key + @progression_key ||= "#{self.controller_path.sub(/\//, '')}_prg".to_sym + end + def print_page_action_method(id) page = @pages[id] finish_button = self.button_for_function(:finish).id next_button = self.button_for_function(:next).id - model_persist_line = self.persist_model_per_page? ? 'save_wizard_model!' : '' + model_persist_line = self.persist_model_per_page? ? "@#{self.model}.save_without_validation!" : '' (mb = StringIO.new) << <<-ONE def #{page.name} @@ -95,15 +101,13 @@ def #{page.name} if self.last_page?(id) mb << <<-TWO callback_performs_action?(:on_#{id}_form_#{finish_button}) - _on_wizard_#{finish_button} - redirect_to #{Utils.formatted_redirect(self.completed_redirect)} unless self.performed? + complete_wizard TWO elsif self.first_page?(id) mb << <<-THREE if button_id == :#{finish_button} callback_performs_action?(:on_#{id}_form_#{finish_button}) - _on_wizard_#{finish_button} if button_id == :#{finish_button} - redirect_to #{Utils.formatted_redirect(self.completed_redirect)} unless self.performed? + complete_wizard return end #{model_persist_line} @@ -114,8 +118,7 @@ def #{page.name} mb << <<-FOUR if button_id == :#{finish_button} callback_performs_action?(:on_#{id}_form_#{finish_button}) - _on_wizard_#{finish_button} if button_id == :#{finish_button} - redirect_to #{Utils.formatted_redirect(self.completed_redirect)} unless self.performed? + complete_wizard return end #{model_persist_line} @@ -147,7 +150,7 @@ def _on_wizard_#{finish} _wizard_final_redirect_to(:completed) end def _on_wizard_#{skip} - session[:progression] = (session[:progression]||[]) - [@step] + self.progression = self.progression - [@step] redirect_to(:action=>wizard_config.next_page(@step)) unless self.performed? end def _on_wizard_#{back} @@ -156,12 +159,12 @@ def _on_wizard_#{back} def _on_wizard_#{cancel} _wizard_final_redirect_to(:canceled) end - def _wizard_final_redirect_to(type) - initial_referer = (type == :canceled && wizard_config.form_data_keep_in_session?) ? - session[:initial_referer] : + def _wizard_final_redirect_to(type) + init = (type == :canceled && wizard_config.form_data_keep_in_session?) ? + self.initial_referer : reset_wizard_session_vars unless self.performed? - redir = (type == :canceled ? wizard_config.canceled_redirect : wizard_config.completed_redirect) || initial_referer + redir = (type == :canceled ? wizard_config.canceled_redirect : wizard_config.completed_redirect) || init return redirect_to(redir) if redir raise Wizardly::RedirectNotDefinedError, "No redirect was defined for completion or canceling the wizard. Use :completed and :canceled options to define redirects.", caller end @@ -174,26 +177,27 @@ def print_helpers next_id = self.button_for_function(:next).id finish_id = self.button_for_function(:finish).id first_page = self.page_order.first + finish_button = self.button_for_function(:finish).id guard_line = self.guard? ? '' : 'return check_progression #guard entry disabled' mb = StringIO.new mb << <<-PROGRESSION protected def previous_in_progression_from(step) - po = wizard_config.page_order - p = session[:progression]||[] + po = #{self.page_order.inspect} + p = self.progression p -= po[po.index(step)..-1] - session[:progression] = p + self.progression = p p.last end def check_progression - p = session[:progression]||[] + p = self.progression a = params[:action].to_sym return if p.last == a - po = wizard_config.page_order + po = #{self.page_order.inspect} return unless (ai = po.index(a)) p -= po[ai..-1] p << a - session[:progression] = p + self.progression = p end PROGRESSION if self.form_data_keep_in_session? @@ -203,14 +207,14 @@ def guard_entry if (r = request.env['HTTP_REFERER']) h = ::ActionController::Routing::Routes.recognize_path(URI.parse(r).path) return check_progression if (h[:controller]||'') == '#{self.controller_name}' - session[:initial_referer] ||= h + self.initial_referer = h unless self.initial_referer end # coming from outside the controller #{guard_line} if (params[:action] == '#{first_page}' || params[:action] == 'index') return check_progression elsif self.wizard_form_data - p = session[:progression]||[] + p = self.progression return check_progression if p.include?(params[:action].to_sym) return redirect_to(:action=>(p.last||:#{first_page})) end @@ -226,9 +230,9 @@ def guard_entry if (r = request.env['HTTP_REFERER']) h = ::ActionController::Routing::Routes.recognize_path(URI.parse(r).path) return check_progression if (h[:controller]||'') == '#{self.controller_name}' - session[:initial_referer] = h + self.initial_referer = h else - session[:initial_referer] = nil + self.initial_referer = nil end # coming from outside the controller reset_wizard_form_data @@ -241,25 +245,38 @@ def guard_entry SANDBOX end mb << <<-HELPERS - def save_wizard_model! - @#{self.model}.save_without_validation! - if wizard_config.form_data_keep_in_session? - h = self.wizard_form_data - h['id'] = @#{self.model}.id - self.wizard_form_data= h - end + def complete_wizard(redirect = nil) + redirect_to redirect if redirect + _on_wizard_#{finish_button} + redirect_to #{Utils.formatted_redirect(self.completed_redirect)} unless self.performed? end def build_wizard_model(params) if (wizard_config.persist_model_per_page? && (model_id = params['id'])) - _model = #{self.model_class_name}.find(model_id) - _model.attributes = params - _model - else - #{self.model_class_name}.new(params) + begin + _model = #{self.model_class_name}.find(model_id) + _model.attributes = params + return _model + rescue + end end + #{self.model_class_name}.new(params) end hide_action :build_wizard_model, :save_wizard_model! + def initial_referer + session[:#{self.initial_referer_key}] + end + def initial_referer=(val) + session[:#{self.initial_referer_key}] = val + end + def progression=(array) + session[:#{self.progression_key}] = array + end + def progression + session[:#{self.progression_key}]||[] + end + hide_action :progression, :progression= + def wizard_form_data=(hash) if wizard_config.form_data_keep_in_session? session[:#{self.persist_key}] = hash @@ -291,9 +308,9 @@ def underscore_button_name(value) hide_action :underscore_button_name def reset_wizard_session_vars - session[:progression] = nil - init = session[:initial_referer] - session[:initial_referer] = nil + self.progression = nil + init = self.initial_referer + self.initial_referer = nil init end hide_action :reset_wizard_session_vars @@ -319,9 +336,19 @@ def check_action_for_button end hide_action :check_action_for_button - def callback_performs_action?(methId, arg=nil) - return false unless self.methods.include?(methId.to_s) - #self.__send__(methId) + @wizard_callbacks ||= {} + def self.wizard_callbacks; @wizard_callbacks; end + + def callback_performs_action?(methId) + cache = self.class.wizard_callbacks + return false if ((m = cache[methId]) == :none) + unless m == :found + unless self.methods.include?(methId.to_s) + cache[methId] = :none + return false + end + cache[methId] = :found + end self.method(methId).call self.performed? end diff --git a/public/images/Thumbs.db b/public/images/Thumbs.db new file mode 100644 index 0000000..764c349 Binary files /dev/null and b/public/images/Thumbs.db differ diff --git a/public/images/wizardly/Thumbs.db b/public/images/wizardly/Thumbs.db new file mode 100644 index 0000000..0e50de7 Binary files /dev/null and b/public/images/wizardly/Thumbs.db differ diff --git a/public/images/wizardly/back.png b/public/images/wizardly/back.png new file mode 100644 index 0000000..6a8c2d7 Binary files /dev/null and b/public/images/wizardly/back.png differ diff --git a/public/images/wizardly/cancel.png b/public/images/wizardly/cancel.png new file mode 100644 index 0000000..202a412 Binary files /dev/null and b/public/images/wizardly/cancel.png differ diff --git a/public/images/wizardly/finish.png b/public/images/wizardly/finish.png new file mode 100644 index 0000000..e6226a1 Binary files /dev/null and b/public/images/wizardly/finish.png differ diff --git a/public/images/wizardly/next.png b/public/images/wizardly/next.png new file mode 100644 index 0000000..f6000f0 Binary files /dev/null and b/public/images/wizardly/next.png differ diff --git a/public/images/wizardly/skip.png b/public/images/wizardly/skip.png new file mode 100644 index 0000000..fd319c4 Binary files /dev/null and b/public/images/wizardly/skip.png differ diff --git a/rails_generators/wizardly_controller/wizardly_controller_generator.rb b/rails_generators/wizardly_controller/wizardly_controller_generator.rb index 61e2da5..d1386ca 100644 --- a/rails_generators/wizardly_controller/wizardly_controller_generator.rb +++ b/rails_generators/wizardly_controller/wizardly_controller_generator.rb @@ -5,7 +5,7 @@ class WizardlyControllerGenerator < Rails::Generator::Base def initialize(runtime_args, runtime_options = {}) super - @controller_name = @args[0].sub(/^:/, '').underscore + @controller_name = @args[0].sub(/^:/,'') @model_name = @args[1].sub(/^:/, '').underscore @completed_redirect = @args[2] @canceled_redirect = @args[3] @@ -13,7 +13,7 @@ def initialize(runtime_args, runtime_options = {}) opts[:completed] = @completed_redirect if @completed_redirect opts[:canceled] = @canceled_redirect if @canceled_redirect - @wizard_config = Wizardly::Wizard::Configuration.new(@controller_name.to_sym, opts) + @wizard_config = Wizardly::Wizard::Configuration.new(@controller_name, opts) @wizard_config.inspect_model!(@model_name.to_sym) end diff --git a/rails_generators/wizardly_scaffold/templates/form.html.erb b/rails_generators/wizardly_scaffold/templates/form.html.erb index ed3ef86..080e427 100644 --- a/rails_generators/wizardly_scaffold/templates/form.html.erb +++ b/rails_generators/wizardly_scaffold/templates/form.html.erb @@ -14,7 +14,7 @@

<% end -%>

- <%%= wizardly_submit %> + <%%= <%= submit_tag %> %>

<%% end %> diff --git a/rails_generators/wizardly_scaffold/templates/form.html.haml.erb b/rails_generators/wizardly_scaffold/templates/form.html.haml.erb index 5b0b291..0a1f567 100644 --- a/rails_generators/wizardly_scaffold/templates/form.html.haml.erb +++ b/rails_generators/wizardly_scaffold/templates/form.html.haml.erb @@ -16,7 +16,7 @@ %br = f.<%= field.field_type %> :<%= field.name %> <% end %> - %p= wizardly_submit + %p= <%= submit_tag %> %script{:type=>'text/javascript'} document.getElementById('<%=first_field_id %>').focus() diff --git a/rails_generators/wizardly_scaffold/templates/helper.rb.erb b/rails_generators/wizardly_scaffold/templates/helper.rb.erb index fa551a8..c07aeb9 100644 --- a/rails_generators/wizardly_scaffold/templates/helper.rb.erb +++ b/rails_generators/wizardly_scaffold/templates/helper.rb.erb @@ -2,13 +2,29 @@ module <%=controller_name.camelize %>Helper def wizardly_submit @@wizardly_submit ||= {} - unless @@wizardly_submit[@step] + step_id = "#{controller_name}_#{@step}".to_sym + unless @@wizardly_submit[step_id] buttons = @wizard.pages[@step].buttons - @@wizardly_submit[@step] = buttons.inject(StringIO.new) do |io, button| + @@wizardly_submit[step_id] = buttons.inject(StringIO.new) do |io, button| io << submit_tag(button.name) end.string end - @@wizardly_submit[@step] + @@wizardly_submit[step_id] + end + + def wizardly_image_submit(asset_dir = nil, opts = {}) + @@wizardly_image_submit ||={} + step_id = "#{controller_name}_#{@step}".to_sym + unless @@wizardly_image_submit[step_id] + asset_dir = asset_dir ? "#{asset_dir}/".squeeze("/").sub(/^\//,'') : "wizardly/" + buttons = @wizard.pages[@step].buttons + opts[:name] = 'commit' + @@wizardly_image_submit[step_id] = buttons.inject(StringIO.new) do |io, button| + opts[:value] = button.name + io << image_submit_tag("#{asset_dir}#{button.id}.png", opts) + end.string + end + @@wizardly_image_submit[step_id] end end diff --git a/rails_generators/wizardly_scaffold/templates/images/back.png b/rails_generators/wizardly_scaffold/templates/images/back.png new file mode 100644 index 0000000..6a8c2d7 Binary files /dev/null and b/rails_generators/wizardly_scaffold/templates/images/back.png differ diff --git a/rails_generators/wizardly_scaffold/templates/images/cancel.png b/rails_generators/wizardly_scaffold/templates/images/cancel.png new file mode 100644 index 0000000..202a412 Binary files /dev/null and b/rails_generators/wizardly_scaffold/templates/images/cancel.png differ diff --git a/rails_generators/wizardly_scaffold/templates/images/finish.png b/rails_generators/wizardly_scaffold/templates/images/finish.png new file mode 100644 index 0000000..e6226a1 Binary files /dev/null and b/rails_generators/wizardly_scaffold/templates/images/finish.png differ diff --git a/rails_generators/wizardly_scaffold/templates/images/next.png b/rails_generators/wizardly_scaffold/templates/images/next.png new file mode 100644 index 0000000..f6000f0 Binary files /dev/null and b/rails_generators/wizardly_scaffold/templates/images/next.png differ diff --git a/rails_generators/wizardly_scaffold/templates/images/skip.png b/rails_generators/wizardly_scaffold/templates/images/skip.png new file mode 100644 index 0000000..fd319c4 Binary files /dev/null and b/rails_generators/wizardly_scaffold/templates/images/skip.png differ diff --git a/rails_generators/wizardly_scaffold/wizardly_scaffold_generator.rb b/rails_generators/wizardly_scaffold/wizardly_scaffold_generator.rb index c15ba6a..0f8ea6f 100644 --- a/rails_generators/wizardly_scaffold/wizardly_scaffold_generator.rb +++ b/rails_generators/wizardly_scaffold/wizardly_scaffold_generator.rb @@ -1,7 +1,7 @@ require 'wizardly' class WizardlyScaffoldGenerator < Rails::Generator::Base - attr_reader :wizard_config, :pages + attr_reader :wizard_config, :pages, :submit_tag attr_reader :controller_name, :controller_class_path, :controller_file_path, @@ -17,6 +17,7 @@ def add_options!(opt) opt.on('--haml', 'Generate scaffold for haml wizard') { |v| options[:output] = :haml } opt.on('--ajax', 'Generate scaffold for ajax wizard') { |v| options[:output] = :ajax } opt.on('--underscore', 'Append an underscore to front of each file') { |v| options[:underscore] = true } + opt.on('--image_submit', 'Use image submit tags in forms') {|v| options[:image_submit] = true } end @@ -47,6 +48,7 @@ def initialize(runtime_args, runtime_options = {}) @pages = @wizard_config.pages @model_name = @wizard_config.model + @submit_tag = options[:image_submit] ? "wizardly_image_submit" : "wizardly_submit" #based on options, default is --html, others --ajax, --haml @view_file_ext = ["html.erb", "html.erb"] @@ -60,6 +62,7 @@ def manifest m.directory(File.join('app/helpers', controller_class_path)) m.directory(File.join('app/views', controller_class_path, controller_name)) m.directory(File.join('app/views/layouts', controller_class_path)) + m.directory('public/images/wizardly') if options[:image_submit] #m.directory(File.join('test/functional', controller_class_path)) #m.directory(File.join('public/stylesheets', class_path)) @@ -72,6 +75,12 @@ def manifest ) end + if options[:image_submit] + %w(next skip back cancel finish).each do |fn| + m.file("images/#{fn}.png", "public/images/wizardly/#{fn}.png") + end + end + m.template("helper.rb.erb", File.join('app/helpers', controller_class_path, "#{controller_name}_helper.rb")) # Layout and stylesheet. diff --git a/spec/integrations/data_modes2_spec.rb b/spec/integrations/data_modes2_spec.rb new file mode 100644 index 0000000..9b9998c --- /dev/null +++ b/spec/integrations/data_modes2_spec.rb @@ -0,0 +1,103 @@ +require File.dirname(__FILE__) + '/../spec_helper' +require 'step_helpers' + +module TestVariables + def init_page; "init"; end + def second_page; "second"; end + def finish_page; "finish"; end + def blank_error; "can't be blank"; end + def back_button; "back"; end + def next_button; "next"; end + def skip_button; "skip"; end + def finish_button; "finish"; end + def cancel_button; "cancel"; end + def field_first_name; "john"; end + def field_last_name; "doe"; end + def field_age; 30; end + def field_programmer; true; end + def field_status; "active"; end + def field_gender; "male"; end + def field_password; "password"; end + def field_password_confirmation; field_password; end + def field_username; "johndoe"; end + def index_page_path; '/data_modes2/index'; end + def finish_page_path; '/data_modes2/finish'; end + def second_page_path; '/data_modes2/second'; end + def init_page_path; '/data_modes2/init'; end + def main_finished_path; '/main/finished'; end + def main_canceled_path; '/main/canceled'; end +end + +#testing :persist_model=>:per_page, :form_data=>:sandbox +describe "DataModes2Controller" do + include TestVariables + include StepHelpers + + it "should save model incrementally" do + User.delete_all + step_to_finish_page + u = User.find(:first) + assert u + u.first_name.should == field_first_name + u.last_name.should == field_last_name + step_to_finish_page + v = User.find(:first) + assert v + v.first_name.should == field_first_name + v.last_name.should == field_last_name + v.age.should == field_age + v.status.should == field_status + v.programmer.should == field_programmer + v.gender.should == field_gender + w = User.find(:all) + w.size.should == 1 + end + + it "should complete wizard, save model, and create new model next time" do + User.delete_all + step_to_finish_page + fill_in_finish_page + click_button finish_button + u = User.find(:first) + assert u + u.first_name.should == field_first_name + u.password.should == field_password + step_to_second_page + w = User.find(:all) + w.size.should == 2 + w.first.id.should_not == w.last.id + end + + it "should fill in first page, leave and return to first page" do + User.delete_all + step_to_init_page + current_url.should include(init_page) + field_with_id(/first/).value.should be_blank + field_with_id(/last/).value.should be_blank + fill_in_init_page + click_button cancel_button + visit init_page_path + field_with_id(/first/).value.should be_blank + field_with_id(/last/).value.should be_blank + end + + it "should fill in second page, leave and return to init page when trying to return to second page directly" do + User.delete_all + step_to_second_page + current_url.should include(second_page) + field_with_id(/age/).value.should be_blank + field_with_id(/status/).value.should be_blank + fill_in_second_page + click_button cancel_button + visit '/data_modes/'+ second_page + current_url.should include(init_page) + field_with_id(/first/).value.should be_blank + field_with_id(/last/).value.should be_blank + click_button next_button + end + + + it_should_behave_like "form data using sandbox" + it_should_behave_like "all implementations" + +end diff --git a/spec/integrations/data_modes_spec.rb b/spec/integrations/data_modes_spec.rb index c302602..56efb9a 100644 --- a/spec/integrations/data_modes_spec.rb +++ b/spec/integrations/data_modes_spec.rb @@ -35,7 +35,7 @@ def main_canceled_path; '/main/canceled'; end it "should save model incrementally" do User.delete_all - step_to_second_page + step_to_finish_page u = User.find(:first) assert u u.first_name.should == field_first_name @@ -49,6 +49,8 @@ def main_canceled_path; '/main/canceled'; end v.status.should == field_status v.programmer.should == field_programmer v.gender.should == field_gender + w = User.find(:all) + w.size.should == 1 end it "should complete wizard, save model, and create new model next time" do @@ -58,6 +60,8 @@ def main_canceled_path; '/main/canceled'; end click_button finish_button u = User.find(:first) assert u + u.first_name.should == field_first_name + u.password.should == field_password step_to_second_page w = User.find(:all) w.size.should == 2 @@ -65,6 +69,7 @@ def main_canceled_path; '/main/canceled'; end end it "should fill in first page, leave and return to first page" do + User.delete_all step_to_init_page current_url.should include(init_page) field_with_id(/first/).value.should be_blank @@ -77,6 +82,7 @@ def main_canceled_path; '/main/canceled'; end end it "should fill in second page, leave and return to second page directly" do + User.delete_all step_to_second_page current_url.should include(second_page) field_with_id(/age/).value.should be_blank diff --git a/test/functional/image_submit_controller_test.rb b/test/functional/image_submit_controller_test.rb new file mode 100644 index 0000000..28ed576 --- /dev/null +++ b/test/functional/image_submit_controller_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class ImageSubmitControllerTest < ActionController::TestCase + # Replace this with your real tests. + test "the truth" do + assert true + end +end diff --git a/test/unit/helpers/image_submit_helper_test.rb b/test/unit/helpers/image_submit_helper_test.rb new file mode 100644 index 0000000..2c599bb --- /dev/null +++ b/test/unit/helpers/image_submit_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class ImageSubmitHelperTest < ActionView::TestCase +end