luca 0.7.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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);