hat-trick 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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