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.
Files changed (48) hide show
  1. data/CHANGELOG +2 -0
  2. data/Gemfile.lock +2 -2
  3. data/Manifest +14 -3
  4. data/assets/scripts/coffee/hoarder/form/form.coffee +47 -44
  5. data/assets/scripts/coffee/hoarder/form/form_serializer.coffee +23 -0
  6. data/assets/scripts/coffee/hoarder/form_manager.coffee +35 -19
  7. data/assets/scripts/coffee/hoarder/submitter/form_submitter.coffee +10 -15
  8. data/assets/scripts/coffee/hoarder/submitter/submitters/base_submitter.coffee +11 -0
  9. data/assets/scripts/coffee/hoarder/submitter/submitters/polling_submitter.coffee +30 -27
  10. data/assets/scripts/coffee/hoarder/submitter/submitters/simple_submitter.coffee +11 -21
  11. data/assets/scripts/coffee/hoarder/validator/constraints/alpha_constraint.coffee +8 -14
  12. data/assets/scripts/coffee/hoarder/validator/constraints/alphanumeric_constraint.coffee +8 -14
  13. data/assets/scripts/coffee/hoarder/validator/constraints/base_constraint.coffee +10 -0
  14. data/assets/scripts/coffee/hoarder/validator/constraints/credit_card_constraint.coffee +8 -14
  15. data/assets/scripts/coffee/hoarder/validator/constraints/email_constraint.coffee +8 -14
  16. data/assets/scripts/coffee/hoarder/validator/constraints/max_length_constraint.coffee +8 -14
  17. data/assets/scripts/coffee/hoarder/validator/constraints/min_length_constraint.coffee +8 -14
  18. data/assets/scripts/coffee/hoarder/validator/constraints/numeric_constraint.coffee +8 -14
  19. data/assets/scripts/coffee/hoarder/validator/constraints/phone_constraint.coffee +8 -14
  20. data/assets/scripts/coffee/hoarder/validator/constraints/required_constraint.coffee +8 -14
  21. data/assets/scripts/coffee/hoarder/validator/form_validator.coffee +30 -25
  22. data/assets/scripts/coffee/hoarder/validator/rules/validation_rule.coffee +10 -0
  23. data/assets/scripts/js/lib/bonzo.js +1151 -0
  24. data/assets/scripts/js/lib/qwery.js +369 -0
  25. data/assets/scripts/js/lib/reqwest.js +565 -0
  26. data/assets/scripts/js/patches/event_listeners.js +73 -0
  27. data/bin/hoarder.js +2807 -369
  28. data/hoarder-js.gemspec +3 -3
  29. data/spec/jasmine.yml +3 -0
  30. data/spec/runner.html +44 -34
  31. data/spec/support/fixtures.coffee +19 -0
  32. data/spec/support/lib/jasmine-fixture.js +506 -0
  33. data/spec/support/lib/jquery-1.7.1.min.js +4 -0
  34. data/spec/support/mocks.coffee +12 -37
  35. data/spec/support/requirements.coffee +0 -1
  36. data/spec/tests/form/form_serializer_spec.coffee +78 -0
  37. data/spec/tests/form/form_spec.coffee +127 -0
  38. data/spec/tests/form_manager_spec.coffee +128 -40
  39. data/spec/tests/submitter/form_submitter_spec.coffee +59 -42
  40. data/spec/tests/submitter/submitters/polling_submitter_spec.coffee +102 -57
  41. data/spec/tests/submitter/submitters/simple_submitter_spec.coffee +42 -16
  42. data/spec/tests/validator/constraints_spec.coffee +65 -57
  43. data/spec/tests/validator/form_validator_spec.coffee +39 -23
  44. data/spec/tests/validator/validation_rule_spec.coffee +14 -0
  45. metadata +16 -5
  46. data/assets/scripts/coffee/hoarder/form/form_element.coffee +0 -22
  47. data/assets/scripts/coffee/hoarder/validator/error/validation_error.coffee +0 -9
  48. data/assets/scripts/js/lib/jquery.js +0 -5
data/CHANGELOG CHANGED
@@ -1 +1,3 @@
1
+ v0.0.2 removed all dependencies on jquery and update library API - version 1.0.0 pending successful use in a production project
2
+
1
3
  v0.0.1 new library
@@ -1,6 +1,6 @@
1
1
  GIT
2
2
  remote: git://github.com/jpeace/keystone.git
3
- revision: 3680c30328bf3b93af7c7f1b1bad685cbaec35dd
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.3.7)
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/form_element.coffee
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/js/lib/jquery.js
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 "lib/jquery"
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
- constructor: (formId, @type = "simple")->
12
- @form = $("##{formId}")
13
- @form.submit (e)-> e.preventDefault()
14
- @action = @form.attr("action")
15
- @method = @form.attr("method")
16
- @addedElements = []
17
-
18
- elements: ->
19
- elements = []
20
- inputs = @form.find("input")
21
- elements = elements.concat inputs.toArray() if inputs.length > 0
22
- selects = @form.find("select")
23
- elements = elements.concat selects.toArray() if selects.length > 0
24
- textareas = @form.find("textarea")
25
- elements = elements.concat textareas.toArray() if textareas.length > 0
26
-
27
- formElements = []
28
- for element in elements
29
- validationRules = if element.getAttribute("data-validation")? then (rule.trim() for rule in element.getAttribute("data-validation").split(',')) else []
30
- selector = "#{element.nodeName}[data-bind='#{element.getAttribute("data-bind")}']"
31
- formElements.push new FormElement(element.name, element.value, selector, validationRules)
32
- formElements
33
-
34
- addElement: (name, value, isRemovable = true)->
35
- @form.append "<input type='hidden' name='#{name}' value='#{value}'/>"
36
- @addedElements.push $("input[name='#{name}']", @form) if isRemovable
37
-
38
- addElements: (elements)-> @addElement(element.name, element.value) for element in elements
39
-
40
- updateAddedElement: (name, value)-> @form.find("input[name='#{name}']").val(value)
41
-
42
- clearAddedElements: ->
43
- element.remove() for element in @addedElements
44
- @addedElements = []
45
-
46
- serialize: -> @form.serialize()
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
- @default: (pollingUrl="")->
19
- new @(FormSubmitter.default(pollingUrl), FormValidator.default())
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
- validateForm: (form)->
22
- @formValidator.validateForm(form)
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
- submitForm: (form)->
25
- errors = @validateForm(form)
38
+ getForm = (formId)->
39
+ for form in @_forms
40
+ return form if form.formElement.id is formId
26
41
 
27
- if (errors.length > 0)
28
- @validatedWithErrors.dispatch(errors)
29
- else
30
- @formSubmitter.submitForm(form)
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
- @default: (pollingUrl)->
23
- new @([ new SimpleSubmitter(), new PollingSubmitter(pollingUrl, 1000)])
24
-
25
- submitForm: (form)->
18
+ submit: (form, type)->
26
19
  for submitter in @submitters
27
- submitter.submitForm(form) if submitter.canSubmit(form)
20
+ if submitter.canSubmit(type)
21
+ submitter.submit form
22
+ break
28
23
 
29
24
  return FormSubmitter
@@ -0,0 +1,11 @@
1
+ Signal = require 'cronus/signal'
2
+
3
+ class BaseSubmitter
4
+
5
+ constructor: ->
6
+ @submittedWithSuccess = new Signal()
7
+ @submittedWithError = new Signal()
8
+
9
+ canSubmit: (type)-> type is @type
10
+
11
+ return BaseSubmitter
@@ -1,36 +1,39 @@
1
- SimpleSubmitter = require "hoarder/submitter/submitters/simple_submitter"
1
+ require 'lib/reqwest'
2
2
 
3
- #
4
- # @author - Tim Shelburne <tim@musiconelive.com>
5
- #
6
- # handles executing a delayed
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
- canSubmit: (form)-> form.type is "polling"
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
- submitSuccess: (form, data)->
15
- @interval = setInterval( =>
16
- @queryPoll(form, data.pollId)
17
- , @pollFrequency)
18
- @queryPoll(form, data.pollId)
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
- queryPoll: (form, pollId)=>
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: (form, pollId, data)=>
31
- @executing = false
32
- if data.pollCompleted
33
- clearInterval(@interval)
34
- @submittedWithSuccess.dispatch(form, data.pollData)
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 "lib/jquery"
1
+ require 'lib/reqwest'
2
2
 
3
- Signal = require "cronus/signal"
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
- canSubmit: (form)-> form.type is "simple"
7
+ constructor: ->
8
+ super()
9
+ @type = 'simple'
16
10
 
17
- submitForm: (form)->
18
- $.ajax
11
+ submit: (form)->
12
+ reqwest(
19
13
  url: form.action
20
14
  type: form.method
21
15
  data: form.serialize()
22
- success: (data)=>
23
- @submitSuccess(form, data)
24
- error: (xhr, text)=> @submitError(form, xhr, text)
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
- ValidationError = require "hoarder/validator/error/validation_error"
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
- handle: (element)->
13
- # if element.value.match(/^[A-Za-z0-9\s]*$/)
14
- # return []
15
- # else
16
- # return [ new ValidationError "This field only accepts numbers and characters (0-9, A-Z, a-z)." ]
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