luca 0.7.0 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  module Luca
2
2
  module Rails
3
- VERSION = "0.7.0"
3
+ VERSION = "0.7.2"
4
4
  end
5
5
  end
6
6
 
@@ -1,13 +1,201 @@
1
1
  describe 'The Form View', ->
2
- describe 'Generating a form from a model', ->
3
- beforeEach ->
4
- Model = Backbone.Model.extend
5
- schema:
6
- field0: "hidden"
7
- field1: "text"
8
- field3: "boolean"
9
- field4: "blob"
10
- field5:
11
- collection: "sample"
12
-
13
- @model = new Model(field0:1,field1:"jonathan",field3:true,field4:"what up player?")
2
+ beforeEach ->
3
+ FormView = Luca.components.FormView.extend
4
+ components:[
5
+ ctype: 'hidden_field'
6
+ name: 'id'
7
+ ,
8
+
9
+ ctype: "text_field",
10
+ label: "Field Two"
11
+ name: "field2"
12
+ ,
13
+ ctype: "text_field",
14
+ label: "Field One"
15
+ name: "field1"
16
+ ,
17
+ ctype: "checkbox_field"
18
+ label: "Field Three"
19
+ name: "field3"
20
+ ,
21
+ name: "field4"
22
+ label: "Field Four"
23
+ ctype: "text_area_field"
24
+ ,
25
+ name: "field5"
26
+ ctype: "button_field"
27
+ label: "Click Me"
28
+ ]
29
+
30
+ Model = Backbone.Model.extend
31
+ schema:
32
+ field0: "hidden"
33
+ field2: "text"
34
+ field1: "text"
35
+ field3: "boolean"
36
+ field4: "blob"
37
+ field5:
38
+ collection: "sample"
39
+
40
+ @form = new FormView()
41
+ @model = new Model(field0:1,field1:"jonathan",field3:true,field4:"what up player?")
42
+
43
+ it "should create a form", ->
44
+ expect( @form ).toBeDefined()
45
+
46
+ it "should load the model", ->
47
+ @form.loadModel(@model)
48
+ expect( @form.currentModel() ).toEqual @model
49
+
50
+ it "should set the field values from the model when loaded", ->
51
+ @form.render()
52
+ @form.loadModel(@model)
53
+ values = @form.getValues()
54
+ expect( values.field1 ).toEqual "jonathan"
55
+
56
+ it "should render the components", ->
57
+ @form.render()
58
+ expect( @form.$el.html() ).toContain "Field Four"
59
+ expect( @form.$el.html() ).toContain "Field One"
60
+ expect( @form.$el.html() ).toContain "Click Me"
61
+
62
+ it "should allow me to set the values of the form fields with a hash", ->
63
+ @form.render()
64
+ @form.setValues(field1:"yes",field2:"no")
65
+ values = @form.getValues()
66
+
67
+ expect( values.field1 ).toEqual "yes"
68
+ expect( values.field2 ).toEqual "no"
69
+
70
+ it "should sync the model with the form field values", ->
71
+ @form.render()
72
+ @form.loadModel(@model)
73
+ @form.setValues(field1:"yes")
74
+ expect( @form.getValues().field1 ).toEqual "yes"
75
+
76
+ describe "Loading A New Model", ->
77
+ beforeEach ->
78
+ @form.spiedEvents = {}
79
+ @form.render()
80
+ @form.loadModel(@model)
81
+
82
+ it "should have triggered before load", ->
83
+ expect( @form ).toHaveTriggered("before:load")
84
+
85
+ it "should have triggered after load", ->
86
+ expect( @form ).toHaveTriggered("after:load")
87
+
88
+ it "should have triggered before:load:new", ->
89
+ expect( @form ).toHaveTriggered("before:load:new")
90
+
91
+ it "should have triggered after:load:new", ->
92
+ expect( @form ).toHaveTriggered("after:load:new")
93
+
94
+ describe "Loading An Existing Model", ->
95
+ beforeEach ->
96
+ @form.spiedEvents = {}
97
+ @form.render()
98
+ @model.set(id:"one")
99
+ @form.loadModel(@model)
100
+
101
+ it "should have triggered before:load:existing", ->
102
+ expect( @form ).toHaveTriggered("before:load:existing")
103
+
104
+ it "should have triggered after:load:new", ->
105
+ expect( @form ).toHaveTriggered("after:load:existing")
106
+
107
+ it "should apply the form values in the currentModel call if specified", ->
108
+ @form.getField("field1").setValue("sup baby?")
109
+ expect( @form.currentModel().get("field1") ).not.toEqual("sup baby?")
110
+ @form.getField("field1").setValue("sup baby boo?")
111
+ expect( @form.currentModel(refresh:false).get("field1") ).not.toEqual("sup baby boo?")
112
+ expect( @form.currentModel(refresh:true).get("field1") ).toEqual("sup baby boo?")
113
+
114
+ describe "The Fields Accessors", ->
115
+ beforeEach ->
116
+ @form.render()
117
+
118
+ it "should provide access to fields", ->
119
+ expect( @form.getFields().length ).toEqual 6
120
+
121
+ it "should allow me to access a field by its name",->
122
+ expect( @form.getField("field1") ).toBeDefined()
123
+
124
+ describe "The Set Values Function", ->
125
+ beforeEach ->
126
+ @form.render()
127
+ @form.loadModel(@model)
128
+
129
+ it "should set the values on the field", ->
130
+ @form.setValues({field1:"andyadontstop"})
131
+ expect( @form.getField("field1").getValue() ).toEqual "andyadontstop"
132
+
133
+ it "should set the values on the model", ->
134
+ @form.setValues(field1:"krs-one")
135
+ expect( @form.getField("field1").getValue() ).toEqual "krs-one"
136
+ expect( @model.get("field1") ).toEqual "krs-one"
137
+
138
+ it "should skip syncing with the model if passed silent", ->
139
+ @form.setValues({field1:"yesyesyall"},silent:true)
140
+ expect( @form.getField("field1").getValue() ).toEqual "yesyesyall"
141
+ expect( @model.get("field1") ).not.toEqual "yesyesyall"
142
+
143
+ describe "The Get Values Function", ->
144
+ beforeEach ->
145
+ @model.set(field1:"one",field2:"two",field3:undefined,field4:"")
146
+ @form.render()
147
+ @form.loadModel(@model)
148
+ @values = @form.getValues()
149
+
150
+ it "should skip the button fields by default", ->
151
+ expect( _(@values).keys() ).not.toContain("field5")
152
+
153
+ it "should include the button fields if asked", ->
154
+ values = @form.getValues(skip_buttons:false)
155
+ expect( _(values).keys() ).toContain("field5")
156
+
157
+ it "should skip blank fields by default", ->
158
+ values = @form.getValues()
159
+ expect( _(values).keys() ).not.toContain("field4")
160
+
161
+ it "should include blank fields if asked", ->
162
+ values = @form.getValues(reject_blank:false)
163
+ expect( _(values).keys() ).toContain("field4")
164
+
165
+ it "should skip blank id fields", ->
166
+ expect( _(@values).keys() ).not.toContain("id")
167
+
168
+ describe "Events", ->
169
+ beforeEach ->
170
+ @form.render()
171
+ @form.loadModel(@model)
172
+
173
+ describe "Submit Handlers", ->
174
+ beforeEach ->
175
+ @form.spiedEvents = {}
176
+
177
+ it "should trigger after submit events", ->
178
+ @form.submit_success_handler(@model,success:true)
179
+ expect( @form ).toHaveTriggered("after:submit")
180
+ expect( @form ).toHaveTriggered("after:submit:success")
181
+
182
+ it "should trigger after submit error events", ->
183
+ @form.submit_success_handler(@model,success:false)
184
+ expect( @form ).toHaveTriggered("after:submit")
185
+ expect( @form ).toHaveTriggered("after:submit:error")
186
+
187
+ it "should trigger fatal error events", ->
188
+ @form.submit_fatal_error_handler()
189
+ expect( @form ).toHaveTriggered("after:submit")
190
+ expect( @form ).toHaveTriggered("after:submit:fatal_error")
191
+
192
+ describe "Resetting the Form", ->
193
+ it "should trigger before and after reset", ->
194
+ @form.resetHandler(currentTarget:1)
195
+ expect( @form ).toHaveTriggered "before:reset"
196
+ expect( @form ).toHaveTriggered "after:reset"
197
+
198
+ it "should call reset", ->
199
+ @form.reset = sinon.spy()
200
+ @form.resetHandler(currentTarget:1)
201
+ expect( @form.reset ).toHaveBeenCalled()
@@ -30,19 +30,44 @@ describe "The Luca Framework", ->
30
30
  expect(value).toEqual("haha")
31
31
 
32
32
  it "should create an instance of a class by ctype", ->
33
- object =
33
+ object =
34
34
  ctype: "template"
35
- template: "components/form_view"
35
+ template: "components/form_view"
36
36
 
37
37
  component = Luca.util.lazyComponent(object)
38
38
  expect( _.isFunction(component.render) ).toBeTruthy()
39
39
 
40
40
  it "should find a created view in the cache", ->
41
41
  template = new Luca.components.Template
42
- template: "components/form_view"
42
+ template: "components/form_view"
43
43
  name: 'test_template'
44
44
 
45
45
  expect(Luca.cache("test_template")).toBeDefined()
46
46
 
47
+ it "should detect if an object is probably a backbone view", ->
48
+ obj =
49
+ render: sinon.spy()
50
+ el: true
47
51
 
48
- describe
52
+ expect( Luca.isBackboneView(obj) ).toEqual true
53
+ expect( Luca.isBackboneView({}) ).toEqual false
54
+
55
+ it "should detect if an object is probably a backbone collection", ->
56
+ obj =
57
+ fetch: sinon.spy()
58
+ reset: sinon.spy()
59
+
60
+ expect( Luca.isBackboneCollection(obj) ).toEqual true
61
+ expect( Luca.isBackboneCollection({}) ).toEqual false
62
+
63
+ it "should detect if an object is probably a backbone model", ->
64
+ obj =
65
+ set: sinon.spy()
66
+ get: sinon.spy()
67
+ attributes: {}
68
+
69
+ expect( Luca.isBackboneModel(obj) ).toEqual true
70
+ expect( Luca.isBackboneModel({}) ).toEqual false
71
+
72
+
73
+ describe
@@ -1,4 +1,4 @@
1
- Luca.components.FormView = Luca.core.Container.extend
1
+ Luca.components.FormView = Luca.core.Container.extend
2
2
  tagName: 'form'
3
3
 
4
4
  className: 'luca-ui-form-view'
@@ -22,48 +22,48 @@ Luca.components.FormView = Luca.core.Container.extend
22
22
  events:
23
23
  "click .submit-button" : "submitHandler"
24
24
  "click .reset-button" : "resetHandler"
25
-
25
+
26
26
  toolbar: true
27
-
27
+
28
28
  initialize: (@options={})->
29
29
  Luca.core.Container::initialize.apply @, arguments
30
-
31
- _.bindAll @, "submitHandler", "resetHandler", "renderToolbars"
30
+
31
+ _.bindAll @, "submitHandler", "resetHandler", "renderToolbars"
32
32
 
33
33
  @state ||= new Backbone.Model
34
34
 
35
35
  @setupHooks( @hooks )
36
-
36
+
37
37
  @legend ||= ""
38
38
 
39
39
  @configureToolbars()
40
- @applyStyles()
40
+ @applyStyles()
41
41
 
42
42
  addBootstrapFormControls: ()->
43
43
  @bind "after:render", ()=>
44
44
  el = @$('.toolbar-container.bottom')
45
45
 
46
46
  el.addClass('form-controls')
47
- el.html @formControlsTemplate || Luca.templates["components/bootstrap_form_controls"](@)
47
+ el.html @formControlsTemplate || Luca.templates["components/bootstrap_form_controls"](@)
48
48
 
49
49
  applyStyles: ()->
50
50
  @applyBootstrapStyles() if Luca.enableBootstrap
51
51
 
52
52
  @$el.addClass( "label-align-#{ @labelAlign }") if @labelAlign
53
- @$el.addClass( @fieldLayoutClass ) if @fieldLayoutClass
53
+ @$el.addClass( @fieldLayoutClass ) if @fieldLayoutClass
54
54
 
55
55
  applyBootstrapStyles: ()->
56
56
  @inlineForm = true if @labelAlign is "left"
57
57
 
58
58
  @$el.addClass('well') if @well
59
- @$el.addClass('form-search') if @searchForm
60
- @$el.addClass('form-horizontal') if @horizontalForm
61
- @$el.addClass('form-inline') if @inlineForm
59
+ @$el.addClass('form-search') if @searchForm
60
+ @$el.addClass('form-horizontal') if @horizontalForm
61
+ @$el.addClass('form-inline') if @inlineForm
62
62
 
63
63
  configureToolbars: ()->
64
64
  return @addBootstrapFormControls() if Luca.enableBootstrap and @toolbar is true
65
65
 
66
- if @toolbar is true
66
+ if @toolbar is true
67
67
  @toolbars = [
68
68
  ctype: 'form_button_toolbar'
69
69
  includeReset: true
@@ -71,7 +71,7 @@ Luca.components.FormView = Luca.core.Container.extend
71
71
  ]
72
72
 
73
73
  if @toolbars and @toolbars.length
74
- @bind "after:render", _.once @renderToolbars
74
+ @bind "after:render", _.once @renderToolbars
75
75
 
76
76
  resetHandler: (e)->
77
77
  me = my = $( e.currentTarget )
@@ -83,17 +83,16 @@ Luca.components.FormView = Luca.core.Container.extend
83
83
  me = my = $( e.currentTarget )
84
84
  @trigger "before:submit", @
85
85
  @submit()
86
-
86
+
87
87
  beforeLayout: ()->
88
88
  Luca.core.Container::beforeLayout?.apply @, arguments
89
- @$el.html Luca.templates["components/form_view"]( @ )
90
-
89
+ @$el.html Luca.templates["components/form_view"]( @ )
91
90
 
92
91
  prepareComponents: ()->
93
92
  container = $('.form-view-body', @el)
94
93
  _( @components ).each (component)->
95
94
  component.container = container
96
-
95
+
97
96
  render: ()->
98
97
  $( @container ).append( @$el )
99
98
 
@@ -108,7 +107,7 @@ Luca.components.FormView = Luca.core.Container.extend
108
107
  toolbar.container = $("##{ @cid }-#{ toolbar.position }-toolbar-container")
109
108
  toolbar = Luca.util.lazyComponent(toolbar)
110
109
  toolbar.render()
111
-
110
+
112
111
  getField: (name)->
113
112
  _( @getFields('name', name) ).first()
114
113
 
@@ -131,74 +130,102 @@ Luca.components.FormView = Luca.core.Container.extend
131
130
  loadModel: (@current_model)->
132
131
  form = @
133
132
  fields = @getFields()
134
-
133
+
135
134
  @trigger "before:load", @, @current_model
136
135
  if @current_model
137
136
  event = "before:load:#{ (if @current_model.isNew() then "new" else "existing")}"
138
137
  @trigger event, @, @current_model
139
-
140
- _( fields ).each (field) =>
141
- field_name = field.input_name || field.name
142
- value = if _.isFunction(@current_model[ field_name ]) then @current_model[field_name].apply(@, form) else @current_model.get( field_name )
143
- field?.setValue( value ) unless field.readOnly is true
144
-
138
+
139
+ @setValues(@current_model)
140
+
145
141
  @trigger "after:load", @, @current_model
146
142
 
147
143
  if @current_model
148
144
  @trigger "after:load:#{ (if @current_model.isNew() then "new" else "existing")}", @, @current_model
149
-
150
-
151
- reset: ()->
145
+
146
+ reset: ()->
152
147
  @loadModel( @current_model )
153
148
 
154
149
  clear: ()->
155
150
  @current_model = if @defaultModel? then @defaultModel() else undefined
156
151
 
157
- _( @getFields() ).each (field)=>
152
+ _( @getFields() ).each (field)=>
158
153
  try
159
154
  field.setValue('')
160
155
  catch e
161
156
  console.log "Error Clearing", @, field
162
157
 
163
- getValues: (reject_blank=false,skip_buttons=true)->
158
+ # set the values on the form
159
+ # without syncing
160
+ setValues: (source, options={})->
161
+ source ||= @currentModel()
162
+ fields = @getFields()
163
+
164
+ _( fields ).each (field) =>
165
+ field_name = field.input_name || field.name
166
+
167
+ if value = source[field_name]
168
+ if _.isFunction(value)
169
+ value = value.apply(@)
170
+
171
+ if !value and Luca.isBackboneModel(source)
172
+ value = source.get(field_name)
173
+
174
+ field?.setValue( value ) unless field.readOnly is true
175
+
176
+ @syncFormWithModel() unless options.silent? is true
177
+
178
+ getValues: (options)->
179
+ options ||= {}
180
+
181
+ options.reject_blank = true unless options.reject_blank?
182
+ options.skip_buttons = true unless options.skip_buttons?
183
+
164
184
  _( @getFields() ).inject (memo,field)->
165
- value = field.getValue()
166
-
185
+ value = field.getValue()
186
+ key = field.input_name || field.name
187
+
167
188
  skip = false
168
- skip = true if skip_buttons and field.ctype is "button_field"
169
- skip = true if reject_blank and _.isBlank(value)
189
+ skip = true if options.skip_buttons and field.ctype is "button_field"
190
+ skip = true if options.reject_blank is true and _.isBlank(value)
170
191
  skip = true if field.input_name is "id" and _.isBlank(value)
171
192
 
172
- memo[ field.input_name || name ] = value unless skip
193
+ memo[ key ] = value unless skip is true
173
194
 
174
195
  memo
175
196
  , {}
176
-
197
+
177
198
  submit_success_handler: (model, response, xhr)->
178
199
  @trigger "after:submit", @, model, response
179
-
180
- if response and response.success
200
+
201
+ if response and response?.success is true
181
202
  @trigger "after:submit:success", @, model, response
182
203
  else
183
204
  @trigger "after:submit:error", @, model, response
184
205
 
185
- submit_fatal_error_handler: ()->
186
- @trigger.apply ["after:submit", @].concat(arguments)
187
- @trigger.apply ["after:submit:fatal_error", @].concat(arguments)
206
+ submit_fatal_error_handler: (model, response, xhr)->
207
+ @trigger "after:submit", @, model, response
208
+ @trigger "after:submit:fatal_error", @, model, response
188
209
 
189
- submit: (save=true, saveOptions={})->
210
+ submit: (save=true, saveOptions={})->
190
211
  _.bindAll @, "submit_success_handler", "submit_fatal_error_handler"
191
212
 
192
213
  saveOptions.success ||= @submit_success_handler
193
214
  saveOptions.error ||= @submit_fatal_error_handler
194
-
195
- @current_model.set( @getValues() )
215
+
216
+ @syncFormWithModel()
196
217
  return unless save
197
218
  @current_model.save( @current_model.toJSON(), saveOptions )
198
219
 
199
- currentModel: ()->
220
+ currentModel: (options={})->
221
+ if options is true or options?.refresh is true
222
+ @syncFormWithModel()
223
+
200
224
  @current_model
201
225
 
226
+ syncFormWithModel: ()->
227
+ @current_model?.set( @getValues() )
228
+
202
229
  setLegend: (@legend)->
203
230
  $('fieldset legend', @el).first().html(@legend)
204
231
 
data/src/core/view.coffee CHANGED
@@ -115,6 +115,8 @@ _.extend Luca.View.prototype,
115
115
 
116
116
  @registerCollectionEvents()
117
117
 
118
+ @delegateEvents()
119
+
118
120
  $container: ()-> $(@container)
119
121
  #### Hooks or Auto Event Binding
120
122
  #
data/src/framework.coffee CHANGED
@@ -1,7 +1,7 @@
1
1
  _.mixin( _.string )
2
2
 
3
3
  window.Luca =
4
- VERSION: "0.7.0"
4
+ VERSION: "0.7.2"
5
5
  core: {}
6
6
  containers: {}
7
7
  components: {}
@@ -21,6 +21,15 @@ window.Luca =
21
21
  # problem on our own!
22
22
  Luca.enableBootstrap = true
23
23
 
24
+ Luca.isBackboneModel = (obj)->
25
+ _.isFunction(obj?.set) and _.isFunction(obj?.get) and _.isObject(obj?.attributes)
26
+
27
+ Luca.isBackboneView = (obj)->
28
+ _.isFunction(obj?.render) and !_.isUndefined(obj?.el)
29
+
30
+ Luca.isBackboneCollection = (obj)->
31
+ _.isFunction(obj?.fetch) and _.isFunction(obj?.reset)
32
+
24
33
  # adds an additional namespace to look for luca ui
25
34
  # components. useful for when you define a bunch of
26
35
  # components in your own application's namespace
@@ -3,7 +3,7 @@
3
3
  _.mixin(_.string);
4
4
 
5
5
  window.Luca = {
6
- VERSION: "0.7.0",
6
+ VERSION: "0.7.2",
7
7
  core: {},
8
8
  containers: {},
9
9
  components: {},
@@ -22,6 +22,18 @@
22
22
 
23
23
  Luca.enableBootstrap = true;
24
24
 
25
+ Luca.isBackboneModel = function(obj) {
26
+ return _.isFunction(obj != null ? obj.set : void 0) && _.isFunction(obj != null ? obj.get : void 0) && _.isObject(obj != null ? obj.attributes : void 0);
27
+ };
28
+
29
+ Luca.isBackboneView = function(obj) {
30
+ return _.isFunction(obj != null ? obj.render : void 0) && !_.isUndefined(obj != null ? obj.el : void 0);
31
+ };
32
+
33
+ Luca.isBackboneCollection = function(obj) {
34
+ return _.isFunction(obj != null ? obj.fetch : void 0) && _.isFunction(obj != null ? obj.reset : void 0);
35
+ };
36
+
25
37
  Luca.registry.addNamespace = function(identifier) {
26
38
  Luca.registry.namespaces.push(identifier);
27
39
  return Luca.registry.namespaces = _(Luca.registry.namespaces).uniq();
@@ -408,7 +420,8 @@
408
420
  });
409
421
  }
410
422
  this.trigger("after:initialize", this);
411
- return this.registerCollectionEvents();
423
+ this.registerCollectionEvents();
424
+ return this.delegateEvents();
412
425
  },
413
426
  $container: function() {
414
427
  return $(this.container);