hoarder-js 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/CHANGELOG +1 -0
  2. data/Gemfile +9 -0
  3. data/Gemfile.lock +100 -0
  4. data/LICENSE +21 -0
  5. data/Manifest +42 -0
  6. data/README.rdoc +0 -0
  7. data/Rakefile +38 -0
  8. data/assets/scripts/coffee/hoarder/form/form.coffee +48 -0
  9. data/assets/scripts/coffee/hoarder/form/form_element.coffee +22 -0
  10. data/assets/scripts/coffee/hoarder/form_manager.coffee +32 -0
  11. data/assets/scripts/coffee/hoarder/submitter/form_submitter.coffee +29 -0
  12. data/assets/scripts/coffee/hoarder/submitter/submitters/polling_submitter.coffee +36 -0
  13. data/assets/scripts/coffee/hoarder/submitter/submitters/simple_submitter.coffee +30 -0
  14. data/assets/scripts/coffee/hoarder/validator/constraints/alpha_constraint.coffee +18 -0
  15. data/assets/scripts/coffee/hoarder/validator/constraints/alphanumeric_constraint.coffee +18 -0
  16. data/assets/scripts/coffee/hoarder/validator/constraints/credit_card_constraint.coffee +18 -0
  17. data/assets/scripts/coffee/hoarder/validator/constraints/email_constraint.coffee +18 -0
  18. data/assets/scripts/coffee/hoarder/validator/constraints/max_length_constraint.coffee +18 -0
  19. data/assets/scripts/coffee/hoarder/validator/constraints/min_length_constraint.coffee +18 -0
  20. data/assets/scripts/coffee/hoarder/validator/constraints/numeric_constraint.coffee +18 -0
  21. data/assets/scripts/coffee/hoarder/validator/constraints/phone_constraint.coffee +18 -0
  22. data/assets/scripts/coffee/hoarder/validator/constraints/required_constraint.coffee +18 -0
  23. data/assets/scripts/coffee/hoarder/validator/error/validation_error.coffee +9 -0
  24. data/assets/scripts/coffee/hoarder/validator/form_validator.coffee +53 -0
  25. data/assets/scripts/js/lib/jquery.js +5 -0
  26. data/bin/hoarder.js +1197 -0
  27. data/config/assets.rb +8 -0
  28. data/hoarder-js.gemspec +36 -0
  29. data/lib/hoarder.rb +1 -0
  30. data/lib/hoarder/symbols.rb +17 -0
  31. data/spec/jasmine.yml +44 -0
  32. data/spec/runner.html +75 -0
  33. data/spec/support/classes.coffee +0 -0
  34. data/spec/support/helpers.coffee +22 -0
  35. data/spec/support/mocks.coffee +42 -0
  36. data/spec/support/objects.coffee +0 -0
  37. data/spec/support/requirements.coffee +1 -0
  38. data/spec/tests/form_manager_spec.coffee +43 -0
  39. data/spec/tests/submitter/form_submitter_spec.coffee +47 -0
  40. data/spec/tests/submitter/submitters/polling_submitter_spec.coffee +60 -0
  41. data/spec/tests/submitter/submitters/simple_submitter_spec.coffee +19 -0
  42. data/spec/tests/validator/constraints_spec.coffee +74 -0
  43. data/spec/tests/validator/form_validator_spec.coffee +29 -0
  44. metadata +132 -0
@@ -0,0 +1 @@
1
+ v0.0.1 new library
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source :rubygems
2
+
3
+ gem "echoe"
4
+ gem 'rake'
5
+ gem 'jasmine'
6
+ gem 'jasmine-headless-webkit'
7
+
8
+ gem 'keystone', git: "git://github.com/jpeace/keystone.git"
9
+ gem 'cronus', git: "git://github.com/tshelburne/cronus-js.git"
@@ -0,0 +1,100 @@
1
+ GIT
2
+ remote: git://github.com/jpeace/keystone.git
3
+ revision: 3680c30328bf3b93af7c7f1b1bad685cbaec35dd
4
+ specs:
5
+ keystone (0.0.1)
6
+ closure-compiler
7
+ coffee-script
8
+ sass
9
+ sinatra
10
+
11
+ GIT
12
+ remote: git://github.com/tshelburne/cronus-js.git
13
+ revision: c2cb5da182efb6c3742518dabda93f48b5281126
14
+ specs:
15
+ cronus (0.0.1)
16
+
17
+ GEM
18
+ remote: http://rubygems.org/
19
+ specs:
20
+ allison (2.0.3)
21
+ childprocess (0.3.9)
22
+ ffi (~> 1.0, >= 1.0.11)
23
+ closure-compiler (1.1.8)
24
+ coffee-script (2.2.0)
25
+ coffee-script-source
26
+ execjs
27
+ coffee-script-source (1.6.2)
28
+ diff-lcs (1.2.4)
29
+ echoe (4.6.3)
30
+ allison (>= 2.0.3)
31
+ gemcutter (>= 0.7.0)
32
+ rake (>= 0.9.2)
33
+ rdoc (>= 3.6.1)
34
+ rubyforge (>= 2.0.4)
35
+ execjs (1.4.0)
36
+ multi_json (~> 1.0)
37
+ ffi (1.8.1)
38
+ gemcutter (0.7.1)
39
+ hike (1.2.2)
40
+ jasmine (1.3.2)
41
+ jasmine-core (~> 1.3.1)
42
+ rack (~> 1.0)
43
+ rspec (>= 1.3.1)
44
+ selenium-webdriver (>= 0.1.3)
45
+ jasmine-core (1.3.1)
46
+ jasmine-headless-webkit (0.8.4)
47
+ coffee-script
48
+ jasmine-core (~> 1.1)
49
+ multi_json
50
+ rainbow
51
+ sprockets (~> 2)
52
+ json (1.7.7)
53
+ json_pure (1.7.7)
54
+ multi_json (1.7.2)
55
+ rack (1.5.2)
56
+ rack-protection (1.5.0)
57
+ rack
58
+ rainbow (1.1.4)
59
+ rake (10.0.4)
60
+ rdoc (4.0.1)
61
+ json (~> 1.4)
62
+ rspec (2.13.0)
63
+ rspec-core (~> 2.13.0)
64
+ rspec-expectations (~> 2.13.0)
65
+ rspec-mocks (~> 2.13.0)
66
+ rspec-core (2.13.1)
67
+ rspec-expectations (2.13.0)
68
+ diff-lcs (>= 1.1.3, < 2.0)
69
+ rspec-mocks (2.13.1)
70
+ rubyforge (2.0.4)
71
+ json_pure (>= 1.1.7)
72
+ rubyzip (0.9.9)
73
+ sass (3.2.8)
74
+ selenium-webdriver (2.32.1)
75
+ childprocess (>= 0.2.5)
76
+ multi_json (~> 1.0)
77
+ rubyzip
78
+ websocket (~> 1.0.4)
79
+ sinatra (1.4.2)
80
+ rack (~> 1.5, >= 1.5.2)
81
+ rack-protection (~> 1.4)
82
+ tilt (~> 1.3, >= 1.3.4)
83
+ sprockets (2.9.3)
84
+ hike (~> 1.2)
85
+ multi_json (~> 1.0)
86
+ rack (~> 1.0)
87
+ tilt (~> 1.1, != 1.3.0)
88
+ tilt (1.3.7)
89
+ websocket (1.0.7)
90
+
91
+ PLATFORMS
92
+ ruby
93
+
94
+ DEPENDENCIES
95
+ cronus!
96
+ echoe
97
+ jasmine
98
+ jasmine-headless-webkit
99
+ keystone!
100
+ rake
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Tim Shelburne
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,42 @@
1
+ CHANGELOG
2
+ Gemfile
3
+ Gemfile.lock
4
+ LICENSE
5
+ Manifest
6
+ README.rdoc
7
+ Rakefile
8
+ assets/scripts/coffee/hoarder/form/form.coffee
9
+ assets/scripts/coffee/hoarder/form/form_element.coffee
10
+ assets/scripts/coffee/hoarder/form_manager.coffee
11
+ assets/scripts/coffee/hoarder/submitter/form_submitter.coffee
12
+ assets/scripts/coffee/hoarder/submitter/submitters/polling_submitter.coffee
13
+ assets/scripts/coffee/hoarder/submitter/submitters/simple_submitter.coffee
14
+ assets/scripts/coffee/hoarder/validator/constraints/alpha_constraint.coffee
15
+ assets/scripts/coffee/hoarder/validator/constraints/alphanumeric_constraint.coffee
16
+ assets/scripts/coffee/hoarder/validator/constraints/credit_card_constraint.coffee
17
+ assets/scripts/coffee/hoarder/validator/constraints/email_constraint.coffee
18
+ assets/scripts/coffee/hoarder/validator/constraints/max_length_constraint.coffee
19
+ assets/scripts/coffee/hoarder/validator/constraints/min_length_constraint.coffee
20
+ assets/scripts/coffee/hoarder/validator/constraints/numeric_constraint.coffee
21
+ assets/scripts/coffee/hoarder/validator/constraints/phone_constraint.coffee
22
+ assets/scripts/coffee/hoarder/validator/constraints/required_constraint.coffee
23
+ assets/scripts/coffee/hoarder/validator/error/validation_error.coffee
24
+ assets/scripts/coffee/hoarder/validator/form_validator.coffee
25
+ assets/scripts/js/lib/jquery.js
26
+ bin/hoarder.js
27
+ config/assets.rb
28
+ lib/hoarder.rb
29
+ lib/hoarder/symbols.rb
30
+ spec/jasmine.yml
31
+ spec/runner.html
32
+ spec/support/classes.coffee
33
+ spec/support/helpers.coffee
34
+ spec/support/mocks.coffee
35
+ spec/support/objects.coffee
36
+ spec/support/requirements.coffee
37
+ spec/tests/form_manager_spec.coffee
38
+ spec/tests/submitter/form_submitter_spec.coffee
39
+ spec/tests/submitter/submitters/polling_submitter_spec.coffee
40
+ spec/tests/submitter/submitters/simple_submitter_spec.coffee
41
+ spec/tests/validator/constraints_spec.coffee
42
+ spec/tests/validator/form_validator_spec.coffee
File without changes
@@ -0,0 +1,38 @@
1
+ $: << File.expand_path("#{File.dirname(__FILE__)}/lib")
2
+
3
+ require 'hoarder'
4
+ require 'cronus'
5
+
6
+ require 'rake'
7
+ require 'jasmine-headless-webkit'
8
+ require 'keystone'
9
+ require 'echoe'
10
+
11
+ Echoe.new("hoarder-js") do |p|
12
+ p.author = "Tim Shelburne"
13
+ p.email = "shelburt02@gmail.com"
14
+ p.url = "https://github.com/tshelburne/hoarder-js"
15
+
16
+ p.ignore_pattern = FileList[".gitignore"]
17
+ p.development_dependencies = [ "jasmine", "jasmine-headless-webkit" ]
18
+ end
19
+
20
+ desc "Default"
21
+ task default: :'test:jasmine'
22
+
23
+ namespace :test do
24
+
25
+ desc "Run Jasmine tests"
26
+ Jasmine::Headless::Task.new(jasmine: :assets) do |t|
27
+ t.colors = true
28
+ t.keep_on_error = true
29
+ t.jasmine_config = './spec/jasmine.yml'
30
+ end
31
+
32
+ end
33
+
34
+ desc "Build assets"
35
+ Keystone::RakeTask.new :assets do |t|
36
+ t.config_file = "config/assets.rb"
37
+ t.output_path = 'bin'
38
+ end
@@ -0,0 +1,48 @@
1
+ require "lib/jquery"
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
+ 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()
47
+
48
+ return Form
@@ -0,0 +1,22 @@
1
+ require "lib/jquery"
2
+
3
+ #
4
+ # @author - Tim Shelburne <tim@musiconelive.com>
5
+ #
6
+ # represents a single element in a form
7
+ #
8
+ class FormElement
9
+ constructor: (@name, @value, @selector, @validationRules = [])->
10
+
11
+ addError: (error)->
12
+ $(@selector).closest("li").addClass("invalid")
13
+ $(@selector).closest("li").find("aside.tooltip").html(error.message)
14
+ $(@selector).focus -> $(this).closest("li").addClass("focused")
15
+ $(@selector).blur -> $(this).closest("li").removeClass("focused")
16
+
17
+ clearError: ->
18
+ $(@selector).closest("li").removeClass("invalid")
19
+ $(@selector).closest("li").find("aside.tooltip").html("")
20
+ $(@selector).unbind("focus").unbind("blur")
21
+
22
+ return FormElement
@@ -0,0 +1,32 @@
1
+ Signal = require "cronus/signal"
2
+ SignalRelay = require "cronus/signal_relay"
3
+
4
+ FormSubmitter = require 'hoarder/submitter/form_submitter'
5
+ FormValidator = require 'hoarder/validator/form_validator'
6
+
7
+ #
8
+ # @author - Tim Shelburne <tim@musiconelive.com>
9
+ #
10
+ # abstracts submitting and validating forms from the validator and submitter
11
+ #
12
+ class FormManager
13
+ constructor: (@formSubmitter, @formValidator)->
14
+ @validatedWithErrors = new Signal()
15
+ @submittedWithSuccess = new SignalRelay(@formSubmitter.submittedWithSuccess)
16
+ @submittedWithError = new SignalRelay(@formSubmitter.submittedWithError)
17
+
18
+ @default: (pollingUrl="")->
19
+ new @(FormSubmitter.default(pollingUrl), FormValidator.default())
20
+
21
+ validateForm: (form)->
22
+ @formValidator.validateForm(form)
23
+
24
+ submitForm: (form)->
25
+ errors = @validateForm(form)
26
+
27
+ if (errors.length > 0)
28
+ @validatedWithErrors.dispatch(errors)
29
+ else
30
+ @formSubmitter.submitForm(form)
31
+
32
+ return FormManager
@@ -0,0 +1,29 @@
1
+ MultiSignalRelay = require "cronus/multi_signal_relay"
2
+
3
+ SimpleSubmitter = require "hoarder/submitter/submitters/simple_submitter"
4
+ PollingSubmitter = require "hoarder/submitter/submitters/polling_submitter"
5
+
6
+ #
7
+ # @author - Tim Shelburne <tim@musiconelive.com>
8
+ #
9
+ # a class to handle submitting forms
10
+ #
11
+ class FormSubmitter
12
+ constructor: (@submitters)->
13
+ successSignals = []
14
+ errorSignals = []
15
+ for submitter in @submitters
16
+ successSignals.push submitter.submittedWithSuccess
17
+ errorSignals.push submitter.submittedWithError
18
+
19
+ @submittedWithSuccess = new MultiSignalRelay(successSignals)
20
+ @submittedWithError = new MultiSignalRelay(errorSignals)
21
+
22
+ @default: (pollingUrl)->
23
+ new @([ new SimpleSubmitter(), new PollingSubmitter(pollingUrl, 1000)])
24
+
25
+ submitForm: (form)->
26
+ for submitter in @submitters
27
+ submitter.submitForm(form) if submitter.canSubmit(form)
28
+
29
+ return FormSubmitter
@@ -0,0 +1,36 @@
1
+ SimpleSubmitter = require "hoarder/submitter/submitters/simple_submitter"
2
+
3
+ #
4
+ # @author - Tim Shelburne <tim@musiconelive.com>
5
+ #
6
+ # handles executing a delayed
7
+ #
8
+ class PollingSubmitter extends SimpleSubmitter
9
+ constructor: (@pollUrl, @pollFrequency)->
10
+ super()
11
+
12
+ canSubmit: (form)-> form.type is "polling"
13
+
14
+ submitSuccess: (form, data)->
15
+ @interval = setInterval( =>
16
+ @queryPoll(form, data.pollId)
17
+ , @pollFrequency)
18
+ @queryPoll(form, data.pollId)
19
+
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
+
30
+ pollSuccess: (form, pollId, data)=>
31
+ @executing = false
32
+ if data.pollCompleted
33
+ clearInterval(@interval)
34
+ @submittedWithSuccess.dispatch(form, data.pollData)
35
+
36
+ return PollingSubmitter
@@ -0,0 +1,30 @@
1
+ require "lib/jquery"
2
+
3
+ Signal = require "cronus/signal"
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()
14
+
15
+ canSubmit: (form)-> form.type is "simple"
16
+
17
+ submitForm: (form)->
18
+ $.ajax
19
+ url: form.action
20
+ type: form.method
21
+ 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)
29
+
30
+ return SimpleSubmitter
@@ -0,0 +1,18 @@
1
+ ValidationError = require "hoarder/validator/error/validation_error"
2
+
3
+ #
4
+ # @author - Tim Shelburne <tim@musiconelive.com>
5
+ #
6
+ #
7
+ #
8
+ class AlphaConstraint
9
+ canHandle: (type)->
10
+ type is "alpha"
11
+
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)." ]
17
+
18
+ return AlphaConstraint