hat-trick 0.0.1 → 0.1.0

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/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  ## Install
5
5
  gem install hat-trick
6
6
 
7
- ### Rails 3.2
7
+ ### Rails 3.1+
8
8
  (older versions not supported)
9
9
 
10
10
  Put this in your Gemfile:
@@ -37,8 +37,8 @@ Jumping to a step based on logged in status:
37
37
 
38
38
  wizard do
39
39
  step :first_step do
40
- # after_this_step defines a callback to run after the current step is completed by the user
41
- after_this_step do
40
+ # after defines a callback to run after the current step is completed by the user
41
+ after do
42
42
  # code in this block will be exec'd in the context of your controller
43
43
  if user_signed_in?
44
44
  next_step :third_step
@@ -64,8 +64,8 @@ Skipping a step under certain conditions:
64
64
  wizard do
65
65
  step :first_step
66
66
  step :second_step do
67
- # before_this_step defines a callback to run before the user sees this step
68
- before_this_step do
67
+ # before defines a callback to run before the user sees this step
68
+ before do
69
69
  # code in this block will be exec'd in the context of your controller
70
70
  skip_this_step unless foo.present?
71
71
  end
@@ -3,21 +3,58 @@
3
3
  class HatTrickWizard
4
4
  constructor: (formElem, @wizard) ->
5
5
  @form = $(formElem)
6
- fieldsets = @form.find("fieldset")
7
- fieldsets.addClass("step")
8
- wizard_buttons = '<input type="reset" /><input type="submit" />'
9
- fieldsets.find("div.buttons").html wizard_buttons
10
- window.htData = {}
11
- # prevent submitting the step that happens to be the last fieldset
12
- this.addFakeLastStep()
13
- this.enableFormwizard() # unless this.formwizardEnabled()
14
- this.setCurrentStepField()
15
- # TODO: Try this out instead of putting :start first
16
- # this.showStep(@wizard.currentStep)
17
- this.bindEvents()
6
+ this.stepShownCallback() # because we just showed the first step (or the one in the URL)
7
+
8
+ formwizardEnabled: false
9
+
10
+ linkClass: "_ht_link"
18
11
 
19
12
  buttons: {}
20
13
 
14
+ stepsNeedUpdate: false
15
+
16
+ stepShownCallback: ->
17
+ if not @formwizardEnabled
18
+ this.addStepClass()
19
+ # prevent submitting the step that happens to be the last fieldset
20
+ # TODO: Figure out a better way to do this
21
+ this.addFakeLastStep()
22
+ this.addDefaultButtons()
23
+ this.updateStepFromMetadata()
24
+ if not @formwizardEnabled
25
+ this.setupButtonsForAllSteps()
26
+ this.enableFormwizard() # this clobbers our button customizations for the current step
27
+ this.setupButtonsForCurrentStep() # so we run this to reconfigure it
28
+ this.bindEvents()
29
+ else
30
+ this.setupButtonsForCurrentStep()
31
+ # this must be run here & after setupButtonsForCurrentStep() to support setContents()
32
+ if @stepsNeedUpdate
33
+ this.updateSteps()
34
+ @stepsNeedUpdate = false
35
+ this.setCurrentStepField()
36
+ this.clearNextStepField()
37
+ this.setFormFields(hatTrick.model)
38
+ this.createDummyModelField() unless this.currentStepHasModelFields()
39
+
40
+ addStepClass: ->
41
+ @form.find("fieldset").addClass("step")
42
+
43
+ addDefaultButtons: ($scope = @form.find("fieldset")) ->
44
+ hatTrick = this
45
+ $scope.each (index) ->
46
+ id = $(this).attr('id')
47
+ buttons =
48
+ next:
49
+ id: "#{id}_next_button"
50
+ label: "Next"
51
+ if index > 0 or hatTrick.formwizardEnabled
52
+ buttons['back'] =
53
+ id: "#{id}_back_button"
54
+ label: "Back"
55
+
56
+ hatTrick.buttons[id] = buttons
57
+
21
58
  findStep: (stepId) ->
22
59
  @form.find("fieldset##{stepId}")
23
60
 
@@ -26,9 +63,10 @@ class HatTrickWizard
26
63
 
27
64
  setAction: (url, method) ->
28
65
  methodLower = method.toLowerCase()
29
- console.log "Setting form action to #{methodLower} #{url}"
66
+ # log "Setting form action to #{methodLower} #{url}"
30
67
  @form.attr("action", url)
31
68
  @form.attr("method", "post")
69
+ @form.formwizard("option", remoteAjax: this.ajaxEvents())
32
70
  methodField = @form.find('input[name="_method"]')
33
71
  methodField.remove()
34
72
  if methodLower isnt "post"
@@ -41,40 +79,50 @@ class HatTrickWizard
41
79
  stepId = this.currentStepId()
42
80
  this.findStep(stepId)
43
81
 
44
- nextStepFieldHTML: """<input type="hidden" name="_ht_next_step" class="_ht_link" value="" />"""
45
-
46
82
  fieldsets: ->
47
83
  @form.find("fieldset")
48
84
 
49
- ajaxEvents: (firstStep=false) ->
85
+ ajaxEvents: ->
50
86
  remoteAjax = {}
51
87
  $fieldsets = this.fieldsets()
52
- $fieldsets = $fieldsets.filter(":first") if firstStep
53
88
  $fieldsets.each (index, element) =>
54
89
  stepId = $(element).attr("id")
55
90
  remoteAjax[stepId] = this.createAjaxEvent(stepId)
56
91
  remoteAjax
57
92
 
58
93
  createAjaxEvent: (step) ->
59
- # console.log "Adding AJAX to step #{step}"
60
94
  ajax =
61
- url: @form.attr("action"),
62
- dataType: "json",
63
- beforeSubmit: (data) =>
64
- console.log "Sending these data to the server: #{$.param(data)}"
65
- success: (data) =>
66
- console.log "Successful form POST; got #{$.param(data)}"
67
- if data.wizardMetadata?
68
- this.setAction(data.wizardMetadata.url, data.wizardMetadata.method)
69
- # merge new data with window.htData
70
- $.extend(window.htData, data)
71
- error: (data) =>
72
- appErrors = eval "(#{data.responseText})"
73
- this.addErrorItem value[0] for key, value of appErrors.formModel
95
+ url: @form.attr("action")
96
+ dataType: "json"
97
+ # beforeSubmit: (data) =>
98
+ # log "Sending these data to the server: #{JSON.stringify data}"
99
+ success: (serverData) =>
100
+ this.handleServerData serverData
101
+ # log "Successful form POST; got #{JSON.stringify(serverData)}"
102
+ error: (event, status, errorThrown) =>
103
+ log "Error response: #{event.status} #{status} - #{errorThrown} - #{event.responseText}"
104
+ try
105
+ appErrors = eval "(#{event.responseText})"
106
+ catch err
107
+ appErrors =
108
+ model:
109
+ unknown: [
110
+ "There was an error communicating with the server. TurboVote staff have been notified."
111
+ ]
112
+ this.clearErrors()
113
+ this.addErrorItem value[0] for key, value of appErrors.model
74
114
  ajax
75
115
 
116
+ getErrorListElement: ->
117
+ this.currentStep().find("ul.hat_trick_errors")
118
+
119
+ clearErrors: ->
120
+ $errorList = this.getErrorListElement()
121
+ $errorList.hide()
122
+ $errorList.empty()
123
+
76
124
  addErrorItem: (message) ->
77
- $errorList = this.currentStep().find("ul.hat_trick_errors")
125
+ $errorList = this.getErrorListElement()
78
126
  if $errorList.length > 0
79
127
  $errorList.append("<li>#{message}</li>")
80
128
  $errorList.show()
@@ -84,26 +132,30 @@ class HatTrickWizard
84
132
  @form.formwizard("option", remoteAjax: this.ajaxEvents())
85
133
 
86
134
  goToStepId: (stepId) ->
87
- console.log "Setting up goto #{stepId}"
88
- this.setHTMeta("next_step", stepId)
135
+ this.setLinkField(stepId)
89
136
  @form.formwizard("next")
90
137
 
138
+ # TODO: Try linking to the same step rather than cloning it.
139
+ # I'm becoming more and more convinced that that won't work, however. And this isn't as bad as it used to be.
91
140
  repeatStep: (step) ->
92
- $sourceStep = this.findStep(step.repeatOf.fieldset)
93
- console.log "Cloning repeated step #{step.repeatOf.fieldset}"
94
- $clonedStep = $sourceStep.clone(true, true)
95
- $clonedStep.css("display", "none")
96
- $clonedStep.attr("id", step.name)
97
- $sourceStep.after($clonedStep)
98
- this.updateSteps()
99
- @form.formwizard("show", step.name)
100
-
101
- showStep: (step) ->
102
- console.log "Showing step #{step.fieldset}"
103
- @form.formwizard("show", step.fieldset)
104
-
105
- formwizardEnabled: ->
106
- @form.formwizard?
141
+ if $("fieldset##{step.name}").length is 0
142
+ $sourceStep = this.findStep(step.repeatOf.fieldset)
143
+ $clonedStep = $sourceStep.clone(true, true)
144
+ $clonedStep.css("display", "none")
145
+ $clonedStep.attr("id", step.name)
146
+ $sourceStep.after($clonedStep)
147
+ this.updateSteps()
148
+ this.setLinkField step.name
149
+
150
+ removeLinkField: ->
151
+ this.currentStep().find("input.#{@linkClass}").remove()
152
+
153
+ setLinkField: (stepId) ->
154
+ inputId = "_ht_link_to_#{stepId}"
155
+ this.setHiddenInput "_ht_step_link", stepId, inputId, @linkClass, this.currentStep()
156
+
157
+ LinkFieldSet: ->
158
+ this.currentStep().find("input[name='_ht_step_link']").length > 0
107
159
 
108
160
  addFakeLastStep: ->
109
161
  @form.append """<fieldset id="_ht_fake_last_step" style="display: none;" class="step"></fieldset>"""
@@ -111,27 +163,28 @@ class HatTrickWizard
111
163
  enableFormwizard: ->
112
164
  @form.formwizard
113
165
  formPluginEnabled: true,
114
- validationEnabled: true,
166
+ validationEnabled: false,
115
167
  focusFirstInput: true,
116
168
  historyEnabled: true,
117
169
  disableUIStyles: true,
118
170
  inDuration: 0,
119
- linkClass: "_ht_link",
120
- remoteAjax: this.ajaxEvents(true), # adds first Ajax event
121
- formOptions:
122
- success: (data) =>
123
- console.log "Successful form POST"
124
- beforeSubmit: (data) =>
125
- console.log "Sending these data to the server: #{$.param(data)}"
171
+ linkClass: ".#{@linkClass}",
172
+ remoteAjax: this.ajaxEvents(),
173
+ firstStep: hatTrick.metadata.currentStep.name
174
+ this.formwizardEnabled = true
126
175
 
127
- htMetaHTML: (name) ->
128
- """<input type="hidden" name="_ht_meta[#{name}]" id="_ht_#{name}" value="" />"""
176
+ setHiddenInput: (name, value, id, classes = "", scope = @form) ->
177
+ $scope = $(scope)
178
+ $input = $scope.find("""input##{id}[name="#{name}"]""")
179
+ if $input.length is 0
180
+ $input = $(this.hiddenInputHTML(name, id, classes)).prependTo $scope
181
+ $input.val value
182
+
183
+ hiddenInputHTML: (name, id, classes = "") ->
184
+ """<input type="hidden" id="#{id}" name="#{name}" class="#{classes}" value="" />"""
129
185
 
130
186
  setHTMeta: (key, value) ->
131
- $meta = @form.find("input:hidden#_ht_#{key}")
132
- if $meta.length is 0
133
- $meta = @form.prepend(this.htMetaHTML(key)).find("#_ht_#{key}")
134
- $meta.val(value)
187
+ this.setHiddenInput "_ht_meta[#{key}]", value, "_ht_#{key}"
135
188
 
136
189
  clearHTMeta: (key) ->
137
190
  @form.find("input:hidden#_ht_#{key}").remove()
@@ -139,95 +192,176 @@ class HatTrickWizard
139
192
  setCurrentStepField: ->
140
193
  stepId = this.currentStepId()
141
194
  this.setHTMeta("step", stepId)
142
- console.log "Current form step: #{stepId}"
143
195
 
196
+ # TODO: See if we still need this "next_step" ht_meta field.
144
197
  clearNextStepField: ->
145
198
  this.clearHTMeta("next_step")
199
+ this.removeLinkField()
146
200
 
147
201
  fieldRegex: /^([^\[]+)\[([^\]]+)\]$/
148
202
 
149
- setFieldValues: (formModel, selector, callback) ->
203
+ setFieldValues: (model, selector, callback) ->
150
204
  $currentStep = this.currentStep()
151
205
  $currentStep.find(selector).each (index, element) =>
152
206
  $element = $(element)
153
207
  elementName = $element.attr("name")
154
208
  if elementName? and elementName.search(@fieldRegex) isnt -1
155
209
  [_, modelName, fieldName] = elementName.match(@fieldRegex)
156
- if formModel[modelName]? and formModel[modelName][fieldName]?
157
- fieldValue = formModel[modelName][fieldName]
210
+ if model['__name__'] is modelName and model[fieldName]?
211
+ fieldValue = model[fieldName]
158
212
  callback($element, fieldValue) if fieldValue?
159
213
 
160
- fillTextFields: (formModel) ->
161
- this.setFieldValues formModel, "input:text", ($input, value) =>
214
+ fillTextFields: (model) ->
215
+ this.setFieldValues model, "input:text", ($input, value) =>
162
216
  $input.val(value)
163
217
 
164
- setSelectFields: (formModel) ->
165
- this.setFieldValues formModel, "select", ($select, value) =>
218
+ setSelectFields: (model) ->
219
+ this.setFieldValues model, "select", ($select, value) =>
166
220
  $select.find("option[value=\"#{value}\"]").attr("selected", "selected")
167
221
 
168
- setCheckboxes: (formModel) ->
169
- this.setFieldValues formModel, "input:checkbox", ($checkbox, value) =>
222
+ setCheckboxes: (model) ->
223
+ this.setFieldValues model, "input:checkbox", ($checkbox, value) =>
170
224
  $checkbox.attr("checked", "checked") if value
171
225
 
172
- setRadioButtons: (formModel) ->
173
- this.setFieldValues formModel, "input:radio", ($radio, value) =>
226
+ setRadioButtons: (model) ->
227
+ this.setFieldValues model, "input:radio", ($radio, value) =>
174
228
  $radio.find("[value=\"#{value}\"]").attr("checked", "checked")
175
229
 
176
- setFormFields: (formModel) ->
177
- this.fillTextFields(formModel)
178
- this.setSelectFields(formModel)
179
- this.setCheckboxes(formModel)
180
- this.setRadioButtons(formModel)
181
-
182
- createButton: (name, label) ->
183
- """<input type="button" name="#{name}" value="#{label}" />"""
184
-
185
- setButton: (name, label) ->
186
- $buttonsDiv = this.currentStep().find("div.buttons")
230
+ setFormFields: (model) ->
231
+ # log "Setting form fields based on: #{JSON.stringify(model)}"
232
+ this.fillTextFields(model)
233
+ this.setSelectFields(model)
234
+ this.setCheckboxes(model)
235
+ this.setRadioButtons(model)
236
+
237
+ createButton: (name, button) ->
238
+ $button = $("""<input type="button" class="wizard_button" name="#{name}" value="#{button.label}" />""")
239
+ if button.id?
240
+ $button.attr("id", button.id)
241
+ else
242
+ $button.attr("id", "#{this.currentStepId()}_#{name}_#{button.label}")
243
+ $button.click =>
244
+ clickCallbackData =
245
+ currentStep: this.currentStepId()
246
+ button: $button.attr "id"
247
+ @form.trigger "other_button_click", clickCallbackData
248
+ $button
249
+
250
+ setButton: (stepId, name, button) ->
251
+ # log "Setting button for #{stepId} named #{name} to #{JSON.stringify(button)}"
252
+ $buttonsDiv = $("fieldset##{stepId}").find("div.buttons")
187
253
  switch name
188
254
  when "next"
189
- console.log "Setting submit button val to #{label}"
190
- $buttonsDiv.find('input:submit').val(label)
255
+ # log "Setting #{stepId} submit button val to #{button.label}"
256
+ $button = $buttonsDiv.find('input:submit')
257
+ unless $button.length > 0
258
+ $button = $('<input class="wizard_button wizard_next" type="submit" />').appendTo $buttonsDiv
259
+ $button.val(button.label)
260
+ $button.attr("id", button.id) if button.id?
191
261
  when "back"
192
- console.log "Setting reset button val to #{label}"
193
- $buttonsDiv.find('input:reset').val(label)
262
+ # log "Setting reset button val to #{button.label}"
263
+ $button = $buttonsDiv.find('input:reset').val(button.label)
264
+ unless $button.length > 0
265
+ $button = $('<input class="wizard_button wizard_back" type="reset" />').appendTo $buttonsDiv
266
+ $button.val(button.label)
267
+ $button.attr("id", button.id) if button.id?
194
268
  else
195
- buttonSelector = """input:button[name="#{name}"][value="#{label}"]"""
269
+ buttonSelector = """input:button[name="#{name}"][value="#{button.label}"]"""
196
270
  $existingButtons = $buttonsDiv.find(buttonSelector)
197
- if $existingButtons.length == 0
198
- console.log "Adding new #{name}:#{label} button"
199
- $newButton = $buttonsDiv.append(this.createButton(name, label))
271
+ if $existingButtons.length is 0
272
+ # log "Adding new #{name}:#{button.label} button"
273
+ $newButton = $(this.createButton(name, button)).appendTo($buttonsDiv)
200
274
  $newButton.click (event) =>
201
275
  event.preventDefault()
202
276
  this.goToStepId(name)
203
277
 
278
+ setupButtonsForAllSteps: ->
279
+ this.setupButtonsForStep $(fieldset).attr('id') for fieldset in $('fieldset')
280
+
281
+ setupButtonsForCurrentStep: ->
282
+ this.setupButtonsForStep this.currentStepId()
283
+
284
+ setupButtonsForStep: (stepId) ->
285
+ buttons = this.buttons[stepId]
286
+ if buttons?
287
+ this.setButton(stepId, name, button) for name, button of buttons
288
+
289
+ setContents: (stepPartials) ->
290
+ for stepName, partial of stepPartials
291
+ do (stepName, partial) =>
292
+ stepId = underscoreString stepName
293
+ $partial = $(partial)
294
+ fieldsetContents = $partial.find('fieldset').html()
295
+ $step = $("fieldset##{stepId}")
296
+ $step.html fieldsetContents
297
+ this.addDefaultButtons($step)
298
+ @stepsNeedUpdate = true
299
+
300
+ handleServerData: (data) ->
301
+ if data.metadata?
302
+ this.setAction(data.metadata.url, data.metadata.method)
303
+ $.extend(window.hatTrick, data) # merge new data with hatTrick
304
+ this.updateStepFromMetadata()
305
+
306
+ updateStepContents: ->
307
+ this.setContents(hatTrick.data.hatTrickStepContents)
308
+
309
+ setButtonMetadataForCurrentStep: ->
310
+ if hatTrick.metadata?.currentStep?
311
+ currentStep = hatTrick.metadata.currentStep
312
+ if currentStep.buttons?
313
+ stepId = currentStep.fieldset
314
+ this.buttons[stepId] = currentStep.buttons
315
+
316
+ modelName: ->
317
+ hatTrick.model['__name__']
318
+
319
+ createDummyModelField: ->
320
+ this.setHiddenInput "#{this.modelName()}[_dummy]", "1"
321
+
322
+ currentStepHasModelFields: ->
323
+ this.currentStep().find("input[name^='#{this.modelName()}[']").length > 0
324
+
325
+ updateStepFromMetadata: ->
326
+ if hatTrick.metadata?.currentStep?
327
+ this.updateStepContents() if hatTrick.data.hatTrickStepContents?
328
+ this.setButtonMetadataForCurrentStep()
329
+ this.createDummyModelField() unless this.currentStepHasModelFields()
330
+
331
+ currentStep = hatTrick.metadata.currentStep
332
+ if currentStep.repeatOf?
333
+ this.repeatStep(currentStep)
334
+ else
335
+ this.setLinkField(currentStep.fieldset) unless this.LinkFieldSet()
336
+
204
337
  bindEvents: ->
205
338
  @form.bind "step_shown", (event, data) =>
206
- this.setCurrentStepField()
207
- this.clearNextStepField()
208
- this.setFormFields(htData.formModel)
209
-
210
- buttons = this.buttons[this.currentStepId()]
211
- if buttons?
212
- this.setButton(name, label) for own name, label of buttons
213
-
214
- if data.previousStep is data.firstStep
215
- console.log "Adding additional Ajax events"
216
- # adds additional Ajax events now that we have the update URL
217
- @form.formwizard("option", remoteAjax: this.ajaxEvents())
218
-
219
- @form.bind "after_remote_ajax", (event, data) =>
220
- if htData.wizardMetadata?.currentStep.buttons?
221
- stepId = htData.wizardMetadata.currentStep.fieldset
222
- this.buttons[stepId] = htData.wizardMetadata.currentStep.buttons
223
-
224
- if htData.wizardMetadata?.currentStep.repeatOf?
225
- this.repeatStep(htData.wizardMetadata.currentStep)
226
- else
227
- this.showStep(htData.wizardMetadata.currentStep)
339
+ this.stepShownCallback()
228
340
 
229
341
  $ ->
230
- $form = $("form.wizard")
231
- if htData? and !htWizard?
232
- console.log "Creating new HatTrickWizard instance"
233
- window.htWizard = new HatTrickWizard($form, htData.wizardMetadata)
342
+ if $("form.wizard").length > 0
343
+ $form = $("form.wizard")
344
+ window.hatTrick = {} unless window.hatTrick?
345
+ unless window.hatTrick.wizard?
346
+ # log "Creating new HatTrickWizard instance"
347
+ window.hatTrick.wizard = new HatTrickWizard($form, hatTrick.metadata)
348
+
349
+ camelizeString = (string) ->
350
+ re = /_([^_]*)/g
351
+ while matches = re.exec(string)
352
+ result = string.slice(0, matches.index) unless result?
353
+ result += "#{matches[1][0].toUpperCase()}#{matches[1].slice(1)}"
354
+ result = string unless result?
355
+ result
356
+
357
+ underscoreString = (string) ->
358
+ re = /([A-Z]+)([a-z\d]+)/g
359
+ while matches = re.exec(string)
360
+ result = string.slice(0, matches.index) unless result?
361
+ result += "_#{matches[1].toLowerCase()}#{matches[2]}"
362
+ result = string unless result?
363
+ result
364
+
365
+ log = (msg) ->
366
+ if window['console']?
367
+ console.log msg
@@ -1 +1 @@
1
- <%= include_gon(:namespace => 'htData', :camel_case => true) %>
1
+ <%= include_gon(:namespace => 'hatTrick', :camel_case => true) %>
data/hat-trick.gemspec CHANGED
@@ -7,9 +7,9 @@ Gem::Specification.new do |s|
7
7
  s.version = HatTrick::VERSION
8
8
  s.authors = ["Wes Morgan"]
9
9
  s.email = ["cap10morgan@gmail.com"]
10
- s.homepage = ""
11
- s.summary = %q{Rails wizards done right}
12
- s.description = %q{Combines jQuery FormWizard, validation_group, and gon for the perfect triple-play of Rails wizarding.}
10
+ s.homepage = "https://github.com/turbovote/hat-trick"
11
+ s.summary = %q{A simple DSL for creating client-side multi-step forms in Rails.}
12
+ s.description = %q{Hat-Trick brings together jQuery, validation_group, and Ajax to make multi-step forms awesome. It tries to insulate you from this complexity by providing a simple yet powerful DSL for defining the steps of your form and their behavior.}
13
13
 
14
14
  s.rubyforge_project = "hat-trick"
15
15
 
data/lib/hat-trick.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require "hat_trick/version"
2
2
  require "active_support"
3
3
  require "active_support/core_ext/module"
4
- require "hat_trick/rails_engine"
4
+ require "hat_trick/engine"
5
5
  require "hat_trick/dsl"
6
6
  require "gon"
7
7
 
@@ -0,0 +1,17 @@
1
+ module HatTrick
2
+ class Config
3
+ attr_reader :wizard_def
4
+
5
+ def initialize(wizard_def)
6
+ @wizard_def = wizard_def
7
+ end
8
+
9
+ def create_url=(url)
10
+ wizard_def.configured_create_url = url
11
+ end
12
+
13
+ def update_url=(url)
14
+ wizard_def.configured_update_url = url
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,64 @@
1
+ module HatTrick
2
+ module ControllerHelpers
3
+
4
+ private
5
+
6
+ def model_key
7
+ params.each do |k,v|
8
+ return k if v.is_a?(Hash) && is_model?(k)
9
+ end
10
+ nil
11
+ end
12
+
13
+ def params_model_name
14
+ class_name model_key unless model_key.nil?
15
+ end
16
+
17
+ def is_model?(model_name)
18
+ begin
19
+ class_name(model_name).constantize
20
+ rescue NameError
21
+ return false
22
+ end
23
+ true
24
+ end
25
+
26
+ def class_name(hash_key)
27
+ hash_key.to_s.camelize
28
+ end
29
+
30
+ def model_class
31
+ return ht_wizard.model.class if ht_wizard.model
32
+
33
+ # if that didn't work, try to grab it from the params hash
34
+ model_name = params_model_name
35
+ return nil if model_name.nil?
36
+
37
+ begin
38
+ model_klass = params_model_name.constantize
39
+ rescue NameError
40
+ Rails.logger.error "Could not find model class #{params_model_name.camelize}"
41
+ nil
42
+ else
43
+ model_klass
44
+ end
45
+ end
46
+
47
+ def setup_validation_group_for(wizard_step)
48
+ klass = model_class
49
+ return if klass.nil?
50
+ step_name = wizard_step.name
51
+ validation_groups = ::ActiveRecord::Base.validation_group_classes[klass] || []
52
+ unless validation_groups.include?(step_name)
53
+ validation_fields = params.keys # TODO: Try it without these (so only the model keys below)
54
+ model = model_key
55
+ if model
56
+ validation_fields += params[model].keys
57
+ end
58
+ validation_fields = validation_fields.map(&:to_sym)
59
+ klass.validation_group(step_name, :fields => validation_fields)
60
+ end
61
+ HatTrick::ModelMethods.set_current_validation_group_for(model_class, step_name)
62
+ end
63
+ end
64
+ end