joosy 0.1.0.RC1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/.gitignore +5 -0
  2. data/Gemfile +14 -0
  3. data/Gemfile.lock +159 -0
  4. data/Guardfile +30 -0
  5. data/MIT-LICENSE +21 -0
  6. data/README.rdoc +3 -0
  7. data/Rakefile +14 -0
  8. data/app/assets/javascripts/joosy.js.coffee +7 -0
  9. data/app/assets/javascripts/joosy/core/application.js.coffee +28 -0
  10. data/app/assets/javascripts/joosy/core/form.js.coffee +87 -0
  11. data/app/assets/javascripts/joosy/core/helpers.js.coffee +6 -0
  12. data/app/assets/javascripts/joosy/core/joosy.js.coffee +65 -0
  13. data/app/assets/javascripts/joosy/core/layout.js.coffee +47 -0
  14. data/app/assets/javascripts/joosy/core/modules/container.js.coffee +59 -0
  15. data/app/assets/javascripts/joosy/core/modules/events.js.coffee +35 -0
  16. data/app/assets/javascripts/joosy/core/modules/filters.js.coffee +39 -0
  17. data/app/assets/javascripts/joosy/core/modules/log.js.coffee +15 -0
  18. data/app/assets/javascripts/joosy/core/modules/module.js.coffee +43 -0
  19. data/app/assets/javascripts/joosy/core/modules/renderer.js.coffee +116 -0
  20. data/app/assets/javascripts/joosy/core/modules/time_manager.js.coffee +25 -0
  21. data/app/assets/javascripts/joosy/core/modules/widgets_manager.js.coffee +58 -0
  22. data/app/assets/javascripts/joosy/core/page.js.coffee +156 -0
  23. data/app/assets/javascripts/joosy/core/preloader.js.coffee +5 -0
  24. data/app/assets/javascripts/joosy/core/resource/generic.js.coffee +61 -0
  25. data/app/assets/javascripts/joosy/core/resource/rest.js.coffee +76 -0
  26. data/app/assets/javascripts/joosy/core/resource/rest_collection.js.coffee +48 -0
  27. data/app/assets/javascripts/joosy/core/router.js.coffee +89 -0
  28. data/app/assets/javascripts/joosy/core/templaters/rails_jst.js.coffee +20 -0
  29. data/app/assets/javascripts/joosy/core/widget.js.coffee +41 -0
  30. data/app/assets/javascripts/joosy/preloaders/caching.js.coffee +94 -0
  31. data/app/assets/javascripts/joosy/preloaders/inline.js.coffee +55 -0
  32. data/app/helpers/joosy/sprockets_helper.rb +23 -0
  33. data/app/views/layouts/json_wrapper.json.erb +1 -0
  34. data/joosy.gemspec +25 -0
  35. data/lib/joosy.rb +9 -0
  36. data/lib/joosy/forms.rb +47 -0
  37. data/lib/joosy/rails/engine.rb +17 -0
  38. data/lib/joosy/rails/version.rb +5 -0
  39. data/lib/rails/generators/joosy/application_generator.rb +41 -0
  40. data/lib/rails/generators/joosy/joosy_base.rb +30 -0
  41. data/lib/rails/generators/joosy/layout_generator.rb +32 -0
  42. data/lib/rails/generators/joosy/page_generator.rb +44 -0
  43. data/lib/rails/generators/joosy/preloader_generator.rb +32 -0
  44. data/lib/rails/generators/joosy/resource_generator.rb +29 -0
  45. data/lib/rails/generators/joosy/templates/app.js.coffee +10 -0
  46. data/lib/rails/generators/joosy/templates/app/helpers/application.js.coffee +4 -0
  47. data/lib/rails/generators/joosy/templates/app/layouts/application.js.coffee +2 -0
  48. data/lib/rails/generators/joosy/templates/app/layouts/template.js.coffee +2 -0
  49. data/lib/rails/generators/joosy/templates/app/pages/application.js.coffee +1 -0
  50. data/lib/rails/generators/joosy/templates/app/pages/template.js.coffee +5 -0
  51. data/lib/rails/generators/joosy/templates/app/pages/welcome/index.js.coffee +22 -0
  52. data/lib/rails/generators/joosy/templates/app/resources/template.js.coffee +2 -0
  53. data/lib/rails/generators/joosy/templates/app/routes.js.coffee +8 -0
  54. data/lib/rails/generators/joosy/templates/app/templates/layouts/application.jst.hamlc +2 -0
  55. data/lib/rails/generators/joosy/templates/app/templates/pages/welcome/index.jst.hamlc +7 -0
  56. data/lib/rails/generators/joosy/templates/app/widgets/template.js.coffee +2 -0
  57. data/lib/rails/generators/joosy/templates/app_controller.rb +9 -0
  58. data/lib/rails/generators/joosy/templates/app_preloader.js.coffee.erb +13 -0
  59. data/lib/rails/generators/joosy/templates/preload.html.erb +26 -0
  60. data/lib/rails/generators/joosy/templates/preload.html.haml +19 -0
  61. data/lib/rails/generators/joosy/widget_generator.rb +32 -0
  62. data/spec/javascripts/helpers/spec_helper.js.coffee +44 -0
  63. data/spec/javascripts/joosy/core/application_spec.js.coffee +40 -0
  64. data/spec/javascripts/joosy/core/form_spec.js.coffee +141 -0
  65. data/spec/javascripts/joosy/core/joosy_spec.js.coffee +72 -0
  66. data/spec/javascripts/joosy/core/layout_spec.js.coffee +50 -0
  67. data/spec/javascripts/joosy/core/modules/container_spec.js.coffee +92 -0
  68. data/spec/javascripts/joosy/core/modules/events_spec.js.coffee +53 -0
  69. data/spec/javascripts/joosy/core/modules/filters_spec.js.coffee +71 -0
  70. data/spec/javascripts/joosy/core/modules/log_spec.js.coffee +15 -0
  71. data/spec/javascripts/joosy/core/modules/module_spec.js.coffee +47 -0
  72. data/spec/javascripts/joosy/core/modules/renderer_spec.js.coffee +149 -0
  73. data/spec/javascripts/joosy/core/modules/time_manager_spec.js.coffee +25 -0
  74. data/spec/javascripts/joosy/core/modules/widget_manager_spec.js.coffee +75 -0
  75. data/spec/javascripts/joosy/core/page_spec.js.coffee +175 -0
  76. data/spec/javascripts/joosy/core/resource/generic_spec.js.coffee +35 -0
  77. data/spec/javascripts/joosy/core/resource/rest_collection_spec.js.coffee +65 -0
  78. data/spec/javascripts/joosy/core/resource/rest_spec.js.coffee +108 -0
  79. data/spec/javascripts/joosy/core/router_spec.js.coffee +123 -0
  80. data/spec/javascripts/joosy/core/templaters/rails_jst_spec.js.coffee +25 -0
  81. data/spec/javascripts/joosy/core/widget_spec.js.coffee +51 -0
  82. data/spec/javascripts/joosy/preloaders/caching_spec.js.coffee +36 -0
  83. data/spec/javascripts/joosy/preloaders/inline_spec.js.coffee +16 -0
  84. data/spec/javascripts/support/assets/coolface.jpg +0 -0
  85. data/spec/javascripts/support/assets/okay.jpg +0 -0
  86. data/spec/javascripts/support/assets/test.js +1 -0
  87. data/spec/javascripts/support/jasmine.yml +74 -0
  88. data/spec/javascripts/support/jasmine_config.rb +23 -0
  89. data/spec/javascripts/support/jasmine_runner.rb +32 -0
  90. data/spec/javascripts/support/sinon-1.3.1.js +3469 -0
  91. data/spec/javascripts/support/sinon-ie-1.3.1.js +82 -0
  92. data/vendor/assets/javascripts/base64.js +135 -0
  93. data/vendor/assets/javascripts/inflection.js +656 -0
  94. data/vendor/assets/javascripts/jquery.form.js +980 -0
  95. data/vendor/assets/javascripts/jquery.hashchange.js +390 -0
  96. data/vendor/assets/javascripts/metamorph.js +409 -0
  97. data/vendor/assets/javascripts/sugar.js +6040 -0
  98. metadata +232 -0
@@ -0,0 +1,32 @@
1
+ require 'rails/generators/named_base'
2
+
3
+ module Joosy
4
+ module Generators
5
+ class PreloaderGenerator < ::Rails::Generators::NamedBase
6
+ class_option :template_engine, :type => :string,
7
+ :desc => "Generate templates for specified engine."
8
+
9
+ source_root File.join(File.dirname(__FILE__), 'templates')
10
+
11
+ def create_preloader_files
12
+ unless class_path.empty?
13
+ puts <<HELP
14
+ Usage: rails generate joosy:preloader joosy_app_name
15
+ HELP
16
+ exit 1
17
+ end
18
+
19
+ template "app_preloader.js.coffee.erb", "app/assets/javascripts/#{file_name}_preloader.js.coffee.erb"
20
+
21
+ empty_directory "app/controllers"
22
+ template "app_controller.rb", "app/controllers/#{file_name}_controller.rb"
23
+
24
+ empty_directory "app/views/layouts"
25
+ template "preload.html.#{options[:template_engine]}",
26
+ "app/views/layouts/#{file_name}.html.#{options[:template_engine]}"
27
+
28
+ route "match '#{file_name}' => '#{file_name}#index'"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ require 'rails/generators/joosy/joosy_base'
2
+
3
+ module Joosy
4
+ module Generators
5
+ class ResourceGenerator < ::Rails::Generators::JoosyBase
6
+ source_root File.join(File.dirname(__FILE__), 'templates')
7
+
8
+ def create_files
9
+ super
10
+
11
+ empty_directory "#{app_path}/resources"
12
+ template "app/resources/template.js.coffee", "#{app_path}/resources/#{file_name}.js.coffee"
13
+ end
14
+
15
+ protected
16
+
17
+ def app_path
18
+ unless class_path.size == 1
19
+ puts <<HELP
20
+ Usage: rails generate joosy:resource joosy_app_name/resource_name
21
+ Tip: resource_name is better to be singular
22
+ HELP
23
+ exit 1
24
+ end
25
+ class_path[0]
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,10 @@
1
+ #= require hamlcoffee
2
+ #= require joosy
3
+ #
4
+ #= require_tree ./<%= file_name %>/helpers
5
+ #= require_tree ./<%= file_name %>/templates
6
+ #= require_tree ./<%= file_name %>/resources
7
+ #= require_tree ./<%= file_name %>/widgets
8
+ #= require_tree ./<%= file_name %>/layouts
9
+ #= require_tree ./<%= file_name %>/pages
10
+ #= require_tree ./<%= file_name %>
@@ -0,0 +1,4 @@
1
+ Joosy.helpers 'Application', ->
2
+
3
+ # helloWorld = (name) ->
4
+ # "Hello World, #{name}"
@@ -0,0 +1,2 @@
1
+ class @ApplicationLayout extends Joosy.Layout
2
+ @view 'application'
@@ -0,0 +1,2 @@
1
+ class @<%= file_name.camelize %>Layout extends ApplicationLayout
2
+ @view '<%= file_name %>'
@@ -0,0 +1 @@
1
+ class @ApplicationPage extends Joosy.Page
@@ -0,0 +1,5 @@
1
+ Joosy.namespace '<%= namespace_name %>', ->
2
+
3
+ class @<%= file_name.camelize %>Page extends ApplicationPage
4
+ @layout <%= layout_name.camelize %>Layout
5
+ @view '<%= file_name %>'
@@ -0,0 +1,22 @@
1
+ Joosy.namespace 'Welcome', ->
2
+
3
+ class @IndexPage extends ApplicationPage
4
+ @layout ApplicationLayout
5
+ @view 'index'
6
+
7
+ @afterLoad ->
8
+ @startHeartbeat()
9
+ @content.css
10
+ 'padding-top': "#{$(window).height() / 2 - 160}px"
11
+
12
+ elements:
13
+ content: '#content'
14
+ joosy: '.joosy'
15
+
16
+ events:
17
+ 'mouseover $joosy': -> clearInterval @heartbeat
18
+ 'mouseout $joosy': 'startHeartbeat'
19
+
20
+ startHeartbeat: ->
21
+ @heartbeat = @setInterval 1500, =>
22
+ @joosy.animate({opacity: 0.8}, 300).animate({opacity: 1}, 300)
@@ -0,0 +1,2 @@
1
+ class @<%= file_name.camelize %>Resource extends Joosy.Resource.REST
2
+ @entity '<%= file_name %>'
@@ -0,0 +1,8 @@
1
+ Joosy.Router.map
2
+ 404 : (path) -> alert "Page '#{path}' was not found :("
3
+ '/' : Welcome.IndexPage
4
+ # '/resources' :
5
+ # '/' : Resource.IndexPage
6
+ # '/:id' : Resource.ShowPage
7
+ # '/:id/edit' : Resource.EditPage
8
+ # '/new' : Resource.EditPage
@@ -0,0 +1,2 @@
1
+ #page{:style => 'font-family: "Lucida Grande", "Verdana"; text-align: center'}
2
+ .content{:id => @yield()}
@@ -0,0 +1,7 @@
1
+ #wrapper
2
+ #content
3
+ %h1 Welcome aboard
4
+ %h2{:style => 'margin-bottom: 30px'} You’re still riding Ruby on Rails.
5
+ .joosy{:style => 'background: #F71; border-radius: 10px; width: 250px; display: inline-block'}
6
+ %div{:style => 'color: #FFF; padding: 10px;'}
7
+ But it's so joosy this time!
@@ -0,0 +1,2 @@
1
+ class @<%= file_name.camelize %>Widget extends Joosy.Widget
2
+ @view '<%= file_name %>'
@@ -0,0 +1,9 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>Controller < ApplicationController
3
+ helper 'joosy/sprockets'
4
+
5
+ def index
6
+ render nothing: true, layout: '<%= file_path %>'
7
+ end
8
+ end
9
+ <% end -%>
@@ -0,0 +1,13 @@
1
+ <%= "<%= require_joosy_preloader_for '" %><%= file_name %><%= "', preloader: 'caching', force: false %" + ">" %>
2
+
3
+ bootstrap = ->
4
+ $('#preloader').remove()
5
+ Joosy.Application.initialize '<%= file_name %>','#application',
6
+ environment: window.joosy.environment
7
+ debug: false
8
+
9
+ window.onload = ->
10
+ Preloader.load window.joosy.libraries,
11
+ complete: bootstrap
12
+ start: -> document.getElementById('preloader').style.display = 'block'
13
+ progress: (percent) -> document.getElementById('percents').innerHTML = percent + '%'
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title><%= file_path %></title>
5
+
6
+ <script type="text/javascript">
7
+ window.joosy = {
8
+ libraries: <%= "<%= extract_sources_and_sizes_from_include_tag('#{file_path}') %"+">" %>,
9
+ environment: '<%= "<%= Rails.env.to_s %"+">" %>'
10
+ };
11
+ </script>
12
+
13
+ <%= "<%= stylesheet_link_tag 'application' %"+">" %>
14
+ <%= "<%= csrf_meta_tags %"+">" %>
15
+ </head>
16
+
17
+ <body>
18
+ <%= "<%= javascript_include_tag '#{file_path}_preloader' %"+">" %>
19
+ <div id="application">
20
+ <div id="preloader">
21
+ Loading application...
22
+ <span id="percents">0%</span>
23
+ </div>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,19 @@
1
+ !!! 5
2
+ %html
3
+ %head
4
+ %title> <%= file_path %>
5
+
6
+ javascript:
7
+ window.preload = {
8
+ libraries: #{extract_sources_and_sizes_from_include_tag('<%= file_path %>')}
9
+ };
10
+
11
+ = stylesheet_link_tag 'application'
12
+ = csrf_meta_tags
13
+
14
+ %body
15
+ = javascript_include_tag '<%= file_path %>_preloader'
16
+ #application
17
+ #preloader
18
+ Loading application...
19
+ %span#percents 0%
@@ -0,0 +1,32 @@
1
+ require 'rails/generators/joosy/joosy_base'
2
+
3
+ module Joosy
4
+ module Generators
5
+ class WidgetGenerator < ::Rails::Generators::JoosyBase
6
+ source_root File.join(File.dirname(__FILE__), 'templates')
7
+
8
+ def create_files
9
+ super
10
+
11
+ empty_directory "#{app_path}/widgets"
12
+ template "app/widgets/template.js.coffee", "#{app_path}/widgets/#{file_name}.js.coffee"
13
+
14
+ empty_directory "#{app_path}/templates/widgets"
15
+ create_file "#{app_path}/templates/widgets/#{file_name}.jst.#{options[:template_kind]}"
16
+ end
17
+
18
+ protected
19
+
20
+ def app_path
21
+ unless class_path.size == 1
22
+ puts <<HELP
23
+ Usage: rails generate joosy:widget joosy_app_name/widget_name
24
+ Tip: do not add Widget suffix to widget_name
25
+ HELP
26
+ exit 1
27
+ end
28
+ class_path[0]
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,44 @@
1
+ beforeEach ->
2
+ window.JST = {}
3
+ $('body').append('<div id="ground">')
4
+ @ground = $('body #ground')
5
+ @seedGround = ->
6
+ @ground.html('
7
+ <div id="application" class="application">
8
+ <div id="header" class="header" />
9
+ <div id="wrapper" class="wrapper">
10
+ <div id="content" class="content">
11
+ <div id="post1" class="post" />
12
+ <div id="post2" class="post" />
13
+ <div id="post3" class="post" />
14
+ </div>
15
+ <div id="sidebar" class="sidebar">
16
+ <div id="widget1" class="widget" />
17
+ <div id="widget2" class="widget" />
18
+ </div>
19
+ </div>
20
+ <div id="footer" class="footer" />
21
+ </div>
22
+ ')
23
+ @addMatchers
24
+ toBeSequenced: () ->
25
+ if !Object.isArray(@actual) || @actual.length == 0
26
+ console.log 'toBeSequenced: not array or empty array given'
27
+ return false
28
+ i = 0
29
+ for spy in @actual
30
+ unless spy.callCount == 1
31
+ console.log "toBeSequenced: spy ##{i} was called #{spy.callCount} times"
32
+ return false
33
+ i++
34
+ if @actual.length > 1
35
+ for spy in @actual.from(1)
36
+ i = @actual.indexOf spy
37
+ previous = @actual[i - 1]
38
+ unless spy.calledAfter previous
39
+ console.log "toBeSequenced: spy ##{i} wasn't called after spy ##{i - 1}"
40
+ return false
41
+ return true
42
+
43
+ afterEach ->
44
+ @ground.remove() unless @polluteGround
@@ -0,0 +1,40 @@
1
+ describe "Joosy.Application", ->
2
+
3
+ beforeEach ->
4
+ sinon.stub(Joosy.Router, "setupRoutes")
5
+ @seedGround()
6
+
7
+ afterEach ->
8
+ Joosy.Router.setupRoutes.restore()
9
+
10
+ it "should initialize", ->
11
+ Joosy.Application.initialize 'app', '#application'
12
+ expect(Joosy.Application.page).toBeUndefined()
13
+ expect(Joosy.Application.selector).toEqual '#application'
14
+ expect(Joosy.Application.sandboxSelector).toMatch /#[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}/
15
+ expect($(Joosy.Application.sandboxSelector).length).toEqual 1
16
+ expect(Joosy.Router.setupRoutes.callCount).toEqual 1
17
+ expect(Joosy.Application.name).toEqual 'app'
18
+
19
+ it "should set container", ->
20
+ expect(Joosy.Application.content()).toEqual $('#application')
21
+
22
+ it "should properly initialize and save pages", ->
23
+ spy = sinon.spy()
24
+ class Page1
25
+ constructor: spy
26
+ class Page2
27
+ constructor: spy
28
+
29
+ Joosy.Application.setCurrentPage(Page1, {foo: 'bar'})
30
+
31
+ expect(Joosy.Application.page instanceof Page1).toBeTruthy()
32
+ expect(spy.callCount).toEqual 1
33
+ expect(spy.args[0]).toEqual [{foo: 'bar'}, undefined]
34
+
35
+ Joosy.Application.setCurrentPage(Page2, {bar: 'baz'})
36
+
37
+ expect(Joosy.Application.page instanceof Page2).toBeTruthy()
38
+ expect(spy.callCount).toEqual 2
39
+ expect(spy.args[1][0]).toEqual {bar: 'baz'}
40
+ expect(spy.args[1][1] instanceof Page1).toBeTruthy()
@@ -0,0 +1,141 @@
1
+ describe "Joosy.Form", ->
2
+
3
+ beforeEach ->
4
+ @server = sinon.fakeServer.create()
5
+ @seedGround()
6
+ @nudeForm = "<form id='nude'><input name='test[foo]'/><input name='test[bar]'/></form>"
7
+ @putForm = "<form id='put' method='put'><input name='test[camel_baz]'/></form>"
8
+ @moreForm = "<form id='more' method='put'><input name='test[ololo]'/></form>"
9
+
10
+ @ground.find('#sidebar').after(@nudeForm).after(@putForm).after(@moreForm)
11
+
12
+ @nudeForm = $('#nude')
13
+ @putForm = $('#put')
14
+ @moreForm = $('#more')
15
+
16
+ class Test extends Joosy.Resource.REST
17
+ @entity 'test'
18
+
19
+ @resource = Test.create
20
+ foo: 'foo',
21
+ bar: 'bar'
22
+ camelBaz: 'baz'
23
+
24
+ afterEach ->
25
+ @server.restore()
26
+
27
+ describe "Initialization", ->
28
+
29
+ beforeEach ->
30
+ @spy = sinon.spy $.fn, 'ajaxForm'
31
+
32
+ afterEach ->
33
+ @spy.restore()
34
+
35
+ it "should properly act with options", ->
36
+ formWithProperties = new Joosy.Form @nudeForm, invalidationClass: 'fluffy'
37
+ expect(formWithProperties.container).toEqual @nudeForm
38
+ expect(formWithProperties.invalidationClass).toEqual 'fluffy'
39
+ expect(formWithProperties.fields.length).toEqual 2
40
+
41
+ expect(@spy.callCount).toEqual 1
42
+
43
+ it "should properly act with callback", ->
44
+ formWithCallback = new Joosy.Form @putForm, callback=sinon.spy()
45
+ expect(formWithCallback.container).toEqual @putForm
46
+ expect(formWithCallback.invalidationClass).toEqual 'field_with_errors'
47
+ expect(formWithCallback.success).toBe callback
48
+ expect(formWithCallback.fields.length).toEqual 1
49
+
50
+ expect(@spy.callCount).toEqual 1
51
+
52
+ it "should hijack form method if it differs from POST/GET", ->
53
+ form = new Joosy.Form @putForm, callback=sinon.spy()
54
+ marker = @putForm.find "input[type=hidden]"
55
+ expect(@putForm.attr('method')?.toLowerCase()).toEqual 'post'
56
+ expect(marker.attr 'name').toEqual '_method'
57
+ expect(marker.attr 'value').toEqual 'put'
58
+
59
+ describe "Filling", ->
60
+
61
+ beforeEach ->
62
+ @nudeForm = new Joosy.Form @nudeForm
63
+ @putForm = new Joosy.Form @putForm
64
+ @moreForm = new Joosy.Form @moreForm
65
+
66
+ it "should fill form and set propert action and method", ->
67
+ @nudeForm.fill @resource
68
+ expect(@nudeForm.fields[0].value).toEqual 'foo'
69
+ expect(@nudeForm.fields[1].value).toEqual 'bar'
70
+ expect(@nudeForm.container.attr('method').toLowerCase()).toEqual 'post'
71
+ expect(@nudeForm.container.attr 'action').toEqual '/tests/'
72
+
73
+ it "should fill form with camelized properties", ->
74
+ @putForm.fill @resource
75
+ expect(@putForm.fields[0].value).toEqual 'baz'
76
+ expect(@putForm.container.attr('method').toLowerCase()).toEqual 'post'
77
+ expect(@putForm.container.attr 'action').toEqual '/tests/'
78
+
79
+ it "should fill form with decorator", ->
80
+ @moreForm.fill @resource, (e) ->
81
+ e.ololo = e.camelBaz
82
+ e
83
+ expect(@moreForm.fields[0].value).toEqual 'baz'
84
+
85
+ describe "Callbacks", ->
86
+ beforeEach ->
87
+ @nudeForm = new Joosy.Form @nudeForm, @spy=sinon.spy()
88
+ @nudeForm.fill @resource
89
+ @nudeForm.container.submit()
90
+ @target = @server.requests.last()
91
+
92
+ it "should trigger 'success'", ->
93
+ expect(@target.method).toEqual 'POST'
94
+ expect(@target.url).toEqual '/tests/'
95
+ @target.respond 200, 'Content-Type': 'application/json', '{"form": "works"}'
96
+ expect(@spy.callCount).toEqual 1
97
+ expect(@spy.args[0][0]).toEqual {form: 'works'}
98
+
99
+ it "should fill class for invalidated fields by default", ->
100
+ @target.respond 422, 'Content-Type': 'application/json', '{"test[foo]": "error!"}'
101
+ expect($(@nudeForm.fields[0]).attr 'class').toEqual 'field_with_errors'
102
+
103
+ it "should trigger 'error' and complete default action if it returned true", ->
104
+ @nudeForm.error = sinon.spy ->
105
+ true
106
+ @target.respond 422, 'Content-Type': 'application/json', '{"test[foo]": "error!"}'
107
+ expect($(@nudeForm.fields[0]).attr 'class').toEqual 'field_with_errors'
108
+ expect(@nudeForm.error.callCount).toEqual 1
109
+ expect(@nudeForm.error.args[0][0]).toEqual Object.extended
110
+ "test[foo]": "error!"
111
+
112
+ it "should trigger 'error' and skip default action if it returned false", ->
113
+ @nudeForm.error = sinon.spy ->
114
+ false
115
+ @target.respond 422, 'Content-Type': 'application/json', '{"test[foo]": "error!"}'
116
+ expect($(@nudeForm.fields[0]).attr 'class').toNotEqual 'field_with_errors'
117
+ expect(@nudeForm.error.callCount).toEqual 1
118
+
119
+ it "should clear fields before another submit", ->
120
+ @target.respond 422, 'Content-Type': 'application/json', '{"test[foo]": "error!"}'
121
+ expect($(@nudeForm.fields[0]).attr 'class').toEqual 'field_with_errors'
122
+ @nudeForm.container.submit()
123
+ expect($(@nudeForm.fields[0]).attr 'class').toNotEqual 'field_with_errors'
124
+
125
+ it "should trigger 'before' and do default action if it returns true", ->
126
+ @target.respond 422, 'Content-Type': 'application/json', '{"test[foo]": "error!"}'
127
+ expect($(@nudeForm.fields[0]).attr 'class').toEqual 'field_with_errors'
128
+ @nudeForm.before = sinon.spy ->
129
+ true
130
+ @nudeForm.container.submit()
131
+ expect($(@nudeForm.fields[0]).attr 'class').toNotEqual 'field_with_errors'
132
+ expect(@nudeForm.before.callCount).toEqual 1
133
+
134
+ it "should trigger 'before' and skip default action if it returns false", ->
135
+ @target.respond 422, 'Content-Type': 'application/json', '{"test[foo]": "error!"}'
136
+ expect($(@nudeForm.fields[0]).attr 'class').toEqual 'field_with_errors'
137
+ @nudeForm.before = sinon.spy ->
138
+ false
139
+ @nudeForm.container.submit()
140
+ expect($(@nudeForm.fields[0]).attr 'class').toEqual 'field_with_errors'
141
+ expect(@nudeForm.before.callCount).toEqual 1