luca 0.8.599 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/.rvmrc +1 -0
- data/CHANGELOG +51 -2
- data/README.md +10 -247
- data/ROADMAP +6 -2
- data/app.rb +16 -2
- data/assets/javascripts/dependencies/bootstrap.min.js +7 -1
- data/assets/javascripts/dependencies/codemirror-coffeescript.js +347 -0
- data/assets/javascripts/dependencies/codemirror-css.js +124 -0
- data/assets/javascripts/dependencies/codemirror-html.js +410 -0
- data/assets/javascripts/dependencies/codemirror-javascript.js +361 -0
- data/assets/javascripts/dependencies/codemirror-less.js +232 -0
- data/assets/javascripts/dependencies/codemirror-vim.js +500 -0
- data/assets/javascripts/dependencies/codemirror.js +3076 -0
- data/assets/javascripts/dependencies.coffee +0 -1
- data/assets/javascripts/luca-ui-base.coffee +10 -3
- data/assets/javascripts/luca-ui-bootstrap.js +1 -0
- data/assets/javascripts/luca-ui-development-tools.coffee +9 -0
- data/assets/javascripts/luca-ui.coffee +6 -1
- data/assets/javascripts/sandbox/application.coffee +51 -0
- data/assets/javascripts/sandbox/router.coffee +14 -0
- data/assets/javascripts/sandbox/templates/main.luca +33 -0
- data/assets/javascripts/sandbox/templates/sandbox/navigation.luca +1 -0
- data/assets/javascripts/sandbox/templates/sandbox.luca +1 -0
- data/assets/javascripts/sandbox/views/top_navigation.coffee +4 -0
- data/assets/javascripts/sandbox.coffee +2 -2
- data/assets/stylesheets/bootstrap.min.css +395 -297
- data/assets/stylesheets/codemirror-blackboard.css +25 -0
- data/assets/stylesheets/codemirror-monokai.css +33 -0
- data/assets/stylesheets/codemirror.css +126 -0
- data/assets/stylesheets/luca-ui-bootstrap.css +0 -1
- data/assets/stylesheets/luca-ui-development-tools.css +5 -0
- data/assets/stylesheets/sandbox/sandbox.scss +1 -3
- data/assets/stylesheets/themes/amelia-bootstrap.css +826 -0
- data/assets/stylesheets/themes/slate-bootstrap.css +797 -0
- data/assets/stylesheets/themes/superhero-bootstrap.css +830 -0
- data/lib/luca/code_browser.rb +55 -0
- data/lib/luca/rails/version.rb +1 -1
- data/lib/luca/rails.rb +1 -0
- data/spec/components/fields/checkbox_array_spec.coffee +46 -0
- data/spec/components/form_view_spec.coffee +10 -4
- data/spec/containers/card_view_spec.coffee +7 -0
- data/spec/core/collection_spec.coffee +58 -4
- data/spec/core/container_spec.coffee +6 -6
- data/spec/core/view_spec.coffee +93 -7
- data/spec/framework_spec.coffee +15 -12
- data/src/components/application.coffee +126 -18
- data/src/components/base_toolbar.coffee +2 -2
- data/src/components/collection_loader_view.coffee +1 -2
- data/src/components/collection_view.coffee +77 -0
- data/src/components/controller.coffee +1 -4
- data/src/components/fields/button_field.coffee +1 -1
- data/src/components/fields/checkbox_array.coffee +2 -2
- data/src/components/fields/checkbox_field.coffee +3 -1
- data/src/components/fields/file_upload_field.coffee +1 -1
- data/src/components/fields/hidden_field.coffee +1 -1
- data/src/components/fields/select_field.coffee +1 -1
- data/src/components/fields/text_area_field.coffee +1 -1
- data/src/components/fields/text_field.coffee +10 -6
- data/src/components/fields/type_ahead_field.coffee +18 -5
- data/src/components/form_button_toolbar.coffee +1 -2
- data/src/components/form_view.coffee +44 -62
- data/src/components/grid_view.coffee +27 -20
- data/src/components/load_mask.coffee +3 -0
- data/src/components/nav_bar.coffee +26 -0
- data/src/components/record_manager.coffee +1 -3
- data/src/components/router.coffee +1 -1
- data/src/components/template.coffee +3 -15
- data/src/components/toolbar_dialog.coffee +25 -0
- data/src/containers/card_view.coffee +22 -23
- data/src/containers/column_view.coffee +1 -6
- data/src/containers/modal_view.coffee +20 -71
- data/src/containers/panel_toolbar.coffee +156 -0
- data/src/containers/panel_view.coffee +1 -1
- data/src/containers/split_view.coffee +1 -3
- data/src/containers/tab_view.coffee +29 -29
- data/src/containers/viewport.coffee +38 -3
- data/src/core/collection.coffee +80 -48
- data/src/core/container.coffee +153 -72
- data/src/core/core.coffee +181 -0
- data/src/core/field.coffee +4 -2
- data/src/core/model.coffee +1 -1
- data/src/core/observer.coffee +3 -3
- data/src/core/panel.coffee +143 -0
- data/src/core/registry.coffee +104 -0
- data/src/core/util.coffee +82 -0
- data/src/core/view.coffee +158 -85
- data/src/framework.coffee +112 -178
- data/src/index.coffee +0 -255
- data/src/managers/collection_manager.coffee +1 -0
- data/src/samples/definition.coffee +49 -0
- data/src/stylesheets/base.scss +0 -78
- data/src/stylesheets/components/form_view.scss +8 -3
- data/src/stylesheets/components/grid_view.scss +3 -7
- data/src/stylesheets/components/load_mask.scss +14 -0
- data/src/stylesheets/components/toolbar.scss +0 -15
- data/src/stylesheets/containers/container.scss +14 -2
- data/src/stylesheets/containers/panels.scss +23 -0
- data/src/stylesheets/tools/class_browser.scss +32 -0
- data/src/stylesheets/tools/code_editor.scss +24 -0
- data/src/stylesheets/tools/component_tester.scss +8 -0
- data/src/stylesheets/tools/console.scss +26 -0
- data/src/templates/components/collection_loader_view.luca +1 -1
- data/src/templates/components/form_view.luca +2 -13
- data/src/templates/components/grid_view.luca +0 -2
- data/src/templates/components/load_mask.luca +3 -0
- data/src/templates/components/nav_bar.luca +2 -0
- data/src/templates/containers/tab_view.luca +1 -0
- data/src/templates/fields/text_field.luca +4 -1
- data/src/tools/class_browser.coffee +39 -0
- data/src/tools/code_editor.coffee +258 -0
- data/src/tools/code_mirror_field.coffee +57 -0
- data/src/tools/coffee_script_editor.coffee +60 -0
- data/src/tools/collection_inspector.coffee +4 -0
- data/src/tools/component_tester.coffee +472 -0
- data/src/tools/components/class_browser_detail.coffee +10 -0
- data/src/tools/components/class_browser_list.coffee +74 -0
- data/src/tools/console.coffee +147 -0
- data/src/tools/development_console.coffee +147 -0
- data/src/tools/models/components.coffee +63 -0
- data/src/tools/templates/component_tester/help.luca +14 -0
- data/vendor/assets/javascripts/luca-ui-base.js +1389 -611
- data/vendor/assets/javascripts/luca-ui-bootstrap.js +9 -0
- data/vendor/assets/javascripts/luca-ui-development-tools.js +18719 -0
- data/vendor/assets/javascripts/luca-ui-spec.js +2065 -878
- data/vendor/assets/javascripts/luca-ui.js +1759 -852
- data/vendor/assets/javascripts/luca-ui.min.js +3 -3
- data/vendor/assets/stylesheets/luca-ui-bootstrap.css +494 -440
- data/vendor/assets/stylesheets/luca-ui-development-tools.css +224 -0
- data/vendor/assets/stylesheets/luca-ui-spec.css +99 -140
- data/vendor/assets/stylesheets/luca-ui.css +99 -140
- data/views/index.erb +6 -3
- metadata +60 -18
- data/assets/javascripts/dependencies/jquery-console.js +0 -649
- data/assets/javascripts/development-console.coffee +0 -2
- data/assets/javascripts/sandbox/sandbox.coffee +0 -16
- data/assets/javascripts/sandbox/templates/features/collection_helpers.luca +0 -33
- data/assets/javascripts/sandbox/templates/features/form_demo_code.luca +0 -48
- data/assets/javascripts/sandbox/templates/features/grid_demo_code.luca +0 -24
- data/assets/javascripts/sandbox/templates/features/introduction.luca +0 -11
- data/assets/javascripts/sandbox/templates/features/view_helpers.luca +0 -43
- data/assets/javascripts/sandbox/templates/navigation.luca +0 -8
- data/assets/javascripts/sandbox/views/form_demo.coffee +0 -47
- data/assets/javascripts/sandbox/views/grid_demo.coffee +0 -23
- data/assets/javascripts/sandbox/views/pages/collection_events_sample.coffee +0 -1
- data/assets/javascripts/sandbox/views/pages/pages_controller.coffee +0 -38
- data/src/components/collection_inspector.coffee +0 -2
- data/src/components/development_console.coffee +0 -59
- data/src/stylesheets/components/development_console.scss +0 -47
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
|
3
|
+
module Luca
|
4
|
+
class CodeBrowser < Sinatra::Base
|
5
|
+
|
6
|
+
class << self
|
7
|
+
attr_accessor :source_locations, :source_map
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.look_for_source_in location=""
|
11
|
+
@source_locations ||= []
|
12
|
+
@source_locations << "#{ location }/**/*.coffee" if File.exists?(location)
|
13
|
+
|
14
|
+
@source_locations
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.map_source
|
18
|
+
@source_map = {}
|
19
|
+
|
20
|
+
(self.source_locations || []).map do |location|
|
21
|
+
files = Dir.glob( location )
|
22
|
+
files.inject( @source_map ) do |memo, file|
|
23
|
+
definitions = IO.read(file).lines.to_a.grep /_\.def/
|
24
|
+
|
25
|
+
definitions.each do |definition|
|
26
|
+
component = definition.match(/_\.def\(['"](.+)['"]\)\./)
|
27
|
+
|
28
|
+
if component and component[1]
|
29
|
+
componentId = component[1].gsub(/['"].*$/,'')
|
30
|
+
memo[ componentId ] = file if componentId
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
memo
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
@source_map
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.lookup_component component=""
|
42
|
+
map_source[ component ]
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.get_component_source file=""
|
46
|
+
IO.read( file ) rescue ""
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.get_source_for component=""
|
50
|
+
path_to_file = lookup_component( component )
|
51
|
+
get_component_source( path_to_file )
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
data/lib/luca/rails/version.rb
CHANGED
data/lib/luca/rails.rb
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
describe 'The Checkbox Array Field', ->
|
2
|
+
|
3
|
+
beforeEach ->
|
4
|
+
@model = new Backbone.Model(item_ids: ["1"])
|
5
|
+
collection = new Luca.Collection
|
6
|
+
|
7
|
+
@formView = new Luca.components.FormView
|
8
|
+
components:[
|
9
|
+
ctype: "checkbox_array"
|
10
|
+
name: 'item_ids'
|
11
|
+
collection: collection
|
12
|
+
]
|
13
|
+
|
14
|
+
@formView.render()
|
15
|
+
@formView.loadModel(@model)
|
16
|
+
|
17
|
+
collection.reset([
|
18
|
+
id: "1", name: "Item1"
|
19
|
+
,
|
20
|
+
id: "2", name: "Item2"
|
21
|
+
,
|
22
|
+
id: "3", name: "Item3"
|
23
|
+
])
|
24
|
+
|
25
|
+
@field = @formView.getFields()[0]
|
26
|
+
|
27
|
+
it "should create a checkbox array field", ->
|
28
|
+
expect(@formView.currentModel()).toEqual(@model)
|
29
|
+
expect(@field.selectedItems).toEqual(["1"])
|
30
|
+
|
31
|
+
it "should render the list of checkboxes", ->
|
32
|
+
expect(@field.$el.html()).toContain("Item1")
|
33
|
+
expect(@field.$el.html()).toContain("Item2")
|
34
|
+
expect(@field.$el.html()).toContain("Item3")
|
35
|
+
|
36
|
+
it "should check off each checkbox in the collection that is selected", ->
|
37
|
+
expect(@field.$el.find("input[value='1']")[0].checked).toBeTruthy()
|
38
|
+
expect(@field.$el.find("input[value='2']")[0].checked).toBeFalsy()
|
39
|
+
expect(@field.$el.find("input[value='3']")[0].checked).toBeFalsy()
|
40
|
+
|
41
|
+
it "should update the form model's attribute to be an array of selected items on click", ->
|
42
|
+
checkbox = $(@field.$el.find("input[value='2']")[0])
|
43
|
+
checkbox.prop("checked", true)
|
44
|
+
checkbox.click()
|
45
|
+
|
46
|
+
expect(@field.getModel().get('item_ids')).toEqual(["1", "2"])
|
@@ -40,6 +40,10 @@ describe 'The Form View', ->
|
|
40
40
|
@form = new FormView()
|
41
41
|
@model = new Model(field0:1,field1:"jonathan",field3:true,field4:"what up player?")
|
42
42
|
|
43
|
+
afterEach ->
|
44
|
+
@form = undefined
|
45
|
+
@model = undefined
|
46
|
+
|
43
47
|
it "should create a form", ->
|
44
48
|
expect( @form ).toBeDefined()
|
45
49
|
|
@@ -53,11 +57,13 @@ describe 'The Form View', ->
|
|
53
57
|
values = @form.getValues()
|
54
58
|
expect( values.field1 ).toEqual "jonathan"
|
55
59
|
|
56
|
-
it "should render the components", ->
|
60
|
+
it "should render the components within the body element", ->
|
61
|
+
@form.render()
|
62
|
+
expect( @form.$bodyEl().is('.form-view-body') ).toEqual true
|
63
|
+
|
64
|
+
it "should assign the components to render inside of the body", ->
|
57
65
|
@form.render()
|
58
|
-
expect( @form.$
|
59
|
-
expect( @form.$el.html() ).toContain "Field One"
|
60
|
-
expect( @form.$el.html() ).toContain "Click Me"
|
66
|
+
expect( @form.$bodyEl().html() ).toContain "Field Four"
|
61
67
|
|
62
68
|
it "should allow me to set the values of the form fields with a hash", ->
|
63
69
|
@form.render()
|
@@ -19,6 +19,13 @@ describe "The Card View", ->
|
|
19
19
|
|
20
20
|
@cardView.render()
|
21
21
|
|
22
|
+
it "should create three card elements", ->
|
23
|
+
expect( @cardView.componentElements().length ).toEqual 3
|
24
|
+
|
25
|
+
it "should hide all but one of the card elements", ->
|
26
|
+
display = _( @cardView.$('.luca-ui-card') ).map (el)-> $(el).css('display')
|
27
|
+
expect( display ).toEqual(['block','none','none'])
|
28
|
+
|
22
29
|
it "should be able to find the cards by name", ->
|
23
30
|
expect( @cardView.find("one") ).toBeDefined()
|
24
31
|
expect( @cardView.find("one").one ).toEqual true
|
@@ -1,5 +1,47 @@
|
|
1
1
|
#### Luca.Collection
|
2
2
|
|
3
|
+
setupCollection = ()->
|
4
|
+
window.cachedMethodOne = 0
|
5
|
+
window.cachedMethodTwo = 0
|
6
|
+
|
7
|
+
window.CachedMethodCollection = Luca.Collection.extend
|
8
|
+
cachedMethods:["cachedMethodOne","cachedMethodTwo"]
|
9
|
+
|
10
|
+
cachedMethodOne: ()->
|
11
|
+
window.cachedMethodOne += 1
|
12
|
+
|
13
|
+
cachedMethodTwo: ()->
|
14
|
+
window.cachedMethodTwo += 1
|
15
|
+
|
16
|
+
describe "Method Caching", ->
|
17
|
+
beforeEach ->
|
18
|
+
setupCollection()
|
19
|
+
@collection = new CachedMethodCollection()
|
20
|
+
|
21
|
+
afterEach ->
|
22
|
+
@collection = undefined
|
23
|
+
window.CachedMethodCollection = undefined
|
24
|
+
|
25
|
+
it "should call the method", ->
|
26
|
+
expect( @collection.cachedMethodOne() ).toEqual 1
|
27
|
+
|
28
|
+
it "should cache the value of the method", ->
|
29
|
+
_( 5 ).times ()=> @collection.cachedMethodOne()
|
30
|
+
expect( @collection.cachedMethodOne() ).toEqual 1
|
31
|
+
|
32
|
+
it "should refresh the method cache upon reset of the models", ->
|
33
|
+
_( 3 ).times ()=> @collection.cachedMethodOne()
|
34
|
+
expect( @collection.cachedMethodOne() ).toEqual 1
|
35
|
+
@collection.reset()
|
36
|
+
_( 3 ).times ()=> @collection.cachedMethodOne()
|
37
|
+
expect( @collection.cachedMethodOne() ).toEqual 2
|
38
|
+
|
39
|
+
it "should restore the collection to the original configuration", ->
|
40
|
+
@collection.restoreMethodCache()
|
41
|
+
_( 5 ).times ()=> @collection.cachedMethodOne()
|
42
|
+
expect( @collection.cachedMethodOne() ).toEqual 6
|
43
|
+
|
44
|
+
|
3
45
|
describe "Luca.Collection", ->
|
4
46
|
it "should accept a name and collection manager", ->
|
5
47
|
mgr = new Luca.CollectionManager()
|
@@ -36,6 +78,18 @@ describe "Luca.Collection", ->
|
|
36
78
|
|
37
79
|
expect( registerSpy ).toHaveBeenCalled()
|
38
80
|
|
81
|
+
it "should query collection with filter", ->
|
82
|
+
models = []
|
83
|
+
models.push id: i, key: 'value' for i in [0..9]
|
84
|
+
models[3].key = 'specialValue'
|
85
|
+
|
86
|
+
collection = new Luca.Collection models
|
87
|
+
|
88
|
+
collection.applyFilter key: 'specialValue'
|
89
|
+
|
90
|
+
expect(collection.length).toBe 1
|
91
|
+
expect(collection.first().get('key')).toBe 'specialValue'
|
92
|
+
|
39
93
|
describe "The ifLoaded helper", ->
|
40
94
|
it "should fire the passed callback automatically if there are models", ->
|
41
95
|
spy = sinon.spy()
|
@@ -171,7 +225,7 @@ describe "The Model Bootstrap", ->
|
|
171
225
|
|
172
226
|
it "should fetch the cached models from the bootstrap", ->
|
173
227
|
collection = new Luca.Collection [],
|
174
|
-
|
228
|
+
cache_key: ()-> "sample"
|
175
229
|
|
176
230
|
collection.fetch()
|
177
231
|
|
@@ -180,14 +234,14 @@ describe "The Model Bootstrap", ->
|
|
180
234
|
|
181
235
|
it "should reference the cached models", ->
|
182
236
|
collection = new Luca.Collection [],
|
183
|
-
|
237
|
+
cache_key: ()-> "sample"
|
184
238
|
|
185
239
|
expect( collection.cached_models().length ).toEqual(5)
|
186
240
|
|
187
241
|
it "should avoid making an API call", ->
|
188
242
|
spy = sinon.spy( Backbone.Collection.prototype.fetch )
|
189
243
|
collection = new Luca.Collection [],
|
190
|
-
|
244
|
+
cache_key: ()-> "sample"
|
191
245
|
|
192
246
|
collection.fetch()
|
193
247
|
expect( spy.called ).toBeFalsy()
|
@@ -196,7 +250,7 @@ describe "The Model Bootstrap", ->
|
|
196
250
|
spy = sinon.spy()
|
197
251
|
|
198
252
|
collection = new Luca.Collection [],
|
199
|
-
|
253
|
+
cache_key: ()-> "sample"
|
200
254
|
url: ()-> "/models"
|
201
255
|
|
202
256
|
collection.bind "after:response", spy
|
@@ -3,15 +3,15 @@ describe 'The Luca Container', ->
|
|
3
3
|
@container = new Luca.core.Container
|
4
4
|
components:[
|
5
5
|
name: "component_one"
|
6
|
-
ctype: "
|
7
|
-
|
6
|
+
ctype: "view"
|
7
|
+
bodyTemplate: ()-> "markup for component one"
|
8
8
|
id: "c1"
|
9
9
|
value: 1
|
10
10
|
spy: sinon.spy()
|
11
11
|
,
|
12
12
|
name: "component_two"
|
13
|
-
ctype: "
|
14
|
-
|
13
|
+
ctype: "view"
|
14
|
+
bodyTemplate: ()-> "markup for component two"
|
15
15
|
id: "c2"
|
16
16
|
value: 0
|
17
17
|
spy: sinon.spy()
|
@@ -22,9 +22,9 @@ describe 'The Luca Container', ->
|
|
22
22
|
value: 1
|
23
23
|
spy: sinon.spy()
|
24
24
|
components:[
|
25
|
-
ctype: "
|
25
|
+
ctype: "view"
|
26
26
|
name: "component_four"
|
27
|
-
|
27
|
+
bodyTemplate: ()-> "markup for component four"
|
28
28
|
spy: sinon.spy()
|
29
29
|
]
|
30
30
|
]
|
data/spec/core/view_spec.coffee
CHANGED
@@ -1,8 +1,4 @@
|
|
1
1
|
describe "Luca.View", ->
|
2
|
-
Custom = Luca.View.extend
|
3
|
-
clickHandler: sinon.spy()
|
4
|
-
autoBindEventHandlers: true
|
5
|
-
|
6
2
|
it "should be defined", ->
|
7
3
|
expect(Luca.View).toBeDefined()
|
8
4
|
|
@@ -16,16 +12,99 @@ describe "Luca.View", ->
|
|
16
12
|
|
17
13
|
it "should register the view in the cache", ->
|
18
14
|
view = new Luca.View(name:"cached")
|
19
|
-
expect( Luca.cache("cached") ).
|
15
|
+
expect( Luca.cache("cached") ).toEqual(view)
|
20
16
|
|
21
17
|
it "should trigger after initialize", ->
|
22
18
|
view = new Luca.View()
|
23
19
|
expect( view ).toHaveTriggered("after:initialize")
|
24
20
|
|
25
|
-
it "should
|
26
|
-
|
21
|
+
it "should be picked up by the isBackboneView helper", ->
|
22
|
+
view = new Luca.View()
|
23
|
+
expect( Luca.isBackboneView(view) ).toEqual true
|
24
|
+
|
25
|
+
it "should be picked up by the isBackboneComponent helper", ->
|
26
|
+
view = new Luca.View()
|
27
|
+
expect( Luca.isComponent(view) ).toEqual true
|
28
|
+
|
29
|
+
it "should be picked up by the supportsBackboneEvents helper", ->
|
30
|
+
view = new Luca.View()
|
31
|
+
expect( Luca.supportsBackboneEvents(view) ).toEqual true
|
32
|
+
|
33
|
+
it "should append additional class names to the view's $el", ->
|
34
|
+
view = new Luca.View(additionalClassNames:["yes-yes","yall"])
|
35
|
+
expect( view.$el.is(".yes-yes.yall") ).toEqual true
|
36
|
+
|
37
|
+
it "should accept a string for additional class names", ->
|
38
|
+
view = new Luca.View(additionalClassNames:"yes-yes yall")
|
39
|
+
expect( view.$el.is(".yes-yes.yall") ).toEqual true
|
40
|
+
|
41
|
+
|
42
|
+
describe "Introspection Helpers", ->
|
43
|
+
beforeEach ->
|
44
|
+
@view = new Luca.View
|
45
|
+
events:
|
46
|
+
"click .a" : "clickHandler"
|
47
|
+
"hover .a" : "hoverHandler"
|
48
|
+
|
49
|
+
clickHandler: ()-> "click"
|
50
|
+
hoverHandler: ()-> "hover"
|
51
|
+
|
52
|
+
collection_one: new Luca.Collection([],name:"collection_one")
|
53
|
+
collection_two: new Luca.Collection([],name:"collection_two")
|
54
|
+
view_one: new Luca.View(name:"view_one")
|
55
|
+
view_two: new Luca.View(name:"view_two")
|
56
|
+
model_one: new Luca.Model(name:"model_one")
|
57
|
+
model_two: new Luca.Model(name:"model_two")
|
58
|
+
|
59
|
+
it "should know the names of functions which are event handlers", ->
|
60
|
+
names = @view.eventHandlerProperties()
|
61
|
+
expect( names ).toEqual ["clickHandler","hoverHandler"]
|
27
62
|
|
63
|
+
it "should know which properties are other views", ->
|
64
|
+
viewNames = _( @view.views() ).pluck("name")
|
65
|
+
expect( viewNames ).toEqual ["view_one","view_two"]
|
28
66
|
|
67
|
+
it "should know which properties are other models", ->
|
68
|
+
modelNames = _( @view.models() ).map (m)-> m.get('name')
|
69
|
+
expect( modelNames ).toEqual ["model_one","model_two"]
|
70
|
+
|
71
|
+
it "should know which properties are other collections", ->
|
72
|
+
collectionNames = _( @view.collections() ).pluck("name")
|
73
|
+
expect( collectionNames ).toEqual ["collection_one","collection_two"]
|
74
|
+
|
75
|
+
describe "DOM Helper Methods", ->
|
76
|
+
it "should use the $html method to inject into the $el", ->
|
77
|
+
view = new Luca.View()
|
78
|
+
view.$html('haha')
|
79
|
+
expect( view.$html() ).toEqual 'haha'
|
80
|
+
|
81
|
+
describe "Deferrable Rendering", ->
|
82
|
+
beforeEach ->
|
83
|
+
@fetchSpy = sinon.spy()
|
84
|
+
@customSpy = sinon.spy()
|
85
|
+
|
86
|
+
@collection = new Luca.Collection
|
87
|
+
url: "/models"
|
88
|
+
fetch: @fetchSpy
|
89
|
+
custom: @customSpy
|
90
|
+
name: "haha"
|
91
|
+
|
92
|
+
@DeferrableView = Luca.View.extend
|
93
|
+
name: "deferrable_view"
|
94
|
+
deferrable: @collection
|
95
|
+
|
96
|
+
@TriggeredView = Luca.View.extend
|
97
|
+
deferrable: @collection
|
98
|
+
deferrable_method: "custom"
|
99
|
+
|
100
|
+
it "should automatically call fetch on the collection ", ->
|
101
|
+
( new @DeferrableView ).render()
|
102
|
+
@server.respond()
|
103
|
+
expect( @fetchSpy ).toHaveBeenCalled()
|
104
|
+
|
105
|
+
it "should call a custom method if configured", ->
|
106
|
+
( new @TriggeredView ).render()
|
107
|
+
expect( @customSpy ).toHaveBeenCalled()
|
29
108
|
|
30
109
|
describe "Hooks", ->
|
31
110
|
it "should have before and after render hooks", ->
|
@@ -85,3 +164,10 @@ describe "The Collection Events API", ->
|
|
85
164
|
collection = @manager.get("sample")
|
86
165
|
collection.reset([])
|
87
166
|
expect( view.resetHandler ).toHaveBeenCalled()
|
167
|
+
|
168
|
+
|
169
|
+
describe "Code Refresh", ->
|
170
|
+
beforeEach ->
|
171
|
+
|
172
|
+
it "should reference the event handler function property names", ->
|
173
|
+
it "should reference the event handler functions", ->
|
data/spec/framework_spec.coffee
CHANGED
@@ -18,7 +18,7 @@ describe "The Luca Framework", ->
|
|
18
18
|
|
19
19
|
it "should allow me to add view namespaces to the registry", ->
|
20
20
|
Luca.registry.addNamespace("Test.namespace")
|
21
|
-
expect( Luca.registry.namespaces ).toContain("Test.namespace")
|
21
|
+
expect( Luca.registry.namespaces(false) ).toContain("Test.namespace")
|
22
22
|
|
23
23
|
it "should resolve a value.string to the object", ->
|
24
24
|
window.nested =
|
@@ -31,18 +31,17 @@ describe "The Luca Framework", ->
|
|
31
31
|
|
32
32
|
it "should create an instance of a class by ctype", ->
|
33
33
|
object =
|
34
|
-
ctype: "
|
35
|
-
template: "components/form_view"
|
34
|
+
ctype: "view"
|
36
35
|
|
37
36
|
component = Luca.util.lazyComponent(object)
|
38
|
-
|
37
|
+
|
38
|
+
expect( Luca.isBackboneView(component) ).toEqual true
|
39
39
|
|
40
40
|
it "should find a created view in the cache", ->
|
41
|
-
template = new Luca.
|
42
|
-
template: "components/form_view"
|
41
|
+
template = new Luca.View
|
43
42
|
name: 'test_template'
|
44
43
|
|
45
|
-
expect(Luca.cache("test_template")).
|
44
|
+
expect( Luca.isBackboneView( Luca.cache("test_template") ) ).toEqual true
|
46
45
|
|
47
46
|
it "should detect if an object is probably a backbone view", ->
|
48
47
|
obj =
|
@@ -79,14 +78,14 @@ describe "Luca Component Definition", ->
|
|
79
78
|
expect( Luca.random ).toBeDefined()
|
80
79
|
|
81
80
|
it "should automatically register the namespace in the registry", ->
|
82
|
-
expect( Luca.registry.namespaces ).toContain
|
81
|
+
expect( Luca.registry.namespaces() ).toContain Luca.random
|
83
82
|
|
84
83
|
it "should automatically register the component in the registry", ->
|
85
84
|
expect( Luca.registry.lookup("component_definition") ).toBeDefined()
|
86
85
|
|
87
86
|
it "should reference the name of the extending class", ->
|
88
87
|
instance = new Luca.random.ComponentDefinition
|
89
|
-
expect( instance.
|
88
|
+
expect( instance.displayName ).toEqual "Luca.random.ComponentDefinition"
|
90
89
|
|
91
90
|
it "should reference the extended class", ->
|
92
91
|
instance = new Luca.random.ComponentDefinition
|
@@ -94,12 +93,16 @@ describe "Luca Component Definition", ->
|
|
94
93
|
|
95
94
|
it "should reference the name of the extended class", ->
|
96
95
|
instance = new Luca.random.ComponentDefinition
|
97
|
-
expect( instance._superClass().
|
96
|
+
expect( instance._superClass().displayName ).toEqual 'Luca.View'
|
98
97
|
|
99
98
|
it "should use the backbone.extend functionality properly", ->
|
100
99
|
instance = new Luca.random.ComponentDefinition
|
101
100
|
expect( instance.property ).toEqual "value"
|
102
101
|
|
103
|
-
it "should alias to _.
|
104
|
-
proxy = _.
|
102
|
+
it "should alias to _.def", ->
|
103
|
+
proxy = _.def('Luca.random.ComponentDefition')
|
105
104
|
expect( proxy.with ).toBeDefined()
|
105
|
+
|
106
|
+
it "should allow me to set the namespace before the definition", ->
|
107
|
+
Luca.util.namespace("Luca.View")
|
108
|
+
expect( Luca.util.namespace() ).toEqual Luca.View
|
@@ -1,25 +1,77 @@
|
|
1
|
-
_.
|
2
|
-
|
1
|
+
_.def('Luca.Application').extends('Luca.containers.Viewport').with
|
2
|
+
|
3
|
+
# automatically starts the @router
|
4
|
+
# if it exists, once the components
|
5
|
+
# for the application have been created
|
6
|
+
autoStartHistory: true
|
7
|
+
|
8
|
+
# we will create a collection manager singleton
|
9
|
+
# by default unless otherwise specified
|
10
|
+
useCollectionManager: true
|
11
|
+
|
12
|
+
# Luca plugin apps are apps which mount onto existing
|
13
|
+
# luca apps, and will not have the behavior of a main
|
14
|
+
# app which acts as a singleton
|
15
|
+
plugin: false
|
16
|
+
|
17
|
+
# by default, the application will use a controller
|
18
|
+
# component, which is a card view container which shows
|
19
|
+
# one view at a time. this is useful for having an application
|
20
|
+
# with several 'pages' so to speak
|
21
|
+
useController: true
|
22
|
+
|
23
|
+
#### Nested Components
|
24
|
+
|
25
|
+
# applications have one component, the controller.
|
26
|
+
# any components defined on the application class directly
|
27
|
+
# will get wrapped by the main controller unless you
|
28
|
+
# set useController = false
|
3
29
|
components:[
|
4
|
-
ctype: '
|
5
|
-
name: '
|
6
|
-
|
7
|
-
|
8
|
-
ctype: 'template'
|
9
|
-
name: 'welcome'
|
10
|
-
template: 'sample/welcome'
|
11
|
-
templateContainer: "Luca.templates"
|
12
|
-
]
|
30
|
+
ctype: 'template'
|
31
|
+
name: 'welcome'
|
32
|
+
template: 'sample/welcome'
|
33
|
+
templateContainer: "Luca.templates"
|
13
34
|
]
|
14
35
|
|
15
36
|
initialize: (@options={})->
|
16
37
|
Luca.containers.Viewport::initialize.apply @, arguments
|
17
38
|
|
18
|
-
@
|
39
|
+
if @useController is true
|
40
|
+
definedComponents = @components || []
|
41
|
+
|
42
|
+
@components = [
|
43
|
+
ctype: 'controller'
|
44
|
+
name: "main_controller"
|
45
|
+
components: definedComponents
|
46
|
+
]
|
47
|
+
|
48
|
+
if @useCollectionManager is true
|
49
|
+
@collectionManager ||= Luca.CollectionManager.get?()
|
50
|
+
@collectionManager ||= new Luca.CollectionManager( @collectionManagerOptions||={} )
|
19
51
|
|
20
52
|
@state = new Backbone.Model( @defaultState )
|
21
53
|
|
22
|
-
|
54
|
+
# we will render when all of the various components
|
55
|
+
# which handle our data dependencies determine that
|
56
|
+
# we are ready
|
57
|
+
@bind "ready", ()=>
|
58
|
+
@render()
|
59
|
+
# the keyRouter allows us to specify
|
60
|
+
# keyEvents on our application with an API very similar
|
61
|
+
# to the DOM events API for Backbone.View
|
62
|
+
#
|
63
|
+
# Example:
|
64
|
+
#
|
65
|
+
# keyEvents:
|
66
|
+
# meta:
|
67
|
+
# forwardslash: "altSlashHandler"
|
68
|
+
@setupKeyRouter() if @useKeyRouter is true and @keyEvents?
|
69
|
+
|
70
|
+
# if the application is a plugin designed to modify the behavior
|
71
|
+
# of another app, then don't claim ownership. otherwise the most common
|
72
|
+
# use-case is that there will be one application instance
|
73
|
+
unless @plugin is true
|
74
|
+
Luca.getApplication = ()=> @
|
23
75
|
|
24
76
|
activeView: ()->
|
25
77
|
if active = @activeSubSection()
|
@@ -33,6 +85,17 @@ _.component('Luca.Application').extends('Luca.containers.Viewport').with
|
|
33
85
|
activeSection: ()->
|
34
86
|
@get("active_section")
|
35
87
|
|
88
|
+
beforeRender: ()->
|
89
|
+
Luca.containers.Viewport::beforeRender?.apply(@, arguments)
|
90
|
+
|
91
|
+
if @router? and @autoStartHistory is true
|
92
|
+
routerStartEvent = @startRouterOn || "after:render"
|
93
|
+
|
94
|
+
if routerStartEvent is "before:render"
|
95
|
+
Backbone.history.start()
|
96
|
+
else
|
97
|
+
@bind routerStartEvent, ()-> Backbone.history.start()
|
98
|
+
|
36
99
|
afterComponents: ()->
|
37
100
|
Luca.containers.Viewport::afterComponents?.apply @, arguments
|
38
101
|
|
@@ -48,9 +111,6 @@ _.component('Luca.Application').extends('Luca.containers.Viewport').with
|
|
48
111
|
component.bind "after:card:switch", (previous,current)=>
|
49
112
|
@state.set(active_sub_section:current.name)
|
50
113
|
|
51
|
-
beforeRender: ()->
|
52
|
-
Luca.containers.Viewport::beforeRender?.apply @, arguments
|
53
|
-
#Backbone.history.start()
|
54
114
|
|
55
115
|
# boot should trigger the ready event, which will call the initial call
|
56
116
|
# to render() your application, which will have a cascading effect on every
|
@@ -72,10 +132,58 @@ _.component('Luca.Application').extends('Luca.containers.Viewport').with
|
|
72
132
|
@state.get(attribute)
|
73
133
|
|
74
134
|
getMainController: ()->
|
75
|
-
@
|
135
|
+
return @components[0] if @useController is true
|
136
|
+
Luca.cache('main_controller')
|
76
137
|
|
77
138
|
set: (attributes)->
|
78
139
|
@state.set(attributes)
|
79
140
|
|
80
|
-
view: (name)->
|
141
|
+
view: (name)->
|
142
|
+
Luca.cache(name)
|
143
|
+
|
144
|
+
#### Navigation Hooks
|
145
|
+
#
|
146
|
+
# delegate to the main controller so that we can switch the active section
|
147
|
+
navigate_to: (component_name, callback)->
|
148
|
+
@getMainController().navigate_to(component_name, callback)
|
149
|
+
|
150
|
+
setupKeyRouter: ()->
|
151
|
+
return unless @keyEvents
|
152
|
+
|
153
|
+
@keyEvents.control_meta ||= {}
|
154
|
+
|
155
|
+
# allow for both meta_control, control_meta for the combo
|
156
|
+
_.extend(@keyEvents.control_meta, @keyEvents.meta_control) if @keyEvents.meta_control
|
157
|
+
|
158
|
+
router = _.bind(@keyRouter, @)
|
159
|
+
|
160
|
+
$( document ).keydown( router )
|
161
|
+
|
162
|
+
#### Key Router
|
163
|
+
#
|
164
|
+
# TODO: Define a syntax for mapping combinations of meta, control, and keycodes
|
165
|
+
# to some sort of method delegation system that the application handles.
|
166
|
+
keyRouter: (e)->
|
167
|
+
return unless e and @keyEvents
|
168
|
+
|
169
|
+
isInputEvent = $(e.target).is('input') || $(e.target).is('textarea')
|
170
|
+
|
171
|
+
return if isInputEvent
|
172
|
+
|
173
|
+
keyname = Luca.keyMap[ e.keyCode ]
|
174
|
+
|
175
|
+
return unless keyname
|
176
|
+
|
177
|
+
meta = e?.metaKey is true
|
178
|
+
control = e?.ctrlKey is true
|
179
|
+
|
180
|
+
source = @keyEvents
|
181
|
+
source = if meta then @keyEvents.meta else source
|
182
|
+
source = if control then @keyEvents.control else source
|
183
|
+
source = if meta and control then @keyEvents.meta_control else source
|
81
184
|
|
185
|
+
if keyEvent = source?[keyname]
|
186
|
+
if @[keyEvent]?
|
187
|
+
@[keyEvent]?.call(@)
|
188
|
+
else
|
189
|
+
@trigger(keyEvent)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
_.
|
1
|
+
_.def('Luca.components.Toolbar').extends('Luca.core.Container').with
|
2
2
|
|
3
3
|
className: 'luca-ui-toolbar'
|
4
4
|
|
@@ -9,7 +9,7 @@ _.component('Luca.components.Toolbar').extends('Luca.core.Container').with
|
|
9
9
|
|
10
10
|
prepareComponents: ()->
|
11
11
|
_( @components ).each (component)=>
|
12
|
-
component.container =
|
12
|
+
component.container = @$el
|
13
13
|
|
14
14
|
render: ()->
|
15
15
|
$(@container).append(@el)
|