luca 0.6.6
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.
- data/.gitignore +5 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +77 -0
- data/Guardfile +22 -0
- data/README.md +291 -0
- data/Rakefile +28 -0
- data/app.rb +46 -0
- data/assets/images/glyphicons-halflings-white.png +0 -0
- data/assets/images/glyphicons-halflings.png +0 -0
- data/assets/javascripts/dependencies/backbone-min.js +37 -0
- data/assets/javascripts/dependencies/backbone-query.min.js +1 -0
- data/assets/javascripts/dependencies/bootstrap.min.js +1 -0
- data/assets/javascripts/dependencies/jasmine-html.js +190 -0
- data/assets/javascripts/dependencies/jasmine.js +2476 -0
- data/assets/javascripts/dependencies/jquery.js +4 -0
- data/assets/javascripts/dependencies/modal.js +698 -0
- data/assets/javascripts/dependencies/modernizr.min.js +30 -0
- data/assets/javascripts/dependencies/prettify.js +28 -0
- data/assets/javascripts/dependencies/sinon.js +3469 -0
- data/assets/javascripts/dependencies/spin-min.js +2 -0
- data/assets/javascripts/dependencies/underscore-min.js +31 -0
- data/assets/javascripts/dependencies/underscore-string.min.js +14 -0
- data/assets/javascripts/dependencies.coffee +7 -0
- data/assets/javascripts/luca-ui-base.coffee +12 -0
- data/assets/javascripts/luca-ui-spec.coffee +2 -0
- data/assets/javascripts/luca-ui.coffee +3 -0
- data/assets/javascripts/sandbox/collections/sample.coffee +0 -0
- data/assets/javascripts/sandbox/config.coffee +7 -0
- data/assets/javascripts/sandbox/sandbox.coffee +16 -0
- data/assets/javascripts/sandbox/templates/features/collection_helpers.luca +33 -0
- data/assets/javascripts/sandbox/templates/features/form_demo_code.luca +48 -0
- data/assets/javascripts/sandbox/templates/features/grid_demo_code.luca +24 -0
- data/assets/javascripts/sandbox/templates/features/introduction.luca +11 -0
- data/assets/javascripts/sandbox/templates/features/view_helpers.luca +43 -0
- data/assets/javascripts/sandbox/templates/navigation.luca +8 -0
- data/assets/javascripts/sandbox/views/form_demo.coffee +47 -0
- data/assets/javascripts/sandbox/views/grid_demo.coffee +23 -0
- data/assets/javascripts/sandbox/views/pages/collection_events_sample.coffee +1 -0
- data/assets/javascripts/sandbox/views/pages/pages_controller.coffee +28 -0
- data/assets/javascripts/sandbox.coffee +4 -0
- data/assets/javascripts/spec-dependencies.coffee +4 -0
- data/assets/stylesheets/bootstrap-responsive.min.css +3 -0
- data/assets/stylesheets/bootstrap.min.css +610 -0
- data/assets/stylesheets/jasmine.css +166 -0
- data/assets/stylesheets/luca-ui-bootstrap.css +5 -0
- data/assets/stylesheets/luca-ui-spec.css +3 -0
- data/assets/stylesheets/luca-ui.css +3 -0
- data/assets/stylesheets/prettify.css +40 -0
- data/assets/stylesheets/sandbox/sandbox.scss +4 -0
- data/assets/stylesheets/sandbox.css +3 -0
- data/config.ru +11 -0
- data/lib/luca/command_line.rb +69 -0
- data/lib/luca/rails/engine.rb +12 -0
- data/lib/luca/rails/version.rb +6 -0
- data/lib/luca/rails.rb +9 -0
- data/lib/luca/template.rb +51 -0
- data/lib/luca/test_harness.rb +106 -0
- data/lib/luca.rb +1 -0
- data/lib/sprockets/luca_template.rb +49 -0
- data/lib/templates/spec_manifest_javascripts.erb +7 -0
- data/lib/templates/spec_manifest_stylesheets.erb +11 -0
- data/luca.gemspec +26 -0
- data/public/jasmine/index.html +26 -0
- data/public/sandbox/api.js +1 -0
- data/spec/components/application_spec.coffee +0 -0
- data/spec/components/collection_loader_view_spec.coffee +0 -0
- data/spec/components/controller_spec.coffee +0 -0
- data/spec/components/form_view_spec.coffee +13 -0
- data/spec/components/grid_view_spec.coffee +0 -0
- data/spec/components/record_manager_spec.coffee +0 -0
- data/spec/components/template_spec.coffee +0 -0
- data/spec/containers/card_view_spec.coffee +1 -0
- data/spec/containers/column_view_spec.coffee +0 -0
- data/spec/containers/modal_view_spec.coffee +0 -0
- data/spec/containers/panel_view_spec.coffee +0 -0
- data/spec/containers/split_view_spec.coffee +0 -0
- data/spec/containers/tab_view_spec.coffee +0 -0
- data/spec/containers/viewport_spec.coffee +0 -0
- data/spec/core/collection_spec.coffee +215 -0
- data/spec/core/container_spec.coffee +0 -0
- data/spec/core/field_spec.coffee +0 -0
- data/spec/core/observer_spec.coffee +0 -0
- data/spec/core/view_spec.coffee +87 -0
- data/spec/framework_spec.coffee +48 -0
- data/spec/helper.coffee +120 -0
- data/spec/managers/collection_manager_spec.coffee +95 -0
- data/spec/managers/socket_manager_spec.coffee +0 -0
- data/src/components/application.coffee +83 -0
- data/src/components/base_toolbar.coffee +16 -0
- data/src/components/collection_loader_view.coffee +37 -0
- data/src/components/controller.coffee +41 -0
- data/src/components/fields/button_field.coffee +40 -0
- data/src/components/fields/checkbox_field.coffee +41 -0
- data/src/components/fields/file_upload_field.coffee +15 -0
- data/src/components/fields/hidden_field.coffee +18 -0
- data/src/components/fields/select_field.coffee +100 -0
- data/src/components/fields/text_area_field.coffee +43 -0
- data/src/components/fields/text_field.coffee +42 -0
- data/src/components/fields/type_ahead_field.coffee +10 -0
- data/src/components/form_button_toolbar.coffee +26 -0
- data/src/components/form_view.coffee +205 -0
- data/src/components/grid_view.coffee +208 -0
- data/src/components/record_manager.coffee +215 -0
- data/src/components/router.coffee +34 -0
- data/src/components/template.coffee +19 -0
- data/src/containers/card_view.coffee +89 -0
- data/src/containers/column_view.coffee +48 -0
- data/src/containers/modal_view.coffee +85 -0
- data/src/containers/panel_view.coffee +24 -0
- data/src/containers/split_view.coffee +12 -0
- data/src/containers/tab_view.coffee +77 -0
- data/src/containers/viewport.coffee +16 -0
- data/src/core/collection.coffee +319 -0
- data/src/core/container.coffee +256 -0
- data/src/core/field.coffee +68 -0
- data/src/core/observer.coffee +17 -0
- data/src/core/view.coffee +190 -0
- data/src/framework.coffee +110 -0
- data/src/index.coffee +255 -0
- data/src/managers/collection_manager.coffee +168 -0
- data/src/managers/socket_manager.coffee +54 -0
- data/src/modules/deferrable.coffee +18 -0
- data/src/modules/local_storage.coffee +50 -0
- data/src/stylesheets/base.scss +78 -0
- data/src/stylesheets/components/form_view.scss +54 -0
- data/src/stylesheets/components/grid_view.scss +111 -0
- data/src/stylesheets/components/toolbar.scss +15 -0
- data/src/stylesheets/containers/container.scss +7 -0
- data/src/stylesheets/containers/modal_view.scss +0 -0
- data/src/stylesheets/containers/tab_view.scss +33 -0
- data/src/stylesheets/normalize.scss +430 -0
- data/src/templates/components/bootstrap_form_controls.luca +7 -0
- data/src/templates/components/collection_loader_view.luca +5 -0
- data/src/templates/components/form_view.luca +15 -0
- data/src/templates/components/grid_view.luca +9 -0
- data/src/templates/components/grid_view_empty_text.luca +3 -0
- data/src/templates/containers/basic.luca +1 -0
- data/src/templates/containers/tab_selector_container.luca +8 -0
- data/src/templates/containers/tab_view.luca +1 -0
- data/src/templates/containers/toolbar_wrapper.luca +1 -0
- data/src/templates/fields/button_field.luca +2 -0
- data/src/templates/fields/button_field_link.luca +5 -0
- data/src/templates/fields/checkbox_field.luca +9 -0
- data/src/templates/fields/file_upload_field.luca +8 -0
- data/src/templates/fields/hidden_field.luca +1 -0
- data/src/templates/fields/select_field.luca +7 -0
- data/src/templates/fields/text_area_field.luca +8 -0
- data/src/templates/fields/text_field.luca +13 -0
- data/src/templates/sample/contents.luca +1 -0
- data/src/templates/sample/welcome.luca +1 -0
- data/vendor/assets/images/glyphicons-halflings-white.png +0 -0
- data/vendor/assets/images/glyphicons-halflings.png +0 -0
- data/vendor/assets/javascripts/luca-spec-dependencies.js +6135 -0
- data/vendor/assets/javascripts/luca-ui-base.js +1527 -0
- data/vendor/assets/javascripts/luca-ui-spec.js +3654 -0
- data/vendor/assets/javascripts/luca-ui.js +2763 -0
- data/vendor/assets/luca-ui/base.css +85 -0
- data/vendor/assets/luca-ui/components/application.js +91 -0
- data/vendor/assets/luca-ui/components/base_toolbar.js +23 -0
- data/vendor/assets/luca-ui/components/controller.js +38 -0
- data/vendor/assets/luca-ui/components/fields/button_field.js +45 -0
- data/vendor/assets/luca-ui/components/fields/checkbox_field.js +43 -0
- data/vendor/assets/luca-ui/components/fields/file_upload_field.js +20 -0
- data/vendor/assets/luca-ui/components/fields/hidden_field.js +20 -0
- data/vendor/assets/luca-ui/components/fields/select_field.js +97 -0
- data/vendor/assets/luca-ui/components/fields/text_area_field.js +48 -0
- data/vendor/assets/luca-ui/components/fields/text_field.js +46 -0
- data/vendor/assets/luca-ui/components/fields/type_ahead_field.js +13 -0
- data/vendor/assets/luca-ui/components/form_button_toolbar.js +32 -0
- data/vendor/assets/luca-ui/components/form_view.css +32 -0
- data/vendor/assets/luca-ui/components/form_view.js +207 -0
- data/vendor/assets/luca-ui/components/grid_view.css +76 -0
- data/vendor/assets/luca-ui/components/grid_view.js +202 -0
- data/vendor/assets/luca-ui/components/record_manager.js +207 -0
- data/vendor/assets/luca-ui/components/router.js +36 -0
- data/vendor/assets/luca-ui/components/template.js +26 -0
- data/vendor/assets/luca-ui/components/toolbar.css +11 -0
- data/vendor/assets/luca-ui/containers/card_view.js +98 -0
- data/vendor/assets/luca-ui/containers/column_view.js +52 -0
- data/vendor/assets/luca-ui/containers/container.css +3 -0
- data/vendor/assets/luca-ui/containers/modal_view.css +0 -0
- data/vendor/assets/luca-ui/containers/modal_view.js +87 -0
- data/vendor/assets/luca-ui/containers/panel_view.js +34 -0
- data/vendor/assets/luca-ui/containers/split_view.js +13 -0
- data/vendor/assets/luca-ui/containers/tab_view.css +16 -0
- data/vendor/assets/luca-ui/containers/tab_view.js +80 -0
- data/vendor/assets/luca-ui/containers/viewport.js +18 -0
- data/vendor/assets/luca-ui/core/collection.js +221 -0
- data/vendor/assets/luca-ui/core/container.js +205 -0
- data/vendor/assets/luca-ui/core/field.js +59 -0
- data/vendor/assets/luca-ui/core/observer.js +42 -0
- data/vendor/assets/luca-ui/core/view.js +127 -0
- data/vendor/assets/luca-ui/framework.js +110 -0
- data/vendor/assets/luca-ui/index.js +5 -0
- data/vendor/assets/luca-ui/managers/collection_manager.js +98 -0
- data/vendor/assets/luca-ui/managers/socket_manager.js +52 -0
- data/vendor/assets/luca-ui/modules/deferrable.js +21 -0
- data/vendor/assets/luca-ui/modules/local_storage.js +81 -0
- data/vendor/assets/luca-ui/normalize.css +359 -0
- data/vendor/assets/luca-ui/stylesheets/base.css +85 -0
- data/vendor/assets/luca-ui/stylesheets/components/form_view.css +32 -0
- data/vendor/assets/luca-ui/stylesheets/components/grid_view.css +76 -0
- data/vendor/assets/luca-ui/stylesheets/components/toolbar.css +11 -0
- data/vendor/assets/luca-ui/stylesheets/containers/container.css +3 -0
- data/vendor/assets/luca-ui/stylesheets/containers/modal_view.css +0 -0
- data/vendor/assets/luca-ui/stylesheets/containers/tab_view.css +16 -0
- data/vendor/assets/luca-ui/stylesheets/normalize.css +359 -0
- data/vendor/assets/luca-ui/templates/components/bootstrap_form_controls.js +4 -0
- data/vendor/assets/luca-ui/templates/components/form_view.js +4 -0
- data/vendor/assets/luca-ui/templates/components/grid_view.js +4 -0
- data/vendor/assets/luca-ui/templates/components/grid_view_empty_text.js +4 -0
- data/vendor/assets/luca-ui/templates/containers/basic.js +4 -0
- data/vendor/assets/luca-ui/templates/containers/tab_selector_container.js +4 -0
- data/vendor/assets/luca-ui/templates/containers/tab_view.js +4 -0
- data/vendor/assets/luca-ui/templates/containers/toolbar_wrapper.js +4 -0
- data/vendor/assets/luca-ui/templates/fields/button_field.js +4 -0
- data/vendor/assets/luca-ui/templates/fields/button_field_link.js +4 -0
- data/vendor/assets/luca-ui/templates/fields/checkbox_field.js +4 -0
- data/vendor/assets/luca-ui/templates/fields/file_upload_field.js +4 -0
- data/vendor/assets/luca-ui/templates/fields/hidden_field.js +4 -0
- data/vendor/assets/luca-ui/templates/fields/select_field.js +4 -0
- data/vendor/assets/luca-ui/templates/fields/text_area_field.js +4 -0
- data/vendor/assets/luca-ui/templates/fields/text_field.js +4 -0
- data/vendor/assets/luca-ui/templates/sample/contents.js +4 -0
- data/vendor/assets/luca-ui/templates/sample/welcome.js +4 -0
- data/vendor/assets/stylesheets/luca-spec-dependencies.css +166 -0
- data/vendor/assets/stylesheets/luca-ui-bootstrap.css +1201 -0
- data/vendor/assets/stylesheets/luca-ui-spec.css +586 -0
- data/vendor/assets/stylesheets/luca-ui.css +586 -0
- data/views/index.erb +20 -0
- data/views/jasmine.erb +22 -0
- data/views/spec_harness.erb +29 -0
- metadata +361 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
#### The Component Container
|
|
2
|
+
#
|
|
3
|
+
# The Component Container is a nestable component
|
|
4
|
+
# which is responsible for laying out the many components
|
|
5
|
+
# it contains, assigning them to a DOM container, and
|
|
6
|
+
# automatically instantiating and rendering the components
|
|
7
|
+
# in their proper place.
|
|
8
|
+
Luca.core.Container = Luca.View.extend
|
|
9
|
+
className: 'luca-ui-container'
|
|
10
|
+
|
|
11
|
+
componentClass: 'luca-ui-panel'
|
|
12
|
+
|
|
13
|
+
isContainer: true
|
|
14
|
+
|
|
15
|
+
hooks:[
|
|
16
|
+
"before:components",
|
|
17
|
+
"before:layout",
|
|
18
|
+
"after:components",
|
|
19
|
+
"after:layout",
|
|
20
|
+
"first:activation"
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
rendered: false
|
|
24
|
+
|
|
25
|
+
components: []
|
|
26
|
+
|
|
27
|
+
initialize: (@options={})->
|
|
28
|
+
_.extend @, @options
|
|
29
|
+
|
|
30
|
+
@setupHooks( Luca.core.Container::hooks )
|
|
31
|
+
|
|
32
|
+
Luca.View::initialize.apply @, arguments
|
|
33
|
+
|
|
34
|
+
#### Rendering Pipeline
|
|
35
|
+
#
|
|
36
|
+
# A container has nested components. these components
|
|
37
|
+
# are automatically rendered inside their own DOM element
|
|
38
|
+
# and then CSS configuration is generally applied to these
|
|
39
|
+
# DOM elements. Each component is assigned to this DOM
|
|
40
|
+
# element by specifying a @container property on the component.
|
|
41
|
+
#
|
|
42
|
+
# Each component is instantiated by looking up its @ctype propery
|
|
43
|
+
# in the Luca Component Registry. Then the components are rendered
|
|
44
|
+
# by having their @render() method called on them.
|
|
45
|
+
#
|
|
46
|
+
# Any class which extends Luca.View will have its defined render method
|
|
47
|
+
# wrapped in a method which triggers "before:render", and "after:render"
|
|
48
|
+
# before and after the defined render method.
|
|
49
|
+
#
|
|
50
|
+
# so you can expect the following, for any container or nested container
|
|
51
|
+
#
|
|
52
|
+
# DOM Element Manipulation:
|
|
53
|
+
#
|
|
54
|
+
# beforeRender()
|
|
55
|
+
# beforeLayout()
|
|
56
|
+
# prepareLayout()
|
|
57
|
+
# afterLayout()
|
|
58
|
+
#
|
|
59
|
+
# Luca / Backbone Component Manipulation
|
|
60
|
+
#
|
|
61
|
+
# beforeComponents()
|
|
62
|
+
# prepareComponents()
|
|
63
|
+
# createComponents()
|
|
64
|
+
# renderComponents() ->
|
|
65
|
+
# calls render() on each component, starting this whole cycle
|
|
66
|
+
#
|
|
67
|
+
# afterComponents()
|
|
68
|
+
#
|
|
69
|
+
# DOM Injection
|
|
70
|
+
#
|
|
71
|
+
# render()
|
|
72
|
+
# afterRender()
|
|
73
|
+
#
|
|
74
|
+
# For Components which are originally hidden
|
|
75
|
+
# ( card view, tab view, etc )
|
|
76
|
+
#
|
|
77
|
+
# firstActivation()
|
|
78
|
+
#
|
|
79
|
+
beforeRender: ()->
|
|
80
|
+
@debug "container before render"
|
|
81
|
+
@doLayout()
|
|
82
|
+
@doComponents()
|
|
83
|
+
|
|
84
|
+
doLayout: ()->
|
|
85
|
+
@debug "container do layout"
|
|
86
|
+
@trigger "before:layout", @
|
|
87
|
+
@prepareLayout()
|
|
88
|
+
@trigger "after:layout", @
|
|
89
|
+
|
|
90
|
+
doComponents: ()->
|
|
91
|
+
@debug "container do components"
|
|
92
|
+
|
|
93
|
+
@trigger "before:components", @, @components
|
|
94
|
+
@prepareComponents()
|
|
95
|
+
@createComponents()
|
|
96
|
+
@renderComponents()
|
|
97
|
+
@trigger "after:components", @, @components
|
|
98
|
+
|
|
99
|
+
applyPanelConfig: (panel, panelIndex)->
|
|
100
|
+
style_declarations = []
|
|
101
|
+
|
|
102
|
+
style_declarations.push "height: #{ (if _.isNumber(panel.height) then panel.height + 'px' else panel.height ) }" if panel.height
|
|
103
|
+
style_declarations.push "width: #{ (if _.isNumber(panel.width) then panel.width + 'px' else panel.width ) }" if panel.width
|
|
104
|
+
style_declarations.push "float: #{ panel.float }" if panel.float
|
|
105
|
+
|
|
106
|
+
config =
|
|
107
|
+
classes: panel?.classes || @componentClass
|
|
108
|
+
id: "#{ @cid }-#{ panelIndex }"
|
|
109
|
+
style: style_declarations.join(';')
|
|
110
|
+
|
|
111
|
+
# prepare layout is where you would perform the DOM element
|
|
112
|
+
# creation / manipulation for how your container lays out
|
|
113
|
+
# its components. Minimally you will want to set the
|
|
114
|
+
# container property on each component.
|
|
115
|
+
prepareLayout: ()->
|
|
116
|
+
@debug "container prepare layout"
|
|
117
|
+
@componentContainers = _( @components ).map (component, index) =>
|
|
118
|
+
@applyPanelConfig.apply @, [ component, index ]
|
|
119
|
+
|
|
120
|
+
if @appendContainers
|
|
121
|
+
_( @componentContainers ).each (container)=>
|
|
122
|
+
@$el.append Luca.templates["containers/basic"](container)
|
|
123
|
+
|
|
124
|
+
# prepare components is where you would set necessary object
|
|
125
|
+
# attributes on the components themselves.
|
|
126
|
+
prepareComponents: ()->
|
|
127
|
+
@debug "container prepare components"
|
|
128
|
+
@components = _( @components ).map (object, index) =>
|
|
129
|
+
panel = @componentContainers[ index ]
|
|
130
|
+
object.container = if @appendContainers then "##{ panel.id }" else @el
|
|
131
|
+
|
|
132
|
+
object
|
|
133
|
+
|
|
134
|
+
createComponents: ()->
|
|
135
|
+
@debug "container create components"
|
|
136
|
+
map = @componentIndex =
|
|
137
|
+
name_index: {}
|
|
138
|
+
cid_index: {}
|
|
139
|
+
|
|
140
|
+
@components = _( @components ).map (object, index)=>
|
|
141
|
+
# you can include normal backbone views as components
|
|
142
|
+
# you will want to make sure your render method handles
|
|
143
|
+
# adding the views @$el to the appropriate @container
|
|
144
|
+
component = if _.isObject( object ) and object.render and object.trigger
|
|
145
|
+
object
|
|
146
|
+
else
|
|
147
|
+
object.ctype ||= Luca.defaultComponentType || "template"
|
|
148
|
+
Luca.util.lazyComponent( object )
|
|
149
|
+
|
|
150
|
+
# if we're using base backbone views, then they don't extend themselves
|
|
151
|
+
# with their passed options, so this is a workaround
|
|
152
|
+
if !component.container and component.options.container
|
|
153
|
+
component.container = component.options.container
|
|
154
|
+
|
|
155
|
+
if map and component.cid?
|
|
156
|
+
map.cid_index[ component.cid ] = index
|
|
157
|
+
|
|
158
|
+
if map and component.name?
|
|
159
|
+
map.name_index[ component.name ] = index
|
|
160
|
+
|
|
161
|
+
component
|
|
162
|
+
|
|
163
|
+
@debug "components created", @components
|
|
164
|
+
# Trigger the Rendering Pipeline process on all of the nested
|
|
165
|
+
# components
|
|
166
|
+
renderComponents: (@debugMode="")->
|
|
167
|
+
@debug "container render components"
|
|
168
|
+
_(@components).each (component)=>
|
|
169
|
+
component.getParent = ()=> @
|
|
170
|
+
$( component.container ).append $(component.el)
|
|
171
|
+
|
|
172
|
+
try
|
|
173
|
+
component.render()
|
|
174
|
+
catch e
|
|
175
|
+
console.log "Error Rendering Component #{ component.name || component.cid }", component
|
|
176
|
+
console.log e.message
|
|
177
|
+
console.log e.stack
|
|
178
|
+
|
|
179
|
+
#### Container Activation
|
|
180
|
+
#
|
|
181
|
+
# When a container is first activated is a good time to perform
|
|
182
|
+
# operations which are not needed unless that component becomes
|
|
183
|
+
# visible. This first activation event should be relayed to all
|
|
184
|
+
# of the nested components. Components which hide / display
|
|
185
|
+
# other components, such as a CardView or TabContainer
|
|
186
|
+
# will trigger first:activation on the components as they become
|
|
187
|
+
# displayed.
|
|
188
|
+
firstActivation: ()->
|
|
189
|
+
_( @components ).each (component)=>
|
|
190
|
+
activator = @
|
|
191
|
+
|
|
192
|
+
# apply the first:activation trigger on the component, in the context of the component
|
|
193
|
+
# passing as arguments the component itself, and the component doing the activation
|
|
194
|
+
unless component?.previously_activated is true
|
|
195
|
+
component?.trigger?.apply component, ["first:activation", [component, activator] ]
|
|
196
|
+
component.previously_activated = true
|
|
197
|
+
|
|
198
|
+
#### Component Finder Methods
|
|
199
|
+
select: (attribute, value, deep=false)->
|
|
200
|
+
components = _( @components ).map (component)->
|
|
201
|
+
matches = []
|
|
202
|
+
test = component[ attribute ]
|
|
203
|
+
|
|
204
|
+
matches.push( component ) if test is value
|
|
205
|
+
|
|
206
|
+
if deep is true and component.isContainer is true
|
|
207
|
+
matches.push component.select(attribute, value, true)
|
|
208
|
+
|
|
209
|
+
_.compact matches
|
|
210
|
+
|
|
211
|
+
_.flatten( components )
|
|
212
|
+
|
|
213
|
+
findComponentByName: (name, deep=false)->
|
|
214
|
+
@findComponent(name, "name_index", deep)
|
|
215
|
+
|
|
216
|
+
findComponentById: (id, deep=false)->
|
|
217
|
+
@findComponent(id, "cid_index", deep)
|
|
218
|
+
|
|
219
|
+
findComponent: (needle, haystack="name", deep=false)->
|
|
220
|
+
position = @componentIndex?[ haystack ][ needle ]
|
|
221
|
+
component = @components?[ position ]
|
|
222
|
+
|
|
223
|
+
return component if component
|
|
224
|
+
|
|
225
|
+
if deep is true
|
|
226
|
+
sub_container = _( @components ).detect (component)-> component?.findComponent?(needle, haystack, true)
|
|
227
|
+
sub_container?.findComponent?(needle, haystack, true)
|
|
228
|
+
|
|
229
|
+
# run a function for each component in this container
|
|
230
|
+
# and any nested containers in those components, recursively
|
|
231
|
+
# pass false as the second argument to skip the deep recursion
|
|
232
|
+
eachComponent: (fn, deep=true)->
|
|
233
|
+
_( @components ).each (component)=>
|
|
234
|
+
fn.apply component, [component]
|
|
235
|
+
component?.eachComponent?.apply component, [fn,deep] if deep
|
|
236
|
+
|
|
237
|
+
indexOf: (name)->
|
|
238
|
+
names = _( @components ).pluck('name')
|
|
239
|
+
_( names ).indexOf(name)
|
|
240
|
+
|
|
241
|
+
activeComponent: ()->
|
|
242
|
+
return @ unless @activeItem
|
|
243
|
+
return @components[ @activeItem ]
|
|
244
|
+
|
|
245
|
+
componentElements: ()-> $(".#{ @componentClass }", @el)
|
|
246
|
+
|
|
247
|
+
getComponent: (needle)->
|
|
248
|
+
@components[ needle ]
|
|
249
|
+
|
|
250
|
+
rootComponent: ()->
|
|
251
|
+
!@getParent?
|
|
252
|
+
|
|
253
|
+
getRootComponent: ()->
|
|
254
|
+
if @rootComponent() then @ else @getParent().getRootComponent()
|
|
255
|
+
|
|
256
|
+
Luca.register "container", "Luca.core.Container"
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
Luca.core.Field = Luca.View.extend
|
|
2
|
+
className: 'luca-ui-text-field luca-ui-field'
|
|
3
|
+
|
|
4
|
+
isField: true
|
|
5
|
+
|
|
6
|
+
template: 'fields/text_field'
|
|
7
|
+
|
|
8
|
+
labelAlign: 'top'
|
|
9
|
+
|
|
10
|
+
hooks:[
|
|
11
|
+
"before:validation",
|
|
12
|
+
"after:validation",
|
|
13
|
+
"on:change"
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
# see: http://twitter.github.com/bootstrap/base-css.html
|
|
17
|
+
statuses: [
|
|
18
|
+
"warning"
|
|
19
|
+
"error"
|
|
20
|
+
"success"
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
initialize: (@options={})->
|
|
24
|
+
_.extend @, @options
|
|
25
|
+
Luca.View::initialize.apply(@, arguments)
|
|
26
|
+
|
|
27
|
+
@input_id ||= _.uniqueId('field')
|
|
28
|
+
@input_name ||= @name
|
|
29
|
+
@helperText ||= ""
|
|
30
|
+
@label ||= "*#{ @label }" if @required and not @label?.match(/^\*/)
|
|
31
|
+
@inputStyles ||= ""
|
|
32
|
+
|
|
33
|
+
@disable() if @disabled
|
|
34
|
+
|
|
35
|
+
@updateState( @state )
|
|
36
|
+
@placeHolder ||= ""
|
|
37
|
+
|
|
38
|
+
beforeRender: ()->
|
|
39
|
+
if Luca.enableBootstrap
|
|
40
|
+
@$el.addClass('control-group')
|
|
41
|
+
|
|
42
|
+
@$el.addClass('required') if @required
|
|
43
|
+
|
|
44
|
+
@$el.html Luca.templates[ @template ]( @ )
|
|
45
|
+
@input = $('input', @el)
|
|
46
|
+
|
|
47
|
+
change_handler: (e)->
|
|
48
|
+
@trigger "on:change", @, e
|
|
49
|
+
|
|
50
|
+
disable: ()->
|
|
51
|
+
$("input",@el).attr('disabled', true)
|
|
52
|
+
|
|
53
|
+
enable: ()->
|
|
54
|
+
$("input", @el).attr('disabled', false)
|
|
55
|
+
|
|
56
|
+
getValue: ()->
|
|
57
|
+
@input.attr('value')
|
|
58
|
+
|
|
59
|
+
render: ()->
|
|
60
|
+
$( @container ).append( @$el )
|
|
61
|
+
|
|
62
|
+
setValue: (value)->
|
|
63
|
+
@input.attr('value', value)
|
|
64
|
+
|
|
65
|
+
updateState: (state)->
|
|
66
|
+
_( @statuses ).each (cls)=>
|
|
67
|
+
@$el.removeClass(cls)
|
|
68
|
+
@$el.addClass(state)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class Luca.Observer
|
|
2
|
+
constructor: (@options={})->
|
|
3
|
+
_.extend @, Backbone.Events
|
|
4
|
+
@type = @options.type
|
|
5
|
+
|
|
6
|
+
if @options.debugAll
|
|
7
|
+
@bind "event", (t, args...)=>
|
|
8
|
+
console.log "Observed #{ @type } #{ (t.name || t.id || t.cid) }", t, _(args).flatten()
|
|
9
|
+
|
|
10
|
+
relay: (triggerer, args...)->
|
|
11
|
+
@trigger "event", triggerer, args
|
|
12
|
+
@trigger "event:#{ args[0] }", triggerer, args.slice(1)
|
|
13
|
+
|
|
14
|
+
Luca.Observer.enableObservers = (options={})->
|
|
15
|
+
Luca.enableGlobalObserver = true
|
|
16
|
+
Luca.ViewObserver = new Luca.Observer _.extend(options, type:"view")
|
|
17
|
+
Luca.CollectionObserver = new Luca.Observer _.extend(options, type:"collection")
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#### Luca Base View
|
|
2
|
+
Luca.View = Backbone.View.extend
|
|
3
|
+
base: 'Luca.View'
|
|
4
|
+
|
|
5
|
+
# The Luca.View class adds some very commonly used patterns
|
|
6
|
+
# and functionality to the stock Backbone.View class. Features
|
|
7
|
+
# such as auto event binding, the facilitation of deferred rendering
|
|
8
|
+
# against a Backbone.Model or Backbone.Collection reset event, Caching
|
|
9
|
+
# views into a global Component Registry, and more.
|
|
10
|
+
|
|
11
|
+
Luca.View.originalExtend = Backbone.View.extend
|
|
12
|
+
|
|
13
|
+
# By overriding Backbone.View.extend we are able to intercept
|
|
14
|
+
# some method definitions and add special behavior around them
|
|
15
|
+
# mostly related to render()
|
|
16
|
+
Luca.View.extend = (definition)->
|
|
17
|
+
#### Rendering
|
|
18
|
+
#
|
|
19
|
+
# Our base view class wraps the defined render() method
|
|
20
|
+
# of the views which inherit from it, and does things like
|
|
21
|
+
# trigger the before and after render events automatically.
|
|
22
|
+
# In addition, if the view has a deferrable property on it
|
|
23
|
+
# then it will make sure that the render method doesn't get called
|
|
24
|
+
# until.
|
|
25
|
+
|
|
26
|
+
_base = definition.render
|
|
27
|
+
|
|
28
|
+
_base ||= ()->
|
|
29
|
+
container = if _.isFunction(@container) then @container() else @container
|
|
30
|
+
|
|
31
|
+
return @ unless $(container) and @$el
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
$(container).append( @$el )
|
|
35
|
+
@
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
definition.render = ()->
|
|
39
|
+
if @deferrable
|
|
40
|
+
@trigger "before:render", @
|
|
41
|
+
|
|
42
|
+
@deferrable.bind @deferrable_event, _.once ()=>
|
|
43
|
+
_base.apply(@, arguments)
|
|
44
|
+
@trigger "after:render", @
|
|
45
|
+
|
|
46
|
+
# we might not want to fetch immediately upon
|
|
47
|
+
# rendering, so we can pass a deferrable_trigger
|
|
48
|
+
# event and not fire the fetch until this event
|
|
49
|
+
# occurs
|
|
50
|
+
if !@deferrable_trigger
|
|
51
|
+
@immediate_trigger = true
|
|
52
|
+
|
|
53
|
+
if @immediate_trigger is true
|
|
54
|
+
@deferrable.fetch()
|
|
55
|
+
else
|
|
56
|
+
@bind @deferrable_trigger, _.once ()=>
|
|
57
|
+
@deferrable.fetch()
|
|
58
|
+
|
|
59
|
+
else
|
|
60
|
+
@trigger "before:render", @
|
|
61
|
+
_base.apply(@, arguments)
|
|
62
|
+
@trigger "after:render", @
|
|
63
|
+
|
|
64
|
+
Luca.View.originalExtend.apply @, [definition]
|
|
65
|
+
|
|
66
|
+
_.extend Luca.View.prototype,
|
|
67
|
+
debug: ()->
|
|
68
|
+
return unless @debugMode or window.LucaDebugMode?
|
|
69
|
+
console.log [(@name || @cid),message] for message in arguments
|
|
70
|
+
|
|
71
|
+
trigger: ()->
|
|
72
|
+
if Luca.enableGlobalObserver
|
|
73
|
+
Luca.ViewObserver ||= new Luca.Observer(type:"view")
|
|
74
|
+
Luca.ViewObserver.relay @, arguments
|
|
75
|
+
|
|
76
|
+
Backbone.View.prototype.trigger.apply @, arguments
|
|
77
|
+
|
|
78
|
+
hooks:[
|
|
79
|
+
"after:initialize"
|
|
80
|
+
"before:render"
|
|
81
|
+
"after:render"
|
|
82
|
+
"first:activation"
|
|
83
|
+
"activation"
|
|
84
|
+
"deactivation"
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
# which event should we listen to on
|
|
88
|
+
# our deferrable property, before we
|
|
89
|
+
# trigger the actual rendering
|
|
90
|
+
deferrable_event: "reset"
|
|
91
|
+
|
|
92
|
+
initialize: (@options={})->
|
|
93
|
+
|
|
94
|
+
_.extend @, @options
|
|
95
|
+
|
|
96
|
+
@cid = _.uniqueId(@name) if @name?
|
|
97
|
+
|
|
98
|
+
#### View Caching
|
|
99
|
+
#
|
|
100
|
+
# Luca.View(s) which get created get stored in a global cache by their
|
|
101
|
+
# component id. This allows us to re-use views when it makes sense
|
|
102
|
+
Luca.cache( @cid, @ )
|
|
103
|
+
|
|
104
|
+
unique = _( Luca.View.prototype.hooks.concat( @hooks ) ).uniq()
|
|
105
|
+
|
|
106
|
+
@setupHooks( unique )
|
|
107
|
+
|
|
108
|
+
if @autoBindEventHandlers is true
|
|
109
|
+
_( @events ).each (handler,event)=>
|
|
110
|
+
if _.isString(handler)
|
|
111
|
+
_.bindAll @, handler
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@trigger "after:initialize", @
|
|
115
|
+
|
|
116
|
+
@registerCollectionEvents()
|
|
117
|
+
|
|
118
|
+
$container: ()-> $(@container)
|
|
119
|
+
#### Hooks or Auto Event Binding
|
|
120
|
+
#
|
|
121
|
+
# views which inherit from Luca.View can define hooks
|
|
122
|
+
# or events which can be emitted from them. Automatically,
|
|
123
|
+
# any functions on the view which are named according to the
|
|
124
|
+
# convention will automatically get run.
|
|
125
|
+
#
|
|
126
|
+
# by default, all Luca.View classes come with the following:
|
|
127
|
+
#
|
|
128
|
+
# before:render : beforeRender()
|
|
129
|
+
# after:render : afterRender()
|
|
130
|
+
# after:initialize : afterInitialize()
|
|
131
|
+
# first:activation : firstActivation()
|
|
132
|
+
setupHooks: (set)->
|
|
133
|
+
set ||= @hooks
|
|
134
|
+
|
|
135
|
+
_(set).each (event)=>
|
|
136
|
+
parts = event.split(':')
|
|
137
|
+
prefix = parts.shift()
|
|
138
|
+
|
|
139
|
+
parts = _( parts ).map (p)-> _.capitalize(p)
|
|
140
|
+
fn = prefix + parts.join('')
|
|
141
|
+
|
|
142
|
+
@bind event, ()=> @[fn].apply @, arguments if @[fn]
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
#### Luca.Collection and Luca.CollectionManager integration
|
|
146
|
+
|
|
147
|
+
# under the hood, this will find your collection manager using
|
|
148
|
+
# Luca.CollectionManager.get, which is a function that returns
|
|
149
|
+
# the first instance of the CollectionManager class ever created.
|
|
150
|
+
#
|
|
151
|
+
# if you want to use more than one collection manager, over ride this
|
|
152
|
+
# function in your views with your own logic
|
|
153
|
+
getCollectionManager: ()->
|
|
154
|
+
@collectionManager || Luca.CollectionManager.get?.call()
|
|
155
|
+
|
|
156
|
+
##### Collection Events
|
|
157
|
+
#
|
|
158
|
+
# By defining a hash of collectionEvents in the form of
|
|
159
|
+
#
|
|
160
|
+
# "books add" : "onBookAdd"
|
|
161
|
+
#
|
|
162
|
+
# the Luca.View will bind to the collection found in the
|
|
163
|
+
# collectionManager with that key, and bind to that event.
|
|
164
|
+
# a property of @booksCollection will be created on the view,
|
|
165
|
+
# and the "add" event will trigger "onBookAdd"
|
|
166
|
+
#
|
|
167
|
+
# you may also specify a function directly. this
|
|
168
|
+
#
|
|
169
|
+
registerCollectionEvents: ()->
|
|
170
|
+
manager = @getCollectionManager()
|
|
171
|
+
|
|
172
|
+
_( @collectionEvents ).each (handler, signature)=>
|
|
173
|
+
[key,event] = signature.split(" ")
|
|
174
|
+
|
|
175
|
+
collection = @["#{ key }Collection"] = manager.getOrCreate( key )
|
|
176
|
+
|
|
177
|
+
if !collection
|
|
178
|
+
throw "Could not find collection specified by #{ key }"
|
|
179
|
+
|
|
180
|
+
if _.isString(handler)
|
|
181
|
+
handler = @[handler]
|
|
182
|
+
|
|
183
|
+
unless _.isFunction(handler)
|
|
184
|
+
throw "invalid collectionEvents configuration"
|
|
185
|
+
|
|
186
|
+
try
|
|
187
|
+
collection.bind(event, handler)
|
|
188
|
+
catch e
|
|
189
|
+
console.log "Error Binding To Collection in registerCollectionEvents", @
|
|
190
|
+
throw e
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
_.mixin( _.string )
|
|
2
|
+
|
|
3
|
+
window.Luca =
|
|
4
|
+
VERSION: "0.6.6"
|
|
5
|
+
core: {}
|
|
6
|
+
containers: {}
|
|
7
|
+
components: {}
|
|
8
|
+
modules: {}
|
|
9
|
+
fields: {}
|
|
10
|
+
util: {}
|
|
11
|
+
registry:
|
|
12
|
+
classes: {}
|
|
13
|
+
namespaces:["Luca.containers","Luca.components"]
|
|
14
|
+
component_cache:
|
|
15
|
+
cid_index: {}
|
|
16
|
+
name_index: {}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# let's use the Twitter 2.0 Bootstrap Framework
|
|
20
|
+
# for what it is best at, and not try to solve this
|
|
21
|
+
# problem on our own!
|
|
22
|
+
Luca.enableBootstrap = true
|
|
23
|
+
|
|
24
|
+
# adds an additional namespace to look for luca ui
|
|
25
|
+
# components. useful for when you define a bunch of
|
|
26
|
+
# components in your own application's namespace
|
|
27
|
+
Luca.registry.addNamespace = (identifier)->
|
|
28
|
+
Luca.registry.namespaces.push( identifier )
|
|
29
|
+
Luca.registry.namespaces = _( Luca.registry.namespaces ).uniq()
|
|
30
|
+
|
|
31
|
+
# stores or looks up a component in the component cache
|
|
32
|
+
# by its backbone @cid or by its component_name
|
|
33
|
+
Luca.cache = (needle, component)->
|
|
34
|
+
Luca.component_cache.cid_index[ needle ] = component if component?
|
|
35
|
+
|
|
36
|
+
component = Luca.component_cache.cid_index[ needle ]
|
|
37
|
+
|
|
38
|
+
# optionally, cache it by tying its name to its cid for easier lookups
|
|
39
|
+
if component?.component_name?
|
|
40
|
+
Luca.component_cache.name_index[ component.component_name ] = component.cid
|
|
41
|
+
else if component?.name?
|
|
42
|
+
Luca.component_cache.name_index[ component.name ] = component.cid
|
|
43
|
+
|
|
44
|
+
return component if component?
|
|
45
|
+
|
|
46
|
+
# perform a lookup by name if the component_id didn't turn anything
|
|
47
|
+
lookup_id = Luca.component_cache.name_index[ needle ]
|
|
48
|
+
|
|
49
|
+
Luca.component_cache.cid_index[ lookup_id ]
|
|
50
|
+
|
|
51
|
+
# Takes an string like "deep.nested.value" and an object like window
|
|
52
|
+
# and returns the value of window.deep.nested.value
|
|
53
|
+
Luca.util.nestedValue = (accessor, source_object)->
|
|
54
|
+
_( accessor.split(/\./) ).inject (obj,key)->
|
|
55
|
+
obj = obj?[key]
|
|
56
|
+
, source_object
|
|
57
|
+
|
|
58
|
+
# Lookup a component in the Luca component registry
|
|
59
|
+
# by it's ctype identifier. If it doesn't exist,
|
|
60
|
+
# check any other registered namespace
|
|
61
|
+
Luca.registry.lookup = (ctype)->
|
|
62
|
+
c = Luca.registry.classes[ctype]
|
|
63
|
+
|
|
64
|
+
return c if c?
|
|
65
|
+
|
|
66
|
+
className = _.camelize _.capitalize( ctype )
|
|
67
|
+
|
|
68
|
+
parents = _( Luca.registry.namespaces ).map (namespace)-> Luca.util.nestedValue(namespace, (window || global))
|
|
69
|
+
|
|
70
|
+
_.first _.compact _( parents ).map (parent)-> parent[className]
|
|
71
|
+
|
|
72
|
+
# creates a new object from a hash with a ctype property
|
|
73
|
+
# matching something in the Luca registry
|
|
74
|
+
Luca.util.lazyComponent = (config)->
|
|
75
|
+
ctype = config.ctype
|
|
76
|
+
|
|
77
|
+
componentClass = Luca.registry.lookup( ctype )
|
|
78
|
+
|
|
79
|
+
throw "Invalid Component Type: #{ ctype }. Did you forget to register it?" unless componentClass
|
|
80
|
+
|
|
81
|
+
constructor = eval( componentClass )
|
|
82
|
+
|
|
83
|
+
new constructor(config)
|
|
84
|
+
|
|
85
|
+
# for lazy component creation
|
|
86
|
+
Luca.register = (component, constructor_class)->
|
|
87
|
+
exists = Luca.registry.classes[component]
|
|
88
|
+
|
|
89
|
+
if exists?
|
|
90
|
+
throw "Can not register component with the signature #{ component }. Already exists"
|
|
91
|
+
else
|
|
92
|
+
Luca.registry.classes[component] = constructor_class
|
|
93
|
+
|
|
94
|
+
Luca.available_templates = (filter="")->
|
|
95
|
+
available = _( Luca.templates ).keys()
|
|
96
|
+
|
|
97
|
+
if filter.length > 0
|
|
98
|
+
_( available ).select (tmpl)-> tmpl.match(filter)
|
|
99
|
+
else
|
|
100
|
+
available
|
|
101
|
+
|
|
102
|
+
Luca.util.isIE = ()->
|
|
103
|
+
try
|
|
104
|
+
Object.defineProperty({}, '', {})
|
|
105
|
+
return false
|
|
106
|
+
catch e
|
|
107
|
+
return true
|
|
108
|
+
|
|
109
|
+
$ do ->
|
|
110
|
+
$('body').addClass('luca-ui-enabled')
|