edk-wizardly 0.1.8.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +38 -0
- data/LICENSE +20 -0
- data/README.rdoc +645 -0
- data/init.rb +1 -0
- data/lib/jeffp-wizardly.rb +1 -0
- data/lib/validation_group.rb +147 -0
- data/lib/wizardly/action_controller.rb +36 -0
- data/lib/wizardly/wizard/button.rb +35 -0
- data/lib/wizardly/wizard/configuration/methods.rb +414 -0
- data/lib/wizardly/wizard/configuration.rb +194 -0
- data/lib/wizardly/wizard/dsl.rb +27 -0
- data/lib/wizardly/wizard/page.rb +62 -0
- data/lib/wizardly/wizard/text_helpers.rb +16 -0
- data/lib/wizardly/wizard/utils.rb +11 -0
- data/lib/wizardly/wizard.rb +16 -0
- data/lib/wizardly.rb +31 -0
- data/rails_generators/wizardly_app/USAGE +6 -0
- data/rails_generators/wizardly_app/templates/wizardly.rake +37 -0
- data/rails_generators/wizardly_app/wizardly_app_generator.rb +41 -0
- data/rails_generators/wizardly_controller/USAGE +3 -0
- data/rails_generators/wizardly_controller/templates/controller.rb.erb +34 -0
- data/rails_generators/wizardly_controller/templates/helper.rb.erb +14 -0
- data/rails_generators/wizardly_controller/wizardly_controller_generator.rb +57 -0
- data/rails_generators/wizardly_scaffold/USAGE +4 -0
- data/rails_generators/wizardly_scaffold/templates/form.html.erb +23 -0
- data/rails_generators/wizardly_scaffold/templates/form.html.haml.erb +22 -0
- data/rails_generators/wizardly_scaffold/templates/helper.rb.erb +30 -0
- data/rails_generators/wizardly_scaffold/templates/images/back.png +0 -0
- data/rails_generators/wizardly_scaffold/templates/images/cancel.png +0 -0
- data/rails_generators/wizardly_scaffold/templates/images/finish.png +0 -0
- data/rails_generators/wizardly_scaffold/templates/images/next.png +0 -0
- data/rails_generators/wizardly_scaffold/templates/images/skip.png +0 -0
- data/rails_generators/wizardly_scaffold/templates/layout.html.erb +15 -0
- data/rails_generators/wizardly_scaffold/templates/layout.html.haml.erb +10 -0
- data/rails_generators/wizardly_scaffold/templates/style.css +54 -0
- data/rails_generators/wizardly_scaffold/wizardly_scaffold_generator.rb +109 -0
- metadata +100 -0
data/init.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'wizardly'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'wizardly'
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
module ValidationGroup
|
|
2
|
+
module ActiveRecord
|
|
3
|
+
module ActsMethods # extends ActiveRecord::Base
|
|
4
|
+
def self.extended(base)
|
|
5
|
+
# Add class accessor which is shared between all models and stores
|
|
6
|
+
# validation groups defined for each model
|
|
7
|
+
base.class_eval do
|
|
8
|
+
cattr_accessor :validation_group_classes
|
|
9
|
+
self.validation_group_classes = {}
|
|
10
|
+
|
|
11
|
+
def self.validation_group_order; @validation_group_order; end
|
|
12
|
+
def self.validation_groups(all_classes = false)
|
|
13
|
+
return (self.validation_group_classes[self] || {}) unless all_classes
|
|
14
|
+
klasses = ValidationGroup::Util.current_and_ancestors(self).reverse
|
|
15
|
+
returning Hash.new do |hash|
|
|
16
|
+
klasses.each do |klass|
|
|
17
|
+
hash.merge! self.validation_group_classes[klass]
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def validation_group(name, options={})
|
|
25
|
+
self_groups = (self.validation_group_classes[self] ||= {})
|
|
26
|
+
self_groups[name.to_sym] = case options[:fields]
|
|
27
|
+
when Array then options[:fields]
|
|
28
|
+
when Symbol, String then [options[:fields].to_sym]
|
|
29
|
+
else []
|
|
30
|
+
end
|
|
31
|
+
# jeffp: capture the declaration order for this class only (no
|
|
32
|
+
# superclasses)
|
|
33
|
+
(@validation_group_order ||= []) << name.to_sym
|
|
34
|
+
|
|
35
|
+
unless included_modules.include?(InstanceMethods)
|
|
36
|
+
# jeffp: added reader for current_validation_fields
|
|
37
|
+
attr_reader :current_validation_group, :current_validation_fields
|
|
38
|
+
include InstanceMethods
|
|
39
|
+
# jeffp: add valid?(group = nil), see definition below
|
|
40
|
+
alias_method_chain :valid?, :validation_group
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
module InstanceMethods # included in every model which calls validation_group
|
|
46
|
+
#needs testing
|
|
47
|
+
# def reset_fields_for_validation_group(group)
|
|
48
|
+
# group_classes = self.class.validation_group_classes
|
|
49
|
+
# found = ValidationGroup::Util.current_and_ancestors(self.class).find do |klass|
|
|
50
|
+
# group_classes[klass] && group_classes[klass].include?(group)
|
|
51
|
+
# end
|
|
52
|
+
# if found
|
|
53
|
+
# group_classes[found][group].each do |field|
|
|
54
|
+
# self[field] = nil
|
|
55
|
+
# end
|
|
56
|
+
# end
|
|
57
|
+
# end
|
|
58
|
+
def enable_validation_group(group)
|
|
59
|
+
# Check if given validation group is defined for current class or one of
|
|
60
|
+
# its ancestors
|
|
61
|
+
group_classes = self.class.validation_group_classes
|
|
62
|
+
found = ValidationGroup::Util.current_and_ancestors(self.class).
|
|
63
|
+
find do |klass|
|
|
64
|
+
group_classes[klass] && group_classes[klass].include?(group)
|
|
65
|
+
end
|
|
66
|
+
if found
|
|
67
|
+
@current_validation_group = group
|
|
68
|
+
# jeffp: capture current fields for performance optimization
|
|
69
|
+
@current_validation_fields = group_classes[found][group]
|
|
70
|
+
else
|
|
71
|
+
raise ArgumentError, "No validation group of name :#{group}"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def disable_validation_group
|
|
76
|
+
@current_validation_group = nil
|
|
77
|
+
# jeffp: delete fields
|
|
78
|
+
@current_validation_fields = nil
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def reject_non_validation_group_errors
|
|
82
|
+
return unless validation_group_enabled?
|
|
83
|
+
self.errors.remove_on(@current_validation_fields)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# jeffp: optimizer for someone writing custom :validate method -- no need
|
|
87
|
+
# to validate fields outside the current validation group note: could also
|
|
88
|
+
# use in validation modules to improve performance
|
|
89
|
+
def should_validate?(attribute)
|
|
90
|
+
!self.validation_group_enabled? || (@current_validation_fields && @current_validation_fields.include?(attribute.to_sym))
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def validation_group_enabled?
|
|
94
|
+
respond_to?(:current_validation_group) && !current_validation_group.nil?
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# eliminates need to use :enable_validation_group before :valid? call --
|
|
98
|
+
# nice
|
|
99
|
+
def valid_with_validation_group?(group=nil)
|
|
100
|
+
self.enable_validation_group(group) if group
|
|
101
|
+
valid_without_validation_group?
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
module Errors # included in ActiveRecord::Errors
|
|
106
|
+
def add_with_validation_group(attribute,
|
|
107
|
+
msg = @@default_error_messages[:invalid], *args,
|
|
108
|
+
&block)
|
|
109
|
+
# jeffp: setting @current_validation_fields and use of should_validate? optimizes code
|
|
110
|
+
add_error = @base.respond_to?(:should_validate?) ? @base.should_validate?(attribute.to_sym) : true
|
|
111
|
+
add_without_validation_group(attribute, msg, *args, &block) if add_error
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def remove_on(attributes)
|
|
115
|
+
return unless attributes
|
|
116
|
+
attributes = [attributes] unless attributes.is_a?(Array)
|
|
117
|
+
@errors.reject!{|k,v| !attributes.include?(k.to_sym)}
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def self.included(base) #:nodoc:
|
|
121
|
+
base.class_eval do
|
|
122
|
+
alias_method_chain :add, :validation_group
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
module Util
|
|
129
|
+
# Return array consisting of current and its superclasses down to and
|
|
130
|
+
# including base_class.
|
|
131
|
+
def self.current_and_ancestors(current)
|
|
132
|
+
returning [] do |klasses|
|
|
133
|
+
klasses << current
|
|
134
|
+
root = current.base_class
|
|
135
|
+
until current == root
|
|
136
|
+
current = current.superclass
|
|
137
|
+
klasses << current
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# jeffp: moved from init.rb for gemification purposes --
|
|
145
|
+
# require 'validation_group' loads everything now, init.rb requires 'validation_group' only
|
|
146
|
+
ActiveRecord::Base.send(:extend, ValidationGroup::ActiveRecord::ActsMethods)
|
|
147
|
+
ActiveRecord::Errors.send :include, ValidationGroup::ActiveRecord::Errors
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'wizardly/wizard'
|
|
2
|
+
|
|
3
|
+
module Wizardly
|
|
4
|
+
module ActionController
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.extend(ClassMethods)
|
|
7
|
+
|
|
8
|
+
base.class_eval do
|
|
9
|
+
before_filter :guard_entry
|
|
10
|
+
class << self
|
|
11
|
+
attr_reader :wizard_config #note: reader for @wizard_config on the class (not the instance)
|
|
12
|
+
end
|
|
13
|
+
hide_action :reset_wizard_session_vars, :wizard_config, :methodize_button_name
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
module ClassMethods
|
|
18
|
+
private
|
|
19
|
+
def configure_wizard_for_model(model, opts={}, &block)
|
|
20
|
+
|
|
21
|
+
# controller_name = self.name.sub(/Controller$/, '').underscore.to_sym
|
|
22
|
+
@wizard_config = Wizardly::Wizard::Configuration.create(controller_name, model, opts, &block)
|
|
23
|
+
# define methods
|
|
24
|
+
self.class_eval @wizard_config.print_page_action_methods
|
|
25
|
+
self.class_eval @wizard_config.print_callbacks
|
|
26
|
+
self.class_eval @wizard_config.print_helpers
|
|
27
|
+
self.class_eval @wizard_config.print_callback_macros
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# instance methods for controller
|
|
32
|
+
public
|
|
33
|
+
def wizard_config; self.class.wizard_config; end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'wizardly/wizard/text_helpers'
|
|
2
|
+
|
|
3
|
+
module Wizardly
|
|
4
|
+
module Wizard
|
|
5
|
+
class Button
|
|
6
|
+
include TextHelpers
|
|
7
|
+
attr_reader :name
|
|
8
|
+
attr_reader :id
|
|
9
|
+
|
|
10
|
+
def initialize(id, name=nil)
|
|
11
|
+
@id = id
|
|
12
|
+
@name = name || symbol_to_button_name(id)
|
|
13
|
+
@user_defined = false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def user_defined?; @user_defined; end
|
|
17
|
+
|
|
18
|
+
#used in the dsl
|
|
19
|
+
def name_to(name, opts={})
|
|
20
|
+
case name
|
|
21
|
+
when String then @name = name.strip.squeeze(' ')
|
|
22
|
+
when Symbol then @name = symbol_to_button_name(name)
|
|
23
|
+
end
|
|
24
|
+
@id = opts[:id] if (opts[:id] && opts[:id].is_a?(Symbol))
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class UserDefinedButton < Button
|
|
29
|
+
def initialize(id, name=nil)
|
|
30
|
+
super
|
|
31
|
+
@user_defined = true
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
module Wizardly
|
|
2
|
+
module Wizard
|
|
3
|
+
class Configuration
|
|
4
|
+
|
|
5
|
+
def print_callback_macros
|
|
6
|
+
macros = [
|
|
7
|
+
%w(on_post _on_post_%s_form),
|
|
8
|
+
%w(on_get _on_get_%s_form),
|
|
9
|
+
%w(on_errors _on_invalid_%s_form)
|
|
10
|
+
]
|
|
11
|
+
self.buttons.each do |id, button|
|
|
12
|
+
macros << ['on_'+ id.to_s, '_on_%s_form_'+ id.to_s ]
|
|
13
|
+
end
|
|
14
|
+
mb = StringIO.new
|
|
15
|
+
macros.each do |macro|
|
|
16
|
+
mb << <<-MACRO
|
|
17
|
+
def self.#{macro.first}(*args, &block)
|
|
18
|
+
self._define_action_callback_macro('#{macro.first}', '#{macro.last}', *args, &block)
|
|
19
|
+
end
|
|
20
|
+
MACRO
|
|
21
|
+
end
|
|
22
|
+
mb << <<-DEFMAC
|
|
23
|
+
def self._define_action_callback_macro(macro_first, macro_last, *args, &block)
|
|
24
|
+
return if args.empty?
|
|
25
|
+
all_forms = #{page_order.inspect}
|
|
26
|
+
if args.include?(:all)
|
|
27
|
+
forms = all_forms
|
|
28
|
+
else
|
|
29
|
+
forms = args.map do |fa|
|
|
30
|
+
unless all_forms.include?(fa)
|
|
31
|
+
raise(ArgumentError, ":"+fa.to_s+" in callback '" + macro_first + "' is not a form defined for the wizard", caller)
|
|
32
|
+
end
|
|
33
|
+
fa
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
forms.each do |form|
|
|
37
|
+
self.send(:define_method, sprintf(macro_last, form.to_s), &block )
|
|
38
|
+
hide_action macro_last.to_sym
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
DEFMAC
|
|
43
|
+
|
|
44
|
+
[
|
|
45
|
+
%w(on_completed _after_wizard_save)
|
|
46
|
+
].each do |macro|
|
|
47
|
+
mb << <<-EVENTS
|
|
48
|
+
def self.#{macro.first}(&block)
|
|
49
|
+
self.send(:define_method, :#{macro.last}, &block )
|
|
50
|
+
end
|
|
51
|
+
EVENTS
|
|
52
|
+
end
|
|
53
|
+
mb.string
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def print_page_action_methods
|
|
57
|
+
mb = StringIO.new
|
|
58
|
+
self.pages.each do |id, p|
|
|
59
|
+
mb << <<-COMMENT
|
|
60
|
+
|
|
61
|
+
# #{id} action method
|
|
62
|
+
#{self.print_page_action_method(id)}
|
|
63
|
+
COMMENT
|
|
64
|
+
end
|
|
65
|
+
mb << <<-INDEX
|
|
66
|
+
def index
|
|
67
|
+
redirect_to :action=>:#{self.page_order.first}
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
INDEX
|
|
71
|
+
mb.string
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def initial_referer_key
|
|
75
|
+
@initial_referer_key ||= "#{self.controller_path.sub(/\//, '')}_irk".to_sym
|
|
76
|
+
end
|
|
77
|
+
def persist_key;
|
|
78
|
+
@persist_key ||= "#{self.controller_path.sub(/\//, '')}_dat".to_sym
|
|
79
|
+
end
|
|
80
|
+
def progression_key
|
|
81
|
+
@progression_key ||= "#{self.controller_path.sub(/\//, '')}_prg".to_sym
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def print_page_action_method(id)
|
|
85
|
+
page = @pages[id]
|
|
86
|
+
finish_button = self.button_for_function(:finish).id
|
|
87
|
+
next_button = self.button_for_function(:next).id
|
|
88
|
+
|
|
89
|
+
(mb = StringIO.new) << <<-ONE
|
|
90
|
+
def #{page.name}
|
|
91
|
+
begin
|
|
92
|
+
@step = :#{id}
|
|
93
|
+
@wizard = wizard_config
|
|
94
|
+
@title = '#{page.title}'
|
|
95
|
+
@description = '#{page.description}'
|
|
96
|
+
_build_wizard_model
|
|
97
|
+
if request.post? && callback_performs_action?(:_on_post_#{id}_form)
|
|
98
|
+
raise CallbackError, "render or redirect not allowed in :on_post(:#{id}) callback", caller
|
|
99
|
+
end
|
|
100
|
+
button_id = check_action_for_button
|
|
101
|
+
return if performed?
|
|
102
|
+
if request.get?
|
|
103
|
+
return if callback_performs_action?(:_on_get_#{id}_form)
|
|
104
|
+
render_wizard_form
|
|
105
|
+
return
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# @#{self.model}.enable_validation_group :#{id}
|
|
109
|
+
unless @#{self.model}.valid?(:#{id})
|
|
110
|
+
return if callback_performs_action?(:_on_invalid_#{id}_form)
|
|
111
|
+
render_wizard_form
|
|
112
|
+
return
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
@do_not_complete = false
|
|
116
|
+
ONE
|
|
117
|
+
if self.last_page?(id)
|
|
118
|
+
mb << <<-TWO
|
|
119
|
+
callback_performs_action?(:_on_#{id}_form_#{finish_button})
|
|
120
|
+
complete_wizard unless @do_not_complete
|
|
121
|
+
TWO
|
|
122
|
+
elsif self.first_page?(id)
|
|
123
|
+
mb << <<-THREE
|
|
124
|
+
if button_id == :#{finish_button}
|
|
125
|
+
callback_performs_action?(:_on_#{id}_form_#{finish_button})
|
|
126
|
+
complete_wizard unless @do_not_complete
|
|
127
|
+
return
|
|
128
|
+
end
|
|
129
|
+
return if callback_performs_action?(:_on_#{id}_form_#{next_button})
|
|
130
|
+
redirect_to :action=>:#{self.next_page(id)}
|
|
131
|
+
THREE
|
|
132
|
+
else
|
|
133
|
+
mb << <<-FOUR
|
|
134
|
+
if button_id == :#{finish_button}
|
|
135
|
+
callback_performs_action?(:_on_#{id}_form_#{finish_button})
|
|
136
|
+
complete_wizard unless @do_not_complete
|
|
137
|
+
return
|
|
138
|
+
end
|
|
139
|
+
return if callback_performs_action?(:_on_#{id}_form_#{next_button})
|
|
140
|
+
redirect_to :action=>:#{self.next_page(id)}
|
|
141
|
+
FOUR
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
mb << <<-ENSURE
|
|
145
|
+
ensure
|
|
146
|
+
_preserve_wizard_model
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
ENSURE
|
|
150
|
+
mb.string
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def print_callbacks
|
|
154
|
+
finish = self.button_for_function(:finish).id
|
|
155
|
+
skip = self.button_for_function(:skip).id
|
|
156
|
+
back = self.button_for_function(:back).id
|
|
157
|
+
cancel = self.button_for_function(:cancel).id
|
|
158
|
+
<<-CALLBACKS
|
|
159
|
+
protected
|
|
160
|
+
def _on_wizard_#{finish}
|
|
161
|
+
return if @wizard_completed_flag
|
|
162
|
+
@#{self.model}.save_without_validation! if @#{self.model}.changed?
|
|
163
|
+
@wizard_completed_flag = true
|
|
164
|
+
reset_wizard_form_data
|
|
165
|
+
_wizard_final_redirect_to(:completed)
|
|
166
|
+
end
|
|
167
|
+
def _on_wizard_#{skip}
|
|
168
|
+
self.progression = self.progression - [@step]
|
|
169
|
+
redirect_to(:action=>wizard_config.next_page(@step)) unless self.performed?
|
|
170
|
+
end
|
|
171
|
+
def _on_wizard_#{back}
|
|
172
|
+
redirect_to(:action=>(previous_in_progression_from(@step) || :#{self.page_order.first})) unless self.performed?
|
|
173
|
+
end
|
|
174
|
+
def _on_wizard_#{cancel}
|
|
175
|
+
_wizard_final_redirect_to(:canceled)
|
|
176
|
+
end
|
|
177
|
+
def _wizard_final_redirect_to(type)
|
|
178
|
+
init = (type == :canceled && wizard_config.form_data_keep_in_session?) ?
|
|
179
|
+
self.initial_referer :
|
|
180
|
+
reset_wizard_session_vars
|
|
181
|
+
unless self.performed?
|
|
182
|
+
redir = (type == :canceled ? wizard_config.canceled_redirect : wizard_config.completed_redirect) || init
|
|
183
|
+
return redirect_to(redir) if redir
|
|
184
|
+
raise Wizardly::RedirectNotDefinedError, "No redirect was defined for completion or canceling the wizard. Use :completed and :canceled options to define redirects.", caller
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
hide_action :_on_wizard_#{finish}, :_on_wizard_#{skip}, :_on_wizard_#{back}, :_on_wizard_#{cancel}, :_wizard_final_redirect_to
|
|
188
|
+
CALLBACKS
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def print_helpers
|
|
192
|
+
next_id = self.button_for_function(:next).id
|
|
193
|
+
finish_id = self.button_for_function(:finish).id
|
|
194
|
+
first_page = self.page_order.first
|
|
195
|
+
finish_button = self.button_for_function(:finish).id
|
|
196
|
+
guard_line = self.guard? ? '' : 'return check_progression #guard entry disabled'
|
|
197
|
+
mb = StringIO.new
|
|
198
|
+
mb << <<-PROGRESSION
|
|
199
|
+
protected
|
|
200
|
+
def do_not_complete; @do_not_complete = true; end
|
|
201
|
+
def previous_in_progression_from(step)
|
|
202
|
+
po = #{self.page_order.inspect}
|
|
203
|
+
p = self.progression
|
|
204
|
+
p -= po[po.index(step)..-1]
|
|
205
|
+
self.progression = p
|
|
206
|
+
p.last
|
|
207
|
+
end
|
|
208
|
+
def check_progression
|
|
209
|
+
p = self.progression
|
|
210
|
+
a = params[:action].to_sym
|
|
211
|
+
return if p.last == a
|
|
212
|
+
po = #{self.page_order.inspect}
|
|
213
|
+
return unless (ai = po.index(a))
|
|
214
|
+
p -= po[ai..-1]
|
|
215
|
+
p << a
|
|
216
|
+
self.progression = p
|
|
217
|
+
end
|
|
218
|
+
PROGRESSION
|
|
219
|
+
if self.form_data_keep_in_session?
|
|
220
|
+
mb << <<-SESSION
|
|
221
|
+
# for :form_data=>:session
|
|
222
|
+
def guard_entry
|
|
223
|
+
if (r = request.env['HTTP_REFERER'])
|
|
224
|
+
h = ::ActionController::Routing::Routes.recognize_path(URI.parse(r).path)
|
|
225
|
+
return check_progression if (h[:controller].split('/').last||'') == '#{self.controller_name}'
|
|
226
|
+
self.initial_referer = h unless self.initial_referer
|
|
227
|
+
end
|
|
228
|
+
# coming from outside the controller
|
|
229
|
+
#{guard_line}
|
|
230
|
+
if (params[:action] == '#{first_page}' || params[:action] == 'index')
|
|
231
|
+
return check_progression
|
|
232
|
+
elsif self.wizard_form_data
|
|
233
|
+
p = self.progression
|
|
234
|
+
return check_progression if p.include?(params[:action].to_sym)
|
|
235
|
+
return redirect_to(:action=>(p.last||:#{first_page}))
|
|
236
|
+
end
|
|
237
|
+
redirect_to :action=>:#{first_page}
|
|
238
|
+
end
|
|
239
|
+
hide_action :guard_entry
|
|
240
|
+
|
|
241
|
+
SESSION
|
|
242
|
+
else
|
|
243
|
+
mb << <<-SANDBOX
|
|
244
|
+
# for :form_data=>:sandbox
|
|
245
|
+
def guard_entry
|
|
246
|
+
if (r = request.env['HTTP_REFERER'])
|
|
247
|
+
h = ::ActionController::Routing::Routes.recognize_path(URI.parse(r).path)
|
|
248
|
+
return check_progression if (h[:controller].split('/').last||'') == '#{self.controller_name}'
|
|
249
|
+
self.initial_referer = h
|
|
250
|
+
else
|
|
251
|
+
self.initial_referer = nil
|
|
252
|
+
end
|
|
253
|
+
# coming from outside the controller
|
|
254
|
+
reset_wizard_form_data
|
|
255
|
+
#{guard_line}
|
|
256
|
+
return redirect_to(:action=>:#{first_page}) unless (params[:action] || '') == '#{first_page}'
|
|
257
|
+
check_progression
|
|
258
|
+
end
|
|
259
|
+
hide_action :guard_entry
|
|
260
|
+
|
|
261
|
+
SANDBOX
|
|
262
|
+
end
|
|
263
|
+
mb << <<-HELPERS
|
|
264
|
+
def render_and_return
|
|
265
|
+
return if callback_performs_action?('_on_get_'+@step.to_s+'_form')
|
|
266
|
+
render_wizard_form
|
|
267
|
+
render unless self.performed?
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def complete_wizard(redirect = nil)
|
|
271
|
+
unless @wizard_completed_flag
|
|
272
|
+
@#{self.model}.save_without_validation!
|
|
273
|
+
callback_performs_action?(:_after_wizard_save)
|
|
274
|
+
end
|
|
275
|
+
redirect_to redirect if (redirect && !self.performed?)
|
|
276
|
+
return if @wizard_completed_flag
|
|
277
|
+
_on_wizard_#{finish_button}
|
|
278
|
+
redirect_to(#{Utils.formatted_redirect(self.completed_redirect)}) unless self.performed?
|
|
279
|
+
end
|
|
280
|
+
def _build_wizard_model
|
|
281
|
+
if self.wizard_config.persist_model_per_page?
|
|
282
|
+
h = self.wizard_form_data
|
|
283
|
+
if (h && model_id = h['id'])
|
|
284
|
+
_model = #{self.model_class_name}.find(model_id)
|
|
285
|
+
_model.attributes = params[:#{self.model}]||{}
|
|
286
|
+
@#{self.model} = _model
|
|
287
|
+
return
|
|
288
|
+
end
|
|
289
|
+
@#{self.model} = #{self.model_class_name}.new(params[:#{self.model}])
|
|
290
|
+
else # persist data in session or flash
|
|
291
|
+
h = (self.wizard_form_data||{}).merge(params[:#{self.model}] || {})
|
|
292
|
+
@#{self.model} = #{self.model_class_name}.new(h)
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
def _preserve_wizard_model
|
|
296
|
+
return unless (@#{self.model} && !@wizard_completed_flag)
|
|
297
|
+
if self.wizard_config.persist_model_per_page?
|
|
298
|
+
@#{self.model}.save_without_validation!
|
|
299
|
+
if request.get?
|
|
300
|
+
@#{self.model}.errors.clear
|
|
301
|
+
else
|
|
302
|
+
@#{self.model}.reject_non_validation_group_errors
|
|
303
|
+
end
|
|
304
|
+
self.wizard_form_data = {'id'=>@#{self.model}.id}
|
|
305
|
+
else
|
|
306
|
+
self.wizard_form_data = @#{self.model}.attributes
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
hide_action :_build_wizard_model, :_preserve_wizard_model
|
|
310
|
+
|
|
311
|
+
def initial_referer
|
|
312
|
+
session[:#{self.initial_referer_key}]
|
|
313
|
+
end
|
|
314
|
+
def initial_referer=(val)
|
|
315
|
+
session[:#{self.initial_referer_key}] = val
|
|
316
|
+
end
|
|
317
|
+
def progression=(array)
|
|
318
|
+
session[:#{self.progression_key}] = array
|
|
319
|
+
end
|
|
320
|
+
def progression
|
|
321
|
+
session[:#{self.progression_key}]||[]
|
|
322
|
+
end
|
|
323
|
+
hide_action :progression, :progression=, :initial_referer, :initial_referer=
|
|
324
|
+
|
|
325
|
+
def wizard_form_data=(hash)
|
|
326
|
+
if wizard_config.form_data_keep_in_session?
|
|
327
|
+
session[:#{self.persist_key}] = hash
|
|
328
|
+
else
|
|
329
|
+
if hash
|
|
330
|
+
flash[:#{self.persist_key}] = hash
|
|
331
|
+
else
|
|
332
|
+
flash.discard(:#{self.persist_key})
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def reset_wizard_form_data; self.wizard_form_data = nil; end
|
|
338
|
+
def wizard_form_data
|
|
339
|
+
wizard_config.form_data_keep_in_session? ? session[:#{self.persist_key}] : flash[:#{self.persist_key}]
|
|
340
|
+
end
|
|
341
|
+
hide_action :wizard_form_data, :wizard_form_data=, :reset_wizard_form_data
|
|
342
|
+
|
|
343
|
+
def render_wizard_form
|
|
344
|
+
end
|
|
345
|
+
hide_action :render_wizard_form
|
|
346
|
+
|
|
347
|
+
def performed?; super; end
|
|
348
|
+
hide_action :performed?
|
|
349
|
+
|
|
350
|
+
def underscore_button_name(value)
|
|
351
|
+
value.to_s.strip.squeeze(' ').gsub(/ /, '_').downcase
|
|
352
|
+
end
|
|
353
|
+
hide_action :underscore_button_name
|
|
354
|
+
|
|
355
|
+
def reset_wizard_session_vars
|
|
356
|
+
self.progression = nil
|
|
357
|
+
init = self.initial_referer
|
|
358
|
+
self.initial_referer = nil
|
|
359
|
+
init
|
|
360
|
+
end
|
|
361
|
+
hide_action :reset_wizard_session_vars
|
|
362
|
+
|
|
363
|
+
def check_action_for_button
|
|
364
|
+
button_id = nil
|
|
365
|
+
case
|
|
366
|
+
when params[:commit]
|
|
367
|
+
button_name = params[:commit]
|
|
368
|
+
button_id = underscore_button_name(button_name).to_sym
|
|
369
|
+
when ((b_ar = self.wizard_config.buttons.find{|k,b| params[k]}) && params[b_ar.first] == b_ar.last.name)
|
|
370
|
+
button_name = b_ar.last.name
|
|
371
|
+
button_id = b_ar.first
|
|
372
|
+
end
|
|
373
|
+
if button_id
|
|
374
|
+
unless [:#{next_id}, :#{finish_id}].include?(button_id)
|
|
375
|
+
action_method_name = "_on_" + params[:action].to_s + "_form_" + button_id.to_s
|
|
376
|
+
callback_performs_action?(action_method_name)
|
|
377
|
+
unless ((btn_obj = self.wizard_config.buttons[button_id]) == nil || btn_obj.user_defined?)
|
|
378
|
+
method_name = "_on_wizard_" + button_id.to_s
|
|
379
|
+
if (self.method(method_name))
|
|
380
|
+
self.__send__(method_name)
|
|
381
|
+
else
|
|
382
|
+
raise MissingCallbackError, "Callback method either '" + action_method_name + "' or '" + method_name + "' not defined", caller
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
button_id
|
|
388
|
+
end
|
|
389
|
+
hide_action :check_action_for_button
|
|
390
|
+
|
|
391
|
+
@wizard_callbacks ||= []
|
|
392
|
+
def self.wizard_callbacks; @wizard_callbacks; end
|
|
393
|
+
|
|
394
|
+
def callback_performs_action?(methId)
|
|
395
|
+
cache = self.class.wizard_callbacks
|
|
396
|
+
return false if cache.include?(methId)
|
|
397
|
+
|
|
398
|
+
begin
|
|
399
|
+
self.send(methId)
|
|
400
|
+
rescue NoMethodError
|
|
401
|
+
cache << methId
|
|
402
|
+
return false
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
self.performed?
|
|
406
|
+
end
|
|
407
|
+
hide_action :callback_performs_action?
|
|
408
|
+
|
|
409
|
+
HELPERS
|
|
410
|
+
mb.string
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
end
|