hoarder-js 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2 -0
- data/Gemfile.lock +2 -2
- data/Manifest +14 -3
- data/assets/scripts/coffee/hoarder/form/form.coffee +47 -44
- data/assets/scripts/coffee/hoarder/form/form_serializer.coffee +23 -0
- data/assets/scripts/coffee/hoarder/form_manager.coffee +35 -19
- data/assets/scripts/coffee/hoarder/submitter/form_submitter.coffee +10 -15
- data/assets/scripts/coffee/hoarder/submitter/submitters/base_submitter.coffee +11 -0
- data/assets/scripts/coffee/hoarder/submitter/submitters/polling_submitter.coffee +30 -27
- data/assets/scripts/coffee/hoarder/submitter/submitters/simple_submitter.coffee +11 -21
- data/assets/scripts/coffee/hoarder/validator/constraints/alpha_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/constraints/alphanumeric_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/constraints/base_constraint.coffee +10 -0
- data/assets/scripts/coffee/hoarder/validator/constraints/credit_card_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/constraints/email_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/constraints/max_length_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/constraints/min_length_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/constraints/numeric_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/constraints/phone_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/constraints/required_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/form_validator.coffee +30 -25
- data/assets/scripts/coffee/hoarder/validator/rules/validation_rule.coffee +10 -0
- data/assets/scripts/js/lib/bonzo.js +1151 -0
- data/assets/scripts/js/lib/qwery.js +369 -0
- data/assets/scripts/js/lib/reqwest.js +565 -0
- data/assets/scripts/js/patches/event_listeners.js +73 -0
- data/bin/hoarder.js +2807 -369
- data/hoarder-js.gemspec +3 -3
- data/spec/jasmine.yml +3 -0
- data/spec/runner.html +44 -34
- data/spec/support/fixtures.coffee +19 -0
- data/spec/support/lib/jasmine-fixture.js +506 -0
- data/spec/support/lib/jquery-1.7.1.min.js +4 -0
- data/spec/support/mocks.coffee +12 -37
- data/spec/support/requirements.coffee +0 -1
- data/spec/tests/form/form_serializer_spec.coffee +78 -0
- data/spec/tests/form/form_spec.coffee +127 -0
- data/spec/tests/form_manager_spec.coffee +128 -40
- data/spec/tests/submitter/form_submitter_spec.coffee +59 -42
- data/spec/tests/submitter/submitters/polling_submitter_spec.coffee +102 -57
- data/spec/tests/submitter/submitters/simple_submitter_spec.coffee +42 -16
- data/spec/tests/validator/constraints_spec.coffee +65 -57
- data/spec/tests/validator/form_validator_spec.coffee +39 -23
- data/spec/tests/validator/validation_rule_spec.coffee +14 -0
- metadata +16 -5
- data/assets/scripts/coffee/hoarder/form/form_element.coffee +0 -22
- data/assets/scripts/coffee/hoarder/validator/error/validation_error.coffee +0 -9
- data/assets/scripts/js/lib/jquery.js +0 -5
data/CHANGELOG
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
GIT
|
2
2
|
remote: git://github.com/jpeace/keystone.git
|
3
|
-
revision:
|
3
|
+
revision: 54627ade405d8b3307e349f36bab6e87b75fae84
|
4
4
|
specs:
|
5
5
|
keystone (0.0.1)
|
6
6
|
closure-compiler
|
@@ -85,7 +85,7 @@ GEM
|
|
85
85
|
multi_json (~> 1.0)
|
86
86
|
rack (~> 1.0)
|
87
87
|
tilt (~> 1.1, != 1.3.0)
|
88
|
-
tilt (1.
|
88
|
+
tilt (1.4.0)
|
89
89
|
websocket (1.0.7)
|
90
90
|
|
91
91
|
PLATFORMS
|
data/Manifest
CHANGED
@@ -6,13 +6,15 @@ Manifest
|
|
6
6
|
README.rdoc
|
7
7
|
Rakefile
|
8
8
|
assets/scripts/coffee/hoarder/form/form.coffee
|
9
|
-
assets/scripts/coffee/hoarder/form/
|
9
|
+
assets/scripts/coffee/hoarder/form/form_serializer.coffee
|
10
10
|
assets/scripts/coffee/hoarder/form_manager.coffee
|
11
11
|
assets/scripts/coffee/hoarder/submitter/form_submitter.coffee
|
12
|
+
assets/scripts/coffee/hoarder/submitter/submitters/base_submitter.coffee
|
12
13
|
assets/scripts/coffee/hoarder/submitter/submitters/polling_submitter.coffee
|
13
14
|
assets/scripts/coffee/hoarder/submitter/submitters/simple_submitter.coffee
|
14
15
|
assets/scripts/coffee/hoarder/validator/constraints/alpha_constraint.coffee
|
15
16
|
assets/scripts/coffee/hoarder/validator/constraints/alphanumeric_constraint.coffee
|
17
|
+
assets/scripts/coffee/hoarder/validator/constraints/base_constraint.coffee
|
16
18
|
assets/scripts/coffee/hoarder/validator/constraints/credit_card_constraint.coffee
|
17
19
|
assets/scripts/coffee/hoarder/validator/constraints/email_constraint.coffee
|
18
20
|
assets/scripts/coffee/hoarder/validator/constraints/max_length_constraint.coffee
|
@@ -20,9 +22,12 @@ assets/scripts/coffee/hoarder/validator/constraints/min_length_constraint.coffee
|
|
20
22
|
assets/scripts/coffee/hoarder/validator/constraints/numeric_constraint.coffee
|
21
23
|
assets/scripts/coffee/hoarder/validator/constraints/phone_constraint.coffee
|
22
24
|
assets/scripts/coffee/hoarder/validator/constraints/required_constraint.coffee
|
23
|
-
assets/scripts/coffee/hoarder/validator/error/validation_error.coffee
|
24
25
|
assets/scripts/coffee/hoarder/validator/form_validator.coffee
|
25
|
-
assets/scripts/
|
26
|
+
assets/scripts/coffee/hoarder/validator/rules/validation_rule.coffee
|
27
|
+
assets/scripts/js/lib/bonzo.js
|
28
|
+
assets/scripts/js/lib/qwery.js
|
29
|
+
assets/scripts/js/lib/reqwest.js
|
30
|
+
assets/scripts/js/patches/event_listeners.js
|
26
31
|
bin/hoarder.js
|
27
32
|
config/assets.rb
|
28
33
|
lib/hoarder.rb
|
@@ -30,13 +35,19 @@ lib/hoarder/symbols.rb
|
|
30
35
|
spec/jasmine.yml
|
31
36
|
spec/runner.html
|
32
37
|
spec/support/classes.coffee
|
38
|
+
spec/support/fixtures.coffee
|
33
39
|
spec/support/helpers.coffee
|
40
|
+
spec/support/lib/jasmine-fixture.js
|
41
|
+
spec/support/lib/jquery-1.7.1.min.js
|
34
42
|
spec/support/mocks.coffee
|
35
43
|
spec/support/objects.coffee
|
36
44
|
spec/support/requirements.coffee
|
45
|
+
spec/tests/form/form_serializer_spec.coffee
|
46
|
+
spec/tests/form/form_spec.coffee
|
37
47
|
spec/tests/form_manager_spec.coffee
|
38
48
|
spec/tests/submitter/form_submitter_spec.coffee
|
39
49
|
spec/tests/submitter/submitters/polling_submitter_spec.coffee
|
40
50
|
spec/tests/submitter/submitters/simple_submitter_spec.coffee
|
41
51
|
spec/tests/validator/constraints_spec.coffee
|
42
52
|
spec/tests/validator/form_validator_spec.coffee
|
53
|
+
spec/tests/validator/validation_rule_spec.coffee
|
@@ -1,48 +1,51 @@
|
|
1
|
-
require
|
1
|
+
FormSerializer = require 'hoarder/form/form_serializer'
|
2
2
|
|
3
|
-
FormElement = require "hoarder/form/form_element"
|
4
|
-
|
5
|
-
#
|
6
|
-
# @author - Tim Shelburne <tim@musiconelive.com>
|
7
|
-
#
|
8
|
-
# wraps an HTML form for easier form management
|
9
|
-
#
|
10
3
|
class Form
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
4
|
+
|
5
|
+
constructor: (@formElement)->
|
6
|
+
@addedElements = [ ]
|
7
|
+
|
8
|
+
elements: -> (@formElement[index] for index in [0..@formElement.length] when @formElement[index]?.nodeName in [ 'INPUT', 'SELECT', 'TEXTAREA' ])
|
9
|
+
|
10
|
+
action: -> @formElement.action
|
11
|
+
|
12
|
+
method: -> @formElement.method
|
13
|
+
|
14
|
+
addElement: (name, value)->
|
15
|
+
throw new Error "'#{name}' already exists as an element on the form." if @hasElement name
|
16
|
+
element = createElement name, value
|
17
|
+
@formElement.appendChild element
|
18
|
+
@addedElements.push element
|
19
|
+
element
|
20
|
+
|
21
|
+
addElements: (elements)->
|
22
|
+
errors = [ ]
|
23
|
+
for element in elements
|
24
|
+
try @addElement(element.name, element.value)
|
25
|
+
catch e
|
26
|
+
errors.push e
|
27
|
+
throw errors[0] if errors.length
|
28
|
+
|
29
|
+
hasElement: (name)-> @getElement(name)?
|
30
|
+
|
31
|
+
getElement: (name)-> @formElement[name] if @formElement[name] instanceof HTMLElement
|
32
|
+
|
33
|
+
updateAddedElement: (name, value)-> if @formElement[name]? then @formElement[name].value = value else @addElement name, value
|
34
|
+
|
35
|
+
clearAddedElements: ->
|
36
|
+
@formElement.removeChild element for element in @addedElements
|
37
|
+
@addedElements = []
|
38
|
+
|
39
|
+
serialize: -> FormSerializer.toString @
|
40
|
+
|
41
|
+
|
42
|
+
# private
|
43
|
+
|
44
|
+
createElement = (name, value)->
|
45
|
+
element = document.createElement("input")
|
46
|
+
element.type = "hidden"
|
47
|
+
element.name = name
|
48
|
+
element.value = value
|
49
|
+
element
|
47
50
|
|
48
51
|
return Form
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Serializer
|
2
|
+
|
3
|
+
@toString: (form)-> removeNulls((serializeElement element for element in form.elements())).join("&")
|
4
|
+
|
5
|
+
# private
|
6
|
+
|
7
|
+
serializeElement = (element)->
|
8
|
+
return "#{element.name}=#{encodeURIComponent element.value}" unless isComplicated element
|
9
|
+
return "#{element.name}=#{encodeURIComponent element.value}" if isCheckable(element) and element.checked
|
10
|
+
return ("#{element.name}=#{encodeURIComponent option.value}" for option in element.options when option.selected).join("&") if isMultiSelect(element)
|
11
|
+
null
|
12
|
+
|
13
|
+
isComplicated = (element)-> isCheckable(element) or isMultiSelect(element) or isFile(element)
|
14
|
+
|
15
|
+
isCheckable = (element)-> element.nodeName is "INPUT" and element.type in [ "checkbox", "radio" ]
|
16
|
+
|
17
|
+
isMultiSelect = (element)-> element.nodeName is "SELECT" and element.type is "select-multiple"
|
18
|
+
|
19
|
+
isFile = (element)-> element.nodeName is "INPUT" and element.type is "file"
|
20
|
+
|
21
|
+
removeNulls = (array)-> array.filter((e)-> return e)
|
22
|
+
|
23
|
+
return Serializer
|
@@ -1,32 +1,48 @@
|
|
1
|
+
require 'patches/event_listeners'
|
2
|
+
|
1
3
|
Signal = require "cronus/signal"
|
2
4
|
SignalRelay = require "cronus/signal_relay"
|
3
5
|
|
6
|
+
Form = require 'hoarder/form/form'
|
4
7
|
FormSubmitter = require 'hoarder/submitter/form_submitter'
|
5
8
|
FormValidator = require 'hoarder/validator/form_validator'
|
6
9
|
|
7
|
-
#
|
8
|
-
# @author - Tim Shelburne <tim@musiconelive.com>
|
9
|
-
#
|
10
|
-
# abstracts submitting and validating forms from the validator and submitter
|
11
|
-
#
|
12
10
|
class FormManager
|
13
|
-
constructor: (@formSubmitter, @formValidator)->
|
14
|
-
@validatedWithErrors = new Signal()
|
15
|
-
@submittedWithSuccess = new SignalRelay(@formSubmitter.submittedWithSuccess)
|
16
|
-
@submittedWithError = new SignalRelay(@formSubmitter.submittedWithError)
|
17
11
|
|
18
|
-
|
19
|
-
|
12
|
+
@create: (pollingUrl="", pollFrequency=1000)->
|
13
|
+
new @(FormSubmitter.create(pollingUrl, pollFrequency), FormValidator.create())
|
14
|
+
|
15
|
+
constructor: (@formSubmitter, @formValidator)->
|
16
|
+
@validatedWithErrors = new Signal()
|
17
|
+
@submittedWithSuccess = new SignalRelay(@formSubmitter.submittedWithSuccess)
|
18
|
+
@submittedWithError = new SignalRelay(@formSubmitter.submittedWithError)
|
19
|
+
@_forms = [ ]
|
20
|
+
@_listeners = { }
|
21
|
+
|
22
|
+
manage: (formId, type='simple')->
|
23
|
+
throw new Error "'#{formId}' is already a managed form." if getForm.call(@, formId)?
|
24
|
+
formElement = document.getElementById formId
|
25
|
+
form = new Form(formElement)
|
26
|
+
formElement.addEventListener 'submit', @_listeners[formId] = (event)=>
|
27
|
+
event.preventDefault()
|
28
|
+
submit.call @, form, type
|
29
|
+
@_forms.push form
|
30
|
+
form
|
20
31
|
|
21
|
-
|
22
|
-
|
32
|
+
release: (formId)->
|
33
|
+
form = getForm.call @, formId
|
34
|
+
form.formElement.removeEventListener 'submit', @_listeners[formId]
|
35
|
+
delete @_listeners[formId]
|
36
|
+
@_forms.splice @_forms.indexOf(form), 1
|
23
37
|
|
24
|
-
|
25
|
-
|
38
|
+
getForm = (formId)->
|
39
|
+
for form in @_forms
|
40
|
+
return form if form.formElement.id is formId
|
26
41
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
42
|
+
submit = (form, type)->
|
43
|
+
if @formValidator.validateForm form
|
44
|
+
@formSubmitter.submit form, type
|
45
|
+
else
|
46
|
+
@validatedWithErrors.dispatch form
|
31
47
|
|
32
48
|
return FormManager
|
@@ -3,27 +3,22 @@ MultiSignalRelay = require "cronus/multi_signal_relay"
|
|
3
3
|
SimpleSubmitter = require "hoarder/submitter/submitters/simple_submitter"
|
4
4
|
PollingSubmitter = require "hoarder/submitter/submitters/polling_submitter"
|
5
5
|
|
6
|
-
#
|
7
|
-
# @author - Tim Shelburne <tim@musiconelive.com>
|
8
|
-
#
|
9
|
-
# a class to handle submitting forms
|
10
|
-
#
|
11
6
|
class FormSubmitter
|
7
|
+
|
8
|
+
@create: (pollingUrl, pollFrequency=1000)->
|
9
|
+
new @([ new SimpleSubmitter(), new PollingSubmitter(pollingUrl, pollFrequency)])
|
10
|
+
|
12
11
|
constructor: (@submitters)->
|
13
|
-
successSignals =
|
14
|
-
errorSignals =
|
15
|
-
for submitter in @submitters
|
16
|
-
successSignals.push submitter.submittedWithSuccess
|
17
|
-
errorSignals.push submitter.submittedWithError
|
12
|
+
successSignals = (submitter.submittedWithSuccess for submitter in @submitters)
|
13
|
+
errorSignals = (submitter.submittedWithError for submitter in @submitters)
|
18
14
|
|
19
15
|
@submittedWithSuccess = new MultiSignalRelay(successSignals)
|
20
16
|
@submittedWithError = new MultiSignalRelay(errorSignals)
|
21
17
|
|
22
|
-
|
23
|
-
new @([ new SimpleSubmitter(), new PollingSubmitter(pollingUrl, 1000)])
|
24
|
-
|
25
|
-
submitForm: (form)->
|
18
|
+
submit: (form, type)->
|
26
19
|
for submitter in @submitters
|
27
|
-
|
20
|
+
if submitter.canSubmit(type)
|
21
|
+
submitter.submit form
|
22
|
+
break
|
28
23
|
|
29
24
|
return FormSubmitter
|
@@ -1,36 +1,39 @@
|
|
1
|
-
|
1
|
+
require 'lib/reqwest'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
#
|
8
|
-
class PollingSubmitter extends SimpleSubmitter
|
3
|
+
BaseSubmitter = require "hoarder/submitter/submitters/base_submitter"
|
4
|
+
|
5
|
+
class PollingSubmitter extends BaseSubmitter
|
6
|
+
|
9
7
|
constructor: (@pollUrl, @pollFrequency)->
|
10
8
|
super()
|
9
|
+
@type = 'polling'
|
11
10
|
|
12
|
-
|
11
|
+
submit: (form)->
|
12
|
+
reqwest(
|
13
|
+
url: form.action
|
14
|
+
type: form.method
|
15
|
+
data: form.serialize()
|
16
|
+
success: (data)=> @poll(form, data.processId)
|
17
|
+
error: (xhr, text)=> @submittedWithError.dispatch(form, text)
|
18
|
+
)
|
13
19
|
|
14
|
-
|
15
|
-
|
16
|
-
@
|
17
|
-
|
18
|
-
|
20
|
+
poll: (form, processId)=>
|
21
|
+
reqwest(
|
22
|
+
url: @pollUrl
|
23
|
+
type: "POST"
|
24
|
+
data: "processId=#{processId}"
|
25
|
+
success: (data)=> pollSuccess.call @, form, processId, data
|
26
|
+
error: (xhr, text)=> @submittedWithError.dispatch(form, text)
|
27
|
+
)
|
19
28
|
|
20
|
-
|
21
|
-
unless @executing
|
22
|
-
@executing = true
|
23
|
-
$.ajax
|
24
|
-
url: @pollUrl
|
25
|
-
type: "POST"
|
26
|
-
data: "pollId=#{pollId}"
|
27
|
-
success: (data)=> @pollSuccess(form, pollId, data)
|
28
|
-
error: (xhr, text)=> @submitError(form, xhr, text)
|
29
|
+
# private
|
29
30
|
|
30
|
-
pollSuccess
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
pollSuccess = (form, processId, data)->
|
32
|
+
if data.processCompleted
|
33
|
+
@submittedWithSuccess.dispatch(form, data.processData)
|
34
|
+
else
|
35
|
+
setTimeout( =>
|
36
|
+
@poll(form, data.processId)
|
37
|
+
, @pollFrequency)
|
35
38
|
|
36
39
|
return PollingSubmitter
|
@@ -1,30 +1,20 @@
|
|
1
|
-
require
|
1
|
+
require 'lib/reqwest'
|
2
2
|
|
3
|
-
|
3
|
+
BaseSubmitter = require 'hoarder/submitter/submitters/base_submitter'
|
4
4
|
|
5
|
-
|
6
|
-
# @author - Tim Shelburne <tim@musiconelive.com>
|
7
|
-
#
|
8
|
-
# handles submitting a form and waiting for a response
|
9
|
-
#
|
10
|
-
class SimpleSubmitter
|
11
|
-
constructor: ->
|
12
|
-
@submittedWithSuccess = new Signal()
|
13
|
-
@submittedWithError = new Signal()
|
5
|
+
class SimpleSubmitter extends BaseSubmitter
|
14
6
|
|
15
|
-
|
7
|
+
constructor: ->
|
8
|
+
super()
|
9
|
+
@type = 'simple'
|
16
10
|
|
17
|
-
|
18
|
-
|
11
|
+
submit: (form)->
|
12
|
+
reqwest(
|
19
13
|
url: form.action
|
20
14
|
type: form.method
|
21
15
|
data: form.serialize()
|
22
|
-
success: (data)=>
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
submitSuccess: (form, data)-> @submittedWithSuccess.dispatch(form, data)
|
27
|
-
|
28
|
-
submitError: (form, xhr, text)-> @submittedWithError.dispatch(form, text)
|
16
|
+
success: (data)=> @submittedWithSuccess.dispatch(form, data)
|
17
|
+
error: (xhr, text)=> @submittedWithError.dispatch(form, text)
|
18
|
+
)
|
29
19
|
|
30
20
|
return SimpleSubmitter
|
@@ -1,18 +1,12 @@
|
|
1
|
-
|
1
|
+
BaseConstraint = require 'hoarder/validator/constraints/base_constraint'
|
2
2
|
|
3
|
-
|
4
|
-
# @author - Tim Shelburne <tim@musiconelive.com>
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
class AlphaConstraint
|
9
|
-
canHandle: (type)->
|
10
|
-
type is "alpha"
|
3
|
+
class AlphaConstraint extends BaseConstraint
|
11
4
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
5
|
+
constructor: ->
|
6
|
+
@type = "alpha"
|
7
|
+
|
8
|
+
rulePasses: (element)-> element.value.match(/^[A-Za-z\s]*$/)
|
9
|
+
|
10
|
+
errorMessage: -> "This field only accepts numbers and characters (0-9, A-Z, a-z)."
|
17
11
|
|
18
12
|
return AlphaConstraint
|