hat-trick 0.1.2 → 0.1.3
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/.gitignore +1 -0
 - data/Changelog +17 -3
 - data/README.md +44 -19
 - data/app/assets/javascripts/hat-trick.js.coffee +214 -123
 - data/lib/hat-trick.rb +0 -2
 - data/lib/hat_trick/config.rb +10 -11
 - data/lib/hat_trick/controller_helpers.rb +18 -4
 - data/lib/hat_trick/controller_hooks.rb +37 -23
 - data/lib/hat_trick/dsl.rb +144 -50
 - data/lib/hat_trick/engine.rb +6 -0
 - data/lib/hat_trick/form_helper.rb +1 -1
 - data/lib/hat_trick/model_methods.rb +14 -3
 - data/lib/hat_trick/step.rb +24 -11
 - data/lib/hat_trick/step_definition.rb +162 -36
 - data/lib/hat_trick/version.rb +1 -1
 - data/lib/hat_trick/wizard.rb +105 -46
 - data/lib/hat_trick/wizard_definition.rb +18 -9
 - data/lib/hat_trick/wizard_steps.rb +12 -3
 - data/spec/lib/hat_trick/dsl_spec.rb +11 -10
 - data/spec/lib/hat_trick/step_definition_spec.rb +106 -0
 - data/spec/lib/hat_trick/wizard_definition_spec.rb +18 -9
 - data/spec/lib/hat_trick/wizard_spec.rb +22 -17
 - data/spec/spec_helper.rb +6 -0
 - data/vendor/assets/javascripts/array.filter.js +22 -0
 - data/vendor/assets/javascripts/history.html4.js +658 -0
 - data/vendor/assets/javascripts/history.js +1991 -0
 - data/vendor/assets/javascripts/jquery.form.wizard.js +162 -145
 - data/vendor/assets/javascripts/jquery.history.js +77 -1
 - data/vendor/assets/javascripts/json.js +480 -0
 - metadata +10 -4
 
| 
         @@ -28,7 +28,7 @@ module HatTrick 
     | 
|
| 
       28 
28 
     | 
    
         
             
                end
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
                def model_class
         
     | 
| 
       31 
     | 
    
         
            -
                  return  
     | 
| 
      
 31 
     | 
    
         
            +
                  return hat_trick_wizard.model.class if hat_trick_wizard.model
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
       33 
33 
     | 
    
         
             
                  # if that didn't work, try to grab it from the params hash
         
     | 
| 
       34 
34 
     | 
    
         
             
                  model_name = params_model_name
         
     | 
| 
         @@ -46,10 +46,21 @@ module HatTrick 
     | 
|
| 
       46 
46 
     | 
    
         | 
| 
       47 
47 
     | 
    
         
             
                def setup_validation_group_for(wizard_step)
         
     | 
| 
       48 
48 
     | 
    
         
             
                  klass = model_class
         
     | 
| 
       49 
     | 
    
         
            -
                   
     | 
| 
      
 49 
     | 
    
         
            +
                  if klass.nil?
         
     | 
| 
      
 50 
     | 
    
         
            +
                    Rails.logger.warn "model class was nil when setting up validation group for #{wizard_step}"
         
     | 
| 
      
 51 
     | 
    
         
            +
                    return
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
       50 
53 
     | 
    
         
             
                  step_name = wizard_step.name
         
     | 
| 
       51 
54 
     | 
    
         
             
                  validation_groups = ::ActiveRecord::Base.validation_group_classes[klass] || []
         
     | 
| 
       52 
     | 
    
         
            -
                   
     | 
| 
      
 55 
     | 
    
         
            +
                  dynamic_group_exists = HatTrick::ModelMethods.dynamic_validation_groups.include?(step_name)
         
     | 
| 
      
 56 
     | 
    
         
            +
                  static_validation_group_exists = validation_groups.include?(step_name) && !dynamic_group_exists
         
     | 
| 
      
 57 
     | 
    
         
            +
                  dynamic_validation_group = false
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                  if static_validation_group_exists
         
     | 
| 
      
 60 
     | 
    
         
            +
                    Rails.logger.info "Not creating dynamic validation group for #{step_name} because a static one exists"
         
     | 
| 
      
 61 
     | 
    
         
            +
                  else
         
     | 
| 
      
 62 
     | 
    
         
            +
                    Rails.logger.info "Creating a dynamic validation group for #{step_name}"
         
     | 
| 
      
 63 
     | 
    
         
            +
                    dynamic_validation_group = true
         
     | 
| 
       53 
64 
     | 
    
         
             
                    validation_fields = params.keys # TODO: Try it without these (so only the model keys below)
         
     | 
| 
       54 
65 
     | 
    
         
             
                    model = model_key
         
     | 
| 
       55 
66 
     | 
    
         
             
                    if model
         
     | 
| 
         @@ -58,7 +69,10 @@ module HatTrick 
     | 
|
| 
       58 
69 
     | 
    
         
             
                    validation_fields = validation_fields.map(&:to_sym)
         
     | 
| 
       59 
70 
     | 
    
         
             
                    klass.validation_group(step_name, :fields => validation_fields)
         
     | 
| 
       60 
71 
     | 
    
         
             
                  end
         
     | 
| 
       61 
     | 
    
         
            -
                   
     | 
| 
      
 72 
     | 
    
         
            +
                  Rails.logger.info "Setting current validation group for model class #{model_class} to #{step_name}"
         
     | 
| 
      
 73 
     | 
    
         
            +
                  HatTrick::ModelMethods.set_current_validation_group_for(model_class,
         
     | 
| 
      
 74 
     | 
    
         
            +
                                                                          step_name,
         
     | 
| 
      
 75 
     | 
    
         
            +
                                                                          dynamic_validation_group)
         
     | 
| 
       62 
76 
     | 
    
         
             
                end
         
     | 
| 
       63 
77 
     | 
    
         
             
              end
         
     | 
| 
       64 
78 
     | 
    
         
             
            end
         
     | 
| 
         @@ -12,62 +12,76 @@ module HatTrick 
     | 
|
| 
       12 
12 
     | 
    
         | 
| 
       13 
13 
     | 
    
         
             
                def self.def_action_method_aliases(action_methods)
         
     | 
| 
       14 
14 
     | 
    
         
             
                  action_methods.each do |meth|
         
     | 
| 
       15 
     | 
    
         
            -
                     
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
                       
     | 
| 
       18 
     | 
    
         
            -
                         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
      
 15 
     | 
    
         
            +
                    unless respond_to?(:"#{meth}_with_hat_trick")
         
     | 
| 
      
 16 
     | 
    
         
            +
                      Rails.logger.info "Defining #{meth}_with_hat_trick"
         
     | 
| 
      
 17 
     | 
    
         
            +
                      module_eval <<-RUBY_EVAL
         
     | 
| 
      
 18 
     | 
    
         
            +
                        def #{meth}_with_hat_trick(*args)
         
     | 
| 
      
 19 
     | 
    
         
            +
                          Rails.logger.info "#{meth}_with_hat_trick called"
         
     | 
| 
      
 20 
     | 
    
         
            +
                          if respond_to?("#{meth}_hook", :include_private)
         
     | 
| 
      
 21 
     | 
    
         
            +
                            #{meth}_hook(*args)
         
     | 
| 
      
 22 
     | 
    
         
            +
                          end
         
     | 
| 
      
 23 
     | 
    
         
            +
                          common_hook(*args) if respond_to?(:common_hook, :include_private)
         
     | 
| 
      
 24 
     | 
    
         
            +
                          #{meth}_without_hat_trick(*args)
         
     | 
| 
      
 25 
     | 
    
         
            +
                        end
         
     | 
| 
      
 26 
     | 
    
         
            +
                        private "#{meth}_with_hat_trick"
         
     | 
| 
      
 27 
     | 
    
         
            +
                      RUBY_EVAL
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
       25 
29 
     | 
    
         
             
                  end
         
     | 
| 
       26 
30 
     | 
    
         
             
                  true
         
     | 
| 
       27 
31 
     | 
    
         
             
                end
         
     | 
| 
       28 
32 
     | 
    
         | 
| 
       29 
33 
     | 
    
         
             
                private
         
     | 
| 
       30 
34 
     | 
    
         | 
| 
      
 35 
     | 
    
         
            +
                def common_hook(*args)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  Rails.logger.info "common_hook wizard instance: #{hat_trick_wizard.object_id}"
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
       31 
39 
     | 
    
         
             
                def create_hook(*args)
         
     | 
| 
       32 
     | 
    
         
            -
                  setup_validation_group_for( 
     | 
| 
      
 40 
     | 
    
         
            +
                  setup_validation_group_for(hat_trick_wizard.current_step)
         
     | 
| 
       33 
41 
     | 
    
         
             
                end
         
     | 
| 
       34 
42 
     | 
    
         | 
| 
       35 
43 
     | 
    
         
             
                def update_hook(*args)
         
     | 
| 
       36 
     | 
    
         
            -
                  setup_validation_group_for( 
     | 
| 
      
 44 
     | 
    
         
            +
                  setup_validation_group_for(hat_trick_wizard.current_step)
         
     | 
| 
       37 
45 
     | 
    
         
             
                end
         
     | 
| 
       38 
46 
     | 
    
         | 
| 
       39 
47 
     | 
    
         
             
                def render_with_hat_trick(*args, &block)
         
     | 
| 
       40 
48 
     | 
    
         
             
                  rendered = args.first
         
     | 
| 
       41 
49 
     | 
    
         
             
                  if rendered && rendered.has_key?(:json)
         
     | 
| 
       42 
     | 
    
         
            -
                    model = rendered[:json]
         
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
      
 50 
     | 
    
         
            +
                    hat_trick_wizard.model = rendered[:json]
         
     | 
| 
      
 51 
     | 
    
         
            +
                  else
         
     | 
| 
      
 52 
     | 
    
         
            +
                    Rails.logger.warn "No model found in render args #{args.inspect}; model is #{hat_trick_wizard.model.inspect}"
         
     | 
| 
       44 
53 
     | 
    
         
             
                  end
         
     | 
| 
       45 
54 
     | 
    
         | 
| 
       46 
55 
     | 
    
         
             
                  if params.has_key?('_ht_meta')
         
     | 
| 
       47 
     | 
    
         
            -
                    next_step = params[' 
     | 
| 
       48 
     | 
    
         
            -
                     
     | 
| 
      
 56 
     | 
    
         
            +
                    next_step = params['_ht_step_link']
         
     | 
| 
      
 57 
     | 
    
         
            +
                    hat_trick_wizard.advance_step(next_step)
         
     | 
| 
       49 
58 
     | 
    
         
             
                  end
         
     | 
| 
       50 
59 
     | 
    
         | 
| 
       51 
60 
     | 
    
         
             
                  wizard_metadata = {
         
     | 
| 
       52 
     | 
    
         
            -
                    : 
     | 
| 
       53 
     | 
    
         
            -
                    : 
     | 
| 
       54 
     | 
    
         
            -
                    : 
     | 
| 
      
 61 
     | 
    
         
            +
                    :externalRedirectURL => hat_trick_wizard.external_redirect_url,
         
     | 
| 
      
 62 
     | 
    
         
            +
                    :url => hat_trick_wizard.current_form_url,
         
     | 
| 
      
 63 
     | 
    
         
            +
                    :method => hat_trick_wizard.current_form_method,
         
     | 
| 
      
 64 
     | 
    
         
            +
                    :currentStep => hat_trick_wizard.current_step,
         
     | 
| 
      
 65 
     | 
    
         
            +
                    :percentComplete => hat_trick_wizard.percent_complete,
         
     | 
| 
       55 
66 
     | 
    
         
             
                  }
         
     | 
| 
       56 
67 
     | 
    
         | 
| 
       57 
     | 
    
         
            -
                  include_data =  
     | 
| 
      
 68 
     | 
    
         
            +
                  include_data = hat_trick_wizard.include_data
         
     | 
| 
       58 
69 
     | 
    
         | 
| 
       59 
70 
     | 
    
         
             
                  # this sets the gon data (JS hatTrick object) for the initial page load
         
     | 
| 
       60 
71 
     | 
    
         
             
                  gon.metadata = wizard_metadata
         
     | 
| 
       61 
72 
     | 
    
         
             
                  gon.data = include_data
         
     | 
| 
       62 
     | 
    
         
            -
                  gon.model =  
     | 
| 
      
 73 
     | 
    
         
            +
                  gon.model = hat_trick_wizard.model
         
     | 
| 
       63 
74 
     | 
    
         | 
| 
       64 
75 
     | 
    
         
             
                  # this sets the wizard metadata for subsequent AJAX requests
         
     | 
| 
       65 
     | 
    
         
            -
                  if  
     | 
| 
       66 
     | 
    
         
            -
                    args[0][:json] = { :model =>  
     | 
| 
      
 76 
     | 
    
         
            +
                  if hat_trick_wizard.model && rendered.has_key?(:json)
         
     | 
| 
      
 77 
     | 
    
         
            +
                    args[0][:json] = { :model => hat_trick_wizard.model,
         
     | 
| 
       67 
78 
     | 
    
         
             
                                       :metadata => wizard_metadata }
         
     | 
| 
       68 
79 
     | 
    
         
             
                    args[0][:json].merge!( :data => include_data )
         
     | 
| 
       69 
80 
     | 
    
         
             
                  end
         
     | 
| 
       70 
81 
     | 
    
         | 
| 
      
 82 
     | 
    
         
            +
                  # unset redirects for subsequent steps
         
     | 
| 
      
 83 
     | 
    
         
            +
                  hat_trick_wizard.external_redirect_url = nil
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
       71 
85 
     | 
    
         
             
                  render_without_hat_trick(*args, &block)
         
     | 
| 
       72 
86 
     | 
    
         
             
                end
         
     | 
| 
       73 
87 
     | 
    
         
             
              end
         
     | 
    
        data/lib/hat_trick/dsl.rb
    CHANGED
    
    | 
         @@ -6,37 +6,66 @@ module HatTrick 
     | 
|
| 
       6 
6 
     | 
    
         
             
              module DSL
         
     | 
| 
       7 
7 
     | 
    
         
             
                extend ActiveSupport::Concern
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
                attr_accessor : 
     | 
| 
      
 9 
     | 
    
         
            +
                attr_accessor :hat_trick_wizard
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
                delegate :model, :previously_visited_step, :to => : 
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
                included do
         
     | 
| 
       14 
     | 
    
         
            -
                  alias_method_chain :initialize, :hat_trick
         
     | 
| 
       15 
     | 
    
         
            -
                end
         
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
                def initialize_with_hat_trick(*args)
         
     | 
| 
       18 
     | 
    
         
            -
                  @_ht_config = HatTrick::Config.new(self.class.wizard_def)
         
     | 
| 
       19 
     | 
    
         
            -
                  if configure_callback.is_a?(Proc)
         
     | 
| 
       20 
     | 
    
         
            -
                    ht_wizard.controller.instance_exec(@_ht_config, &configure_callback)
         
     | 
| 
       21 
     | 
    
         
            -
                  end
         
     | 
| 
       22 
     | 
    
         
            -
                  initialize_without_hat_trick(*args)
         
     | 
| 
       23 
     | 
    
         
            -
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
                delegate :model, :previously_visited_step, :to => :hat_trick_wizard
         
     | 
| 
       24 
12 
     | 
    
         | 
| 
       25 
13 
     | 
    
         
             
                def next_step(name=nil)
         
     | 
| 
       26 
14 
     | 
    
         
             
                  if name.nil?
         
     | 
| 
       27 
15 
     | 
    
         
             
                    # getter
         
     | 
| 
       28 
     | 
    
         
            -
                     
     | 
| 
      
 16 
     | 
    
         
            +
                    hat_trick_wizard.next_step
         
     | 
| 
       29 
17 
     | 
    
         
             
                  else
         
     | 
| 
       30 
18 
     | 
    
         
             
                    # setter
         
     | 
| 
       31 
     | 
    
         
            -
                    step =  
     | 
| 
      
 19 
     | 
    
         
            +
                    step = hat_trick_wizard.find_step(name)
         
     | 
| 
       32 
20 
     | 
    
         
             
                    # explicitly set steps should not be skipped
         
     | 
| 
       33 
21 
     | 
    
         
             
                    step.skipped = false
         
     | 
| 
       34 
     | 
    
         
            -
                     
     | 
| 
      
 22 
     | 
    
         
            +
                    hat_trick_wizard.current_step.next_step = step
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                def previously_visited_step_name
         
     | 
| 
      
 27 
     | 
    
         
            +
                  if previously_visited_step.nil?
         
     | 
| 
      
 28 
     | 
    
         
            +
                    ''
         
     | 
| 
      
 29 
     | 
    
         
            +
                  else
         
     | 
| 
      
 30 
     | 
    
         
            +
                    previously_visited_step.name
         
     | 
| 
       35 
31 
     | 
    
         
             
                  end
         
     | 
| 
       36 
32 
     | 
    
         
             
                end
         
     | 
| 
       37 
33 
     | 
    
         | 
| 
       38 
34 
     | 
    
         
             
                def skip_this_step
         
     | 
| 
       39 
     | 
    
         
            -
                   
     | 
| 
      
 35 
     | 
    
         
            +
                  hat_trick_wizard.skip_step(hat_trick_wizard.current_step)
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                def button_to(step_name, options={})
         
     | 
| 
      
 39 
     | 
    
         
            +
                  button = self.class.send(:create_button_to, step_name, options)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  hat_trick_wizard.current_step.add_button button
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                def remaining_step_count
         
     | 
| 
      
 44 
     | 
    
         
            +
                  hat_trick_wizard.steps_after_current
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                def adjust_remaining_step_count_by(diff)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  hat_trick_wizard.steps_remaining += diff
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                def change_remaining_step_count_to(count)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  hat_trick_wizard.steps_remaining = count
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                def total_step_count
         
     | 
| 
      
 56 
     | 
    
         
            +
                  hat_trick_wizard.total_step_count
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                def reset_step_count
         
     | 
| 
      
 60 
     | 
    
         
            +
                  hat_trick_wizard.override_step_count = nil
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                def redirect_to_step(step_name)
         
     | 
| 
      
 64 
     | 
    
         
            +
                  hat_trick_wizard.redirect_to_step step_name
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                def redirect_to_external_url(url)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  hat_trick_wizard.external_redirect_url = url
         
     | 
| 
       40 
69 
     | 
    
         
             
                end
         
     | 
| 
       41 
70 
     | 
    
         | 
| 
       42 
71 
     | 
    
         
             
                module ClassMethods
         
     | 
| 
         @@ -47,7 +76,10 @@ module HatTrick 
     | 
|
| 
       47 
76 
     | 
    
         
             
                      include HatTrick::DSL::ControllerInstanceMethods
         
     | 
| 
       48 
77 
     | 
    
         
             
                      include HatTrick::ControllerHooks
         
     | 
| 
       49 
78 
     | 
    
         | 
| 
       50 
     | 
    
         
            -
                       
     | 
| 
      
 79 
     | 
    
         
            +
                      ::ActiveRecord::Base.send(:include, HatTrick::ModelMethods)
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                      config = HatTrick::Config.new
         
     | 
| 
      
 82 
     | 
    
         
            +
                      @wizard_def = HatTrick::WizardDefinition.new(config)
         
     | 
| 
       51 
83 
     | 
    
         | 
| 
       52 
84 
     | 
    
         
             
                      yield
         
     | 
| 
       53 
85 
     | 
    
         | 
| 
         @@ -58,7 +90,15 @@ module HatTrick 
     | 
|
| 
       58 
90 
     | 
    
         | 
| 
       59 
91 
     | 
    
         
             
                  def configure(&block)
         
     | 
| 
       60 
92 
     | 
    
         
             
                    raise "Must pass a block to configure" unless block_given?
         
     | 
| 
       61 
     | 
    
         
            -
                     
     | 
| 
      
 93 
     | 
    
         
            +
                    self.configure_callback = block
         
     | 
| 
      
 94 
     | 
    
         
            +
                  end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  def button_label(type, label)
         
     | 
| 
      
 97 
     | 
    
         
            +
                    wizard_def.config.send("#{type}_button_label=", label)
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  def button_label_i18n_key(type, i18n_key)
         
     | 
| 
      
 101 
     | 
    
         
            +
                    wizard_def.config.send("#{type}_button_label_i18n_key=", i18n_key)
         
     | 
| 
       62 
102 
     | 
    
         
             
                  end
         
     | 
| 
       63 
103 
     | 
    
         | 
| 
       64 
104 
     | 
    
         
             
                  def step(name, args={}, &block)
         
     | 
| 
         @@ -67,19 +107,6 @@ module HatTrick 
     | 
|
| 
       67 
107 
     | 
    
         
             
                    instance_eval &block if block_given?
         
     | 
| 
       68 
108 
     | 
    
         
             
                  end
         
     | 
| 
       69 
109 
     | 
    
         | 
| 
       70 
     | 
    
         
            -
                  def repeat_step(name)
         
     | 
| 
       71 
     | 
    
         
            -
                    raise "repeat_step must be called from within a wizard block" unless wizard_def
         
     | 
| 
       72 
     | 
    
         
            -
                    repeated_step = wizard_def.find_step(name)
         
     | 
| 
       73 
     | 
    
         
            -
                    raise ArgumentError, "Couldn't find step named #{name}" unless repeated_step
         
     | 
| 
       74 
     | 
    
         
            -
                    new_step = repeated_step.dup
         
     | 
| 
       75 
     | 
    
         
            -
                    # use the repeated step's fieldset id
         
     | 
| 
       76 
     | 
    
         
            -
                    new_step.fieldset = repeated_step.fieldset
         
     | 
| 
       77 
     | 
    
         
            -
                    # but use the current step's name
         
     | 
| 
       78 
     | 
    
         
            -
                    new_step.name = wizard_def.last_step.name
         
     | 
| 
       79 
     | 
    
         
            -
                    # replace the step we're in the middle of defining w/ new_step
         
     | 
| 
       80 
     | 
    
         
            -
                    wizard_def.replace_step(wizard_def.last_step, new_step)
         
     | 
| 
       81 
     | 
    
         
            -
                  end
         
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
110 
     | 
    
         
             
                  def skip_this_step
         
     | 
| 
       84 
111 
     | 
    
         
             
                    # skip_this_step in wizard definition (class) context means the step
         
     | 
| 
       85 
112 
     | 
    
         
             
                    # can be explicitly jumped to, but won't be visited in the normal flow
         
     | 
| 
         @@ -87,27 +114,38 @@ module HatTrick 
     | 
|
| 
       87 
114 
     | 
    
         
             
                    wizard_def.last_step.skipped = true
         
     | 
| 
       88 
115 
     | 
    
         
             
                  end
         
     | 
| 
       89 
116 
     | 
    
         | 
| 
       90 
     | 
    
         
            -
                  def  
     | 
| 
       91 
     | 
    
         
            -
                    raise " 
     | 
| 
       92 
     | 
    
         
            -
                     
     | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
      
 117 
     | 
    
         
            +
                  def last_step
         
     | 
| 
      
 118 
     | 
    
         
            +
                    raise "skip_this_step must be called from within a wizard block" unless wizard_def
         
     | 
| 
      
 119 
     | 
    
         
            +
                    wizard_def.last_step.last = true
         
     | 
| 
      
 120 
     | 
    
         
            +
                  end
         
     | 
| 
       94 
121 
     | 
    
         | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
      
 122 
     | 
    
         
            +
                  def button_to(step_name, options={})
         
     | 
| 
      
 123 
     | 
    
         
            +
                    raise "button_to must be called from within a wizard block" unless wizard_def
         
     | 
| 
      
 124 
     | 
    
         
            +
                    wizard_def.last_step.add_button create_button_to(step_name, options)
         
     | 
| 
      
 125 
     | 
    
         
            +
                  end
         
     | 
| 
       96 
126 
     | 
    
         | 
| 
      
 127 
     | 
    
         
            +
                  def hide_button(button_type)
         
     | 
| 
      
 128 
     | 
    
         
            +
                    raise "before must be called from within a wizard block" unless wizard_def
         
     | 
| 
       97 
129 
     | 
    
         
             
                    step = wizard_def.last_step
         
     | 
| 
       98 
     | 
    
         
            -
                     
     | 
| 
       99 
     | 
    
         
            -
                    button[:id] = id unless id.nil?
         
     | 
| 
       100 
     | 
    
         
            -
                    step.buttons = step.buttons.merge(name => button)
         
     | 
| 
      
 130 
     | 
    
         
            +
                    step.delete_button button_type
         
     | 
| 
       101 
131 
     | 
    
         
             
                  end
         
     | 
| 
       102 
132 
     | 
    
         | 
| 
       103 
     | 
    
         
            -
                  def before(&block)
         
     | 
| 
      
 133 
     | 
    
         
            +
                  def before(scope=:current_step, &block)
         
     | 
| 
       104 
134 
     | 
    
         
             
                    raise "before must be called from within a wizard block" unless wizard_def
         
     | 
| 
       105 
     | 
    
         
            -
                     
     | 
| 
      
 135 
     | 
    
         
            +
                    if scope == :each
         
     | 
| 
      
 136 
     | 
    
         
            +
                      wizard_def.before_callback_for_all_steps = block
         
     | 
| 
      
 137 
     | 
    
         
            +
                    else
         
     | 
| 
      
 138 
     | 
    
         
            +
                      wizard_def.last_step.before_callback = block
         
     | 
| 
      
 139 
     | 
    
         
            +
                    end
         
     | 
| 
       106 
140 
     | 
    
         
             
                  end
         
     | 
| 
       107 
141 
     | 
    
         | 
| 
       108 
     | 
    
         
            -
                  def after(&block)
         
     | 
| 
      
 142 
     | 
    
         
            +
                  def after(scope=:current_step, &block)
         
     | 
| 
       109 
143 
     | 
    
         
             
                    raise "after must be called from within a wizard block" unless wizard_def
         
     | 
| 
       110 
     | 
    
         
            -
                     
     | 
| 
      
 144 
     | 
    
         
            +
                    if scope == :each
         
     | 
| 
      
 145 
     | 
    
         
            +
                      wizard_def.after_callback_for_all_steps = block
         
     | 
| 
      
 146 
     | 
    
         
            +
                    else
         
     | 
| 
      
 147 
     | 
    
         
            +
                      wizard_def.last_step.after_callback = block
         
     | 
| 
      
 148 
     | 
    
         
            +
                    end
         
     | 
| 
       111 
149 
     | 
    
         
             
                  end
         
     | 
| 
       112 
150 
     | 
    
         | 
| 
       113 
151 
     | 
    
         
             
                  def include_data(key, &block)
         
     | 
| 
         @@ -117,10 +155,39 @@ module HatTrick 
     | 
|
| 
       117 
155 
     | 
    
         | 
| 
       118 
156 
     | 
    
         
             
                  def set_contents(&block)
         
     | 
| 
       119 
157 
     | 
    
         
             
                    raise "set_contents must be called from within a wizard block" unless wizard_def
         
     | 
| 
       120 
     | 
    
         
            -
                     
     | 
| 
       121 
     | 
    
         
            -
             
     | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
      
 158 
     | 
    
         
            +
                    wizard_def.last_step.step_contents_callback = block
         
     | 
| 
      
 159 
     | 
    
         
            +
                  end
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
                  private
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                  def configure_callback
         
     | 
| 
      
 164 
     | 
    
         
            +
                    @configure_callback
         
     | 
| 
      
 165 
     | 
    
         
            +
                  end
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                  def configure_callback=(block)
         
     | 
| 
      
 168 
     | 
    
         
            +
                    @configure_callback = block
         
     | 
| 
      
 169 
     | 
    
         
            +
                  end
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
                  def create_button_to(to_step_name, options={})
         
     | 
| 
      
 172 
     | 
    
         
            +
                    label = options[:label]
         
     | 
| 
      
 173 
     | 
    
         
            +
                    label ||= to_step_name.to_s.humanize
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
                    name = options[:name]
         
     | 
| 
      
 176 
     | 
    
         
            +
                    name ||= to_step_name.to_s.parameterize
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                    value = options[:value]
         
     | 
| 
      
 179 
     | 
    
         
            +
                    value ||= to_step_name.to_s.parameterize
         
     | 
| 
      
 180 
     | 
    
         
            +
             
     | 
| 
      
 181 
     | 
    
         
            +
                    if options
         
     | 
| 
      
 182 
     | 
    
         
            +
                      id = options[:id]
         
     | 
| 
      
 183 
     | 
    
         
            +
                      css_class = options[:class]
         
     | 
| 
       123 
184 
     | 
    
         
             
                    end
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
                    button = { :name => name, :value => value, :label => label }
         
     | 
| 
      
 187 
     | 
    
         
            +
                    button[:id] = id unless id.nil?
         
     | 
| 
      
 188 
     | 
    
         
            +
                    button[:class] = css_class unless css_class.nil?
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
                    { to_step_name => button }
         
     | 
| 
       124 
191 
     | 
    
         
             
                  end
         
     | 
| 
       125 
192 
     | 
    
         
             
                end
         
     | 
| 
       126 
193 
     | 
    
         | 
| 
         @@ -131,15 +198,42 @@ module HatTrick 
     | 
|
| 
       131 
198 
     | 
    
         
             
                    before_filter :setup_wizard
         
     | 
| 
       132 
199 
     | 
    
         
             
                  end
         
     | 
| 
       133 
200 
     | 
    
         | 
| 
      
 201 
     | 
    
         
            +
                  def back_to_start
         
     | 
| 
      
 202 
     | 
    
         
            +
                    respond_to do |format|
         
     | 
| 
      
 203 
     | 
    
         
            +
                      format.json { }
         
     | 
| 
      
 204 
     | 
    
         
            +
                    end
         
     | 
| 
      
 205 
     | 
    
         
            +
                  end
         
     | 
| 
      
 206 
     | 
    
         
            +
             
     | 
| 
       134 
207 
     | 
    
         
             
                  private
         
     | 
| 
       135 
208 
     | 
    
         | 
| 
       136 
209 
     | 
    
         
             
                  def setup_wizard
         
     | 
| 
       137 
210 
     | 
    
         
             
                    wizard_def = self.class.instance_variable_get("@wizard_def")
         
     | 
| 
       138 
     | 
    
         
            -
                    @ 
     | 
| 
      
 211 
     | 
    
         
            +
                    @hat_trick_wizard ||= wizard_def.make_wizard_for(self)
         
     | 
| 
      
 212 
     | 
    
         
            +
             
     | 
| 
      
 213 
     | 
    
         
            +
                    Rails.logger.info "setup_wizard wizard instance: #{@hat_trick_wizard.object_id}"
         
     | 
| 
      
 214 
     | 
    
         
            +
             
     | 
| 
      
 215 
     | 
    
         
            +
                    config_callback = self.class.send(:configure_callback)
         
     | 
| 
      
 216 
     | 
    
         
            +
                    if config_callback.is_a?(Proc)
         
     | 
| 
      
 217 
     | 
    
         
            +
                      instance_exec(wizard_def.config, &config_callback)
         
     | 
| 
      
 218 
     | 
    
         
            +
                    end
         
     | 
| 
       139 
219 
     | 
    
         | 
| 
       140 
220 
     | 
    
         
             
                    if params.has_key?('_ht_meta')
         
     | 
| 
       141 
221 
     | 
    
         
             
                      step_name = params['_ht_meta']['step']
         
     | 
| 
       142 
     | 
    
         
            -
             
     | 
| 
      
 222 
     | 
    
         
            +
                    end
         
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
      
 224 
     | 
    
         
            +
                    # TODO: Setup the route that enables this in hat-trick automatically.
         
     | 
| 
      
 225 
     | 
    
         
            +
                    #       Currently done manually in the app.
         
     | 
| 
      
 226 
     | 
    
         
            +
                    if params.has_key?('step')
         
     | 
| 
      
 227 
     | 
    
         
            +
                      step_name = params['step']
         
     | 
| 
      
 228 
     | 
    
         
            +
                    end
         
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
      
 230 
     | 
    
         
            +
                    if step_name.present?
         
     | 
| 
      
 231 
     | 
    
         
            +
                      Rails.logger.info "Setting current step to: #{step_name}"
         
     | 
| 
      
 232 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 233 
     | 
    
         
            +
                        @hat_trick_wizard.current_step = step_name
         
     | 
| 
      
 234 
     | 
    
         
            +
                      rescue StepNotFound => e
         
     | 
| 
      
 235 
     | 
    
         
            +
                        raise ActionController::RoutingError, e.message
         
     | 
| 
      
 236 
     | 
    
         
            +
                      end
         
     | 
| 
       143 
237 
     | 
    
         
             
                    end
         
     | 
| 
       144 
238 
     | 
    
         
             
                  end
         
     | 
| 
       145 
239 
     | 
    
         
             
                end
         
     | 
    
        data/lib/hat_trick/engine.rb
    CHANGED
    
    | 
         @@ -4,6 +4,12 @@ module HatTrick 
     | 
|
| 
       4 
4 
     | 
    
         
             
              class Engine < ::Rails::Engine
         
     | 
| 
       5 
5 
     | 
    
         
             
                # just defining this causes Rails to look for assets inside this gem
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
      
 7 
     | 
    
         
            +
                initializer 'hat-trick.dsl' do
         
     | 
| 
      
 8 
     | 
    
         
            +
                  ActiveSupport.on_load(:action_controller) do
         
     | 
| 
      
 9 
     | 
    
         
            +
                    include HatTrick::DSL
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
       7 
13 
     | 
    
         
             
                initializer 'hat-trick.form_helpers' do
         
     | 
| 
       8 
14 
     | 
    
         
             
                  ActiveSupport.on_load(:action_view) do
         
     | 
| 
       9 
15 
     | 
    
         
             
                    include HatTrick::FormHelper
         
     | 
| 
         @@ -2,6 +2,7 @@ module HatTrick 
     | 
|
| 
       2 
2 
     | 
    
         
             
              module ModelMethods
         
     | 
| 
       3 
3 
     | 
    
         
             
                extend ActiveSupport::Concern
         
     | 
| 
       4 
4 
     | 
    
         
             
                mattr_accessor :validation_groups
         
     | 
| 
      
 5 
     | 
    
         
            +
                mattr_accessor :dynamic_validation_groups
         
     | 
| 
       5 
6 
     | 
    
         | 
| 
       6 
7 
     | 
    
         
             
                attr_accessor :_dummy # so the dummy field will have something to set
         
     | 
| 
       7 
8 
     | 
    
         | 
| 
         @@ -10,9 +11,14 @@ module HatTrick 
     | 
|
| 
       10 
11 
     | 
    
         
             
                  alias_method_chain :as_json, :model_name if instance_methods.include?(:as_json)
         
     | 
| 
       11 
12 
     | 
    
         
             
                end
         
     | 
| 
       12 
13 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
                def self. 
     | 
| 
      
 14 
     | 
    
         
            +
                def self.dynamic_validation_groups
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @dynamic_validation_groups ||= []
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                def self.set_current_validation_group_for(klass, validation_group_name, dynamic)
         
     | 
| 
       14 
19 
     | 
    
         
             
                  self.validation_groups ||= {}
         
     | 
| 
       15 
20 
     | 
    
         
             
                  validation_groups[klass.to_s.underscore] = validation_group_name
         
     | 
| 
      
 21 
     | 
    
         
            +
                  dynamic_validation_groups << validation_group_name if dynamic
         
     | 
| 
       16 
22 
     | 
    
         
             
                end
         
     | 
| 
       17 
23 
     | 
    
         | 
| 
       18 
24 
     | 
    
         
             
                def self.current_validation_group_for(klass)
         
     | 
| 
         @@ -33,14 +39,19 @@ module HatTrick 
     | 
|
| 
       33 
39 
     | 
    
         
             
                private
         
     | 
| 
       34 
40 
     | 
    
         | 
| 
       35 
41 
     | 
    
         
             
                # don't call this method 'current_validation_group', it conflicts with
         
     | 
| 
       36 
     | 
    
         
            -
                # the gem
         
     | 
| 
      
 42 
     | 
    
         
            +
                # the validation_group gem
         
     | 
| 
       37 
43 
     | 
    
         
             
                def current_step_validation_group
         
     | 
| 
       38 
44 
     | 
    
         
             
                  HatTrick::ModelMethods.current_validation_group_for(self.class)
         
     | 
| 
       39 
45 
     | 
    
         
             
                end
         
     | 
| 
       40 
46 
     | 
    
         | 
| 
       41 
47 
     | 
    
         
             
                def enable_current_validation_group
         
     | 
| 
       42 
48 
     | 
    
         
             
                  validation_group = current_step_validation_group
         
     | 
| 
       43 
     | 
    
         
            -
                   
     | 
| 
      
 49 
     | 
    
         
            +
                  if validation_group
         
     | 
| 
      
 50 
     | 
    
         
            +
                    Rails.logger.info "Enabling validation group #{validation_group}"
         
     | 
| 
      
 51 
     | 
    
         
            +
                    enable_validation_group validation_group
         
     | 
| 
      
 52 
     | 
    
         
            +
                  else
         
     | 
| 
      
 53 
     | 
    
         
            +
                    Rails.logger.info "NOT enabling a validation group"
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
       44 
55 
     | 
    
         
             
                end
         
     | 
| 
       45 
56 
     | 
    
         
             
              end
         
     | 
| 
       46 
57 
     | 
    
         
             
            end
         
     | 
    
        data/lib/hat_trick/step.rb
    CHANGED
    
    | 
         @@ -3,12 +3,16 @@ require 'hat_trick/step_definition' 
     | 
|
| 
       3 
3 
     | 
    
         
             
            module HatTrick
         
     | 
| 
       4 
4 
     | 
    
         
             
              class Step
         
     | 
| 
       5 
5 
     | 
    
         
             
                attr_reader :step_def, :wizard
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_accessor :next_step, :redirect_from
         
     | 
| 
       6 
7 
     | 
    
         
             
                attr_writer :skipped
         
     | 
| 
       7 
     | 
    
         
            -
                attr_accessor :next_step
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
                delegate :name, :fieldset, : 
     | 
| 
       10 
     | 
    
         
            -
                         :run_after_callback, :run_before_callback, : 
     | 
| 
       11 
     | 
    
         
            -
                         :run_include_data_callback, : 
     | 
| 
      
 9 
     | 
    
         
            +
                delegate :name, :fieldset, :add_button, :buttons, :to_sym, :to_s,
         
     | 
| 
      
 10 
     | 
    
         
            +
                         :run_after_callback, :run_before_callback, :include_data,
         
     | 
| 
      
 11 
     | 
    
         
            +
                         :run_include_data_callback, :run_step_contents_callback,
         
     | 
| 
      
 12 
     | 
    
         
            +
                         :include_data_key, :config, :step_contents, :last?, :first?,
         
     | 
| 
      
 13 
     | 
    
         
            +
                         :to => :step_def
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                delegate :visited_steps, :skipped_steps, :to => :wizard
         
     | 
| 
       12 
16 
     | 
    
         | 
| 
       13 
17 
     | 
    
         
             
                def initialize(step_def, wizard)
         
     | 
| 
       14 
18 
     | 
    
         
             
                  @step_def = step_def
         
     | 
| 
         @@ -16,20 +20,29 @@ module HatTrick 
     | 
|
| 
       16 
20 
     | 
    
         
             
                  @skipped = step_def.skipped?
         
     | 
| 
       17 
21 
     | 
    
         
             
                end
         
     | 
| 
       18 
22 
     | 
    
         | 
| 
       19 
     | 
    
         
            -
                def  
     | 
| 
       20 
     | 
    
         
            -
                   
     | 
| 
      
 23 
     | 
    
         
            +
                def skipped?
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @skipped || (skipped_steps.include?(self.to_sym) && !visited?)
         
     | 
| 
       21 
25 
     | 
    
         
             
                end
         
     | 
| 
       22 
26 
     | 
    
         | 
| 
       23 
     | 
    
         
            -
                def  
     | 
| 
       24 
     | 
    
         
            -
                   
     | 
| 
      
 27 
     | 
    
         
            +
                def redirect?
         
     | 
| 
      
 28 
     | 
    
         
            +
                  redirect_from.present?
         
     | 
| 
       25 
29 
     | 
    
         
             
                end
         
     | 
| 
       26 
30 
     | 
    
         | 
| 
       27 
31 
     | 
    
         
             
                def visited?
         
     | 
| 
       28 
     | 
    
         
            -
                   
     | 
| 
      
 32 
     | 
    
         
            +
                  visited_steps.include? self.to_sym
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def mark_as_visited
         
     | 
| 
      
 36 
     | 
    
         
            +
                  visited_steps << self.to_sym
         
     | 
| 
       29 
37 
     | 
    
         
             
                end
         
     | 
| 
       30 
38 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
                def  
     | 
| 
       32 
     | 
    
         
            -
                   
     | 
| 
      
 39 
     | 
    
         
            +
                def as_json(options = nil)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  json = { :name => name, :fieldset => fieldset }
         
     | 
| 
      
 41 
     | 
    
         
            +
                  json[:buttons] = buttons.empty? ? [] : buttons
         
     | 
| 
      
 42 
     | 
    
         
            +
                  json[:first] = first?
         
     | 
| 
      
 43 
     | 
    
         
            +
                  json[:redirect] = redirect?
         
     | 
| 
      
 44 
     | 
    
         
            +
                  json[:redirectFrom] = redirect_from
         
     | 
| 
      
 45 
     | 
    
         
            +
                  json
         
     | 
| 
       33 
46 
     | 
    
         
             
                end
         
     | 
| 
       34 
47 
     | 
    
         
             
              end
         
     | 
| 
       35 
48 
     | 
    
         
             
            end
         
     |