luca 0.8.599 → 0.9.0
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 +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,181 @@
|
|
1
|
+
# Component Definition Helpers
|
2
|
+
#
|
3
|
+
#
|
4
|
+
# We have customized the core Backbone.extend process to use a slightly
|
5
|
+
# different syntax, which allows us to intercept the component definition at
|
6
|
+
# various points, and maintain information about classes being defined, and
|
7
|
+
# the relationships between inherited classes, etc.
|
8
|
+
|
9
|
+
# _.def, or Luca.define returns a chainable object which allows you to define
|
10
|
+
# your components with a readable syntax. For example:
|
11
|
+
|
12
|
+
# _.def("Luca.View").extends("Backbone.View").with the_good:"shit"
|
13
|
+
# _.def("MyView").extends("Luca.View").with the_custom:"shit"
|
14
|
+
|
15
|
+
Luca.define = (componentName)->
|
16
|
+
new DefineProxy(componentName)
|
17
|
+
|
18
|
+
Luca.component = Luca.define
|
19
|
+
|
20
|
+
# The define proxy chain sets up a call to Luca.extend, which is a wrapper around Luca and Backbone component class' extend function.
|
21
|
+
class DefineProxy
|
22
|
+
constructor:(componentName)->
|
23
|
+
@namespace = Luca.util.namespace()
|
24
|
+
@componentId = @componentName = componentName
|
25
|
+
|
26
|
+
if componentName.match(/\./)
|
27
|
+
@namespaced = true
|
28
|
+
parts = componentName.split('.')
|
29
|
+
@componentId = parts.pop()
|
30
|
+
@namespace = parts.join('.')
|
31
|
+
|
32
|
+
# automatically add the namespace to the namespace registry
|
33
|
+
Luca.registry.addNamespace( parts.join('.') )
|
34
|
+
|
35
|
+
# allow for specifying the namespace
|
36
|
+
in: (@namespace)-> @
|
37
|
+
|
38
|
+
# allow for multiple ways of saying the same thing for readability purposes
|
39
|
+
from: (@superClassName)-> @
|
40
|
+
extends: (@superClassName)-> @
|
41
|
+
extend: (@superClassName)-> @
|
42
|
+
|
43
|
+
# an alias for with, or a readability helper in multi-line definitions
|
44
|
+
enhance: (properties)->
|
45
|
+
return @with(properties) if properties?
|
46
|
+
@
|
47
|
+
|
48
|
+
# which properties, methods, etc will you be extending the base class with?
|
49
|
+
with: (properties)->
|
50
|
+
at = if @namespaced
|
51
|
+
Luca.util.resolve(@namespace, (window || global))
|
52
|
+
else
|
53
|
+
(window||global)
|
54
|
+
|
55
|
+
# automatically create the namespace
|
56
|
+
if @namespaced and not at?
|
57
|
+
eval("(window||global).#{ @namespace } = {}")
|
58
|
+
at = Luca.util.resolve(@namespace,(window || global))
|
59
|
+
|
60
|
+
at[@componentId] = Luca.extend(@superClassName,@componentName, properties)
|
61
|
+
|
62
|
+
# automatically register this with the component registry
|
63
|
+
Luca.register( _.string.underscored(@componentId), @componentName)
|
64
|
+
|
65
|
+
at[@componentId]
|
66
|
+
|
67
|
+
# The last method of the DefineProxy chain is always going to result in
|
68
|
+
# a call to Luca.extend. Luca.extend wraps the call to Luca.View.extend,
|
69
|
+
# or Backbone.Collection.extend, and accepts the names of the extending,
|
70
|
+
# and extended classes as strings. This allows us to maintain information
|
71
|
+
# and references to the classes and their prototypes, mainly for the purposes
|
72
|
+
# of introspection and development tools
|
73
|
+
Luca.extend = (superClassName, childName, properties={})->
|
74
|
+
superClass = Luca.util.resolve( superClassName, (window || global) )
|
75
|
+
|
76
|
+
unless _.isFunction(superClass?.extend)
|
77
|
+
throw "#{ superClassName } is not a valid component to extend from"
|
78
|
+
|
79
|
+
properties.displayName = childName
|
80
|
+
|
81
|
+
properties._superClass = ()->
|
82
|
+
superClass.displayName ||= superClassName
|
83
|
+
superClass
|
84
|
+
|
85
|
+
properties._super = (method, context, args)->
|
86
|
+
@_superClass().prototype[method]?.apply(context, args)
|
87
|
+
|
88
|
+
superClass.extend(properties)
|
89
|
+
|
90
|
+
_.mixin
|
91
|
+
def: Luca.define
|
92
|
+
|
93
|
+
|
94
|
+
# Luca.Events
|
95
|
+
#
|
96
|
+
# These helpers will get mixed into Luca.Collection, Luca.View, and Luca.Model.
|
97
|
+
#
|
98
|
+
# They allow for syntactic sugar like:
|
99
|
+
#
|
100
|
+
# view.defer("someMethodOnTheView").until("collection","fetch")
|
101
|
+
#
|
102
|
+
# or
|
103
|
+
#
|
104
|
+
# view.defer( myCallback ).until("triggered:event")
|
105
|
+
class DeferredBindingProxy
|
106
|
+
constructor: (@object, operation, wrapWithUnderscore=true)->
|
107
|
+
if _.isFunction(operation)
|
108
|
+
fn = operation
|
109
|
+
|
110
|
+
else if _.isString(operation) and _.isFunction(@object[operation])
|
111
|
+
fn = @object[operation]
|
112
|
+
|
113
|
+
unless _.isFunction(fn)
|
114
|
+
throw "Must pass a function or a string representing one"
|
115
|
+
|
116
|
+
if wrapWithUnderscore is true
|
117
|
+
@fn = ()=>
|
118
|
+
_.defer(fn)
|
119
|
+
else
|
120
|
+
@fn = fn
|
121
|
+
|
122
|
+
@
|
123
|
+
|
124
|
+
# until accepts an object to bind to, and a trigger to bind with
|
125
|
+
# if you just pass a trigger, the object getting bound to
|
126
|
+
# will implicitly be @object
|
127
|
+
until: (watch, trigger)->
|
128
|
+
if watch? and not trigger?
|
129
|
+
trigger = watch
|
130
|
+
watch = @object
|
131
|
+
|
132
|
+
watch.once(trigger, @fn)
|
133
|
+
|
134
|
+
@object
|
135
|
+
|
136
|
+
Luca.Events =
|
137
|
+
defer: (operation, wrapWithUnderscore=true)->
|
138
|
+
new DeferredBindingProxy(@, operation, wrapWithUnderscore)
|
139
|
+
|
140
|
+
once: (trigger, callback, context)->
|
141
|
+
context ||= @
|
142
|
+
|
143
|
+
onceFn = ()->
|
144
|
+
callback.apply(context, arguments)
|
145
|
+
@unbind(trigger, onceFn)
|
146
|
+
|
147
|
+
@bind trigger, onceFn
|
148
|
+
|
149
|
+
class Luca.ScriptLoader
|
150
|
+
@loaded: {}
|
151
|
+
|
152
|
+
constructor: (options={})->
|
153
|
+
_.extend(@, Backbone.Events, Luca.Events)
|
154
|
+
@autoStart = options.autoStart is true
|
155
|
+
@scripts = options.scripts
|
156
|
+
|
157
|
+
ready = ()-> @trigger("ready")
|
158
|
+
|
159
|
+
@ready = _.after( @scripts.length, ready)
|
160
|
+
|
161
|
+
_.bindAll @, "load", "ready"
|
162
|
+
|
163
|
+
@defer("load").until(@, "start")
|
164
|
+
|
165
|
+
if @autoStart is true
|
166
|
+
@trigger("start")
|
167
|
+
|
168
|
+
@bind "ready", @onReady
|
169
|
+
|
170
|
+
applyPrefix: (script)->
|
171
|
+
script
|
172
|
+
|
173
|
+
onReady: ()->
|
174
|
+
console.log "All dependencies loaded"
|
175
|
+
|
176
|
+
start: ()->
|
177
|
+
@trigger("start")
|
178
|
+
|
179
|
+
load: ()->
|
180
|
+
Luca.util.loadScript( @applyPrefix(script), @ready ) for script in @scripts
|
181
|
+
|
data/src/core/field.coffee
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
_.
|
1
|
+
_.def('Luca.core.Field').extends('Luca.View').with
|
2
2
|
|
3
3
|
className: 'luca-ui-text-field luca-ui-field'
|
4
4
|
|
@@ -23,10 +23,10 @@ _.component('Luca.core.Field').extends('Luca.View').with
|
|
23
23
|
|
24
24
|
initialize: (@options={})->
|
25
25
|
_.extend @, @options
|
26
|
-
Luca.View::initialize.apply(@, arguments)
|
27
26
|
|
28
27
|
@input_id ||= _.uniqueId('field')
|
29
28
|
@input_name ||= @name
|
29
|
+
@input_class ||= ""
|
30
30
|
@helperText ||= ""
|
31
31
|
@label ||= "*#{ @label }" if @required and not @label?.match(/^\*/)
|
32
32
|
@inputStyles ||= ""
|
@@ -36,6 +36,8 @@ _.component('Luca.core.Field').extends('Luca.View').with
|
|
36
36
|
@updateState( @state )
|
37
37
|
@placeHolder ||= ""
|
38
38
|
|
39
|
+
Luca.View::initialize.apply(@, arguments)
|
40
|
+
|
39
41
|
beforeRender: ()->
|
40
42
|
if Luca.enableBootstrap
|
41
43
|
@$el.addClass('control-group')
|
data/src/core/model.coffee
CHANGED
data/src/core/observer.coffee
CHANGED
@@ -4,10 +4,10 @@ class Luca.Observer
|
|
4
4
|
@type = @options.type
|
5
5
|
|
6
6
|
if @options.debugAll
|
7
|
-
@bind "
|
8
|
-
console.log "
|
9
|
-
|
7
|
+
@bind "all", (trigger, one, two)=>
|
8
|
+
console.log "ALL", trigger, one, two
|
10
9
|
relay: (triggerer, args...)->
|
10
|
+
console.log "Relaying", trigger, args
|
11
11
|
@trigger "event", triggerer, args
|
12
12
|
@trigger "event:#{ args[0] }", triggerer, args.slice(1)
|
13
13
|
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# This is a helper for creating the DOM element that go along with
|
2
|
+
# a given component, if it is configured to use one via the topToolbar
|
3
|
+
# and bottomToolbar properties
|
4
|
+
attachToolbar = (config={})->
|
5
|
+
config.orientation ||= "top"
|
6
|
+
config.ctype ||= @toolbarType || "panel_toolbar"
|
7
|
+
|
8
|
+
id = "#{ @cid }-tbc-#{ config.orientation }"
|
9
|
+
|
10
|
+
toolbar = Luca.util.lazyComponent( config )
|
11
|
+
|
12
|
+
container = @make "div",
|
13
|
+
class:"toolbar-container #{ config.orientation }",
|
14
|
+
id: id
|
15
|
+
,
|
16
|
+
toolbar.render().el
|
17
|
+
|
18
|
+
hasBody = @bodyClassName or @bodyTagName
|
19
|
+
|
20
|
+
# there will be a body panel inside of the views $el
|
21
|
+
# so just place the toolbar before, or after the body
|
22
|
+
action = switch config.orientation
|
23
|
+
when "top", "left"
|
24
|
+
if hasBody then "before" else "prepend"
|
25
|
+
when "bottom", "right"
|
26
|
+
if hasBody then "after" else "append"
|
27
|
+
|
28
|
+
@$bodyEl()[action]( container )
|
29
|
+
|
30
|
+
# A Panel is a basic Luca.View but with Toolbar extensions
|
31
|
+
#
|
32
|
+
# In general other components should inherit from the panel class.
|
33
|
+
|
34
|
+
_.def("Luca.components.Panel").extends("Luca.View").with
|
35
|
+
|
36
|
+
topToolbar: undefined
|
37
|
+
|
38
|
+
bottomToolbar: undefined
|
39
|
+
|
40
|
+
# Load Mask will apply a transparent overlay over the form
|
41
|
+
# upon submission, with a moving progress bar which will be
|
42
|
+
# hidden upon successful response
|
43
|
+
loadMask: false
|
44
|
+
loadMaskTemplate: ["components/load_mask"]
|
45
|
+
|
46
|
+
initialize: (@options={})->
|
47
|
+
Luca.View::initialize.apply(@, arguments)
|
48
|
+
|
49
|
+
if @loadMask is true
|
50
|
+
@defer ()=>
|
51
|
+
@$el.addClass('with-mask')
|
52
|
+
|
53
|
+
if @$('.load-mask').length is 0
|
54
|
+
@loadMaskTarget().prepend Luca.template(@loadMaskTemplate, @)
|
55
|
+
@$('.load-mask').hide()
|
56
|
+
.until("after:render")
|
57
|
+
|
58
|
+
@on "enable:loadmask", @applyLoadMask
|
59
|
+
@on "disable:loadmask", @applyLoadMask
|
60
|
+
|
61
|
+
loadMaskTarget: ()->
|
62
|
+
if @loadMaskEl? then @$(@loadMaskEl) else @$bodyEl()
|
63
|
+
|
64
|
+
applyLoadMask: ()->
|
65
|
+
if @$('.load-mask').is(":visible")
|
66
|
+
@$('.load-mask .bar').css("width","100%")
|
67
|
+
@$('.load-mask').hide()
|
68
|
+
clearInterval(@loadMaskInterval)
|
69
|
+
else
|
70
|
+
@$('.load-mask').show().find('.bar').css("width","0%")
|
71
|
+
maxWidth = @$('.load-mask .progress').width()
|
72
|
+
if maxWidth < 20 and (maxWidth = @$el.width()) < 20
|
73
|
+
maxWidth = @$el.parent().width()
|
74
|
+
|
75
|
+
@loadMaskInterval = setInterval ()=>
|
76
|
+
currentWidth = @$('.load-mask .bar').width()
|
77
|
+
newWidth = currentWidth + 12
|
78
|
+
@$('.load-mask .bar').css('width', newWidth)
|
79
|
+
, 200
|
80
|
+
|
81
|
+
applyStyles: (styles={},body=false)->
|
82
|
+
|
83
|
+
target = if body then @$bodyEl() else @$el
|
84
|
+
|
85
|
+
for setting, value of styles
|
86
|
+
target.css(setting,value)
|
87
|
+
|
88
|
+
@
|
89
|
+
|
90
|
+
beforeRender: ()->
|
91
|
+
Luca.View::beforeRender?.apply(@, arguments)
|
92
|
+
@applyStyles( @styles ) if @styles?
|
93
|
+
@applyStyles( @bodyStyles, true ) if @bodyStyles?
|
94
|
+
@renderToolbars?()
|
95
|
+
|
96
|
+
$bodyEl: ()->
|
97
|
+
element = @bodyTagName || "div"
|
98
|
+
className = @bodyClassName || "view-body"
|
99
|
+
|
100
|
+
@bodyEl ||= "#{ element }.#{ className }"
|
101
|
+
|
102
|
+
bodyEl = @$(@bodyEl)
|
103
|
+
|
104
|
+
return bodyEl if bodyEl.length > 0
|
105
|
+
|
106
|
+
# if we've been configured to have one, and it doesn't exist
|
107
|
+
# then we should append it to ourselves
|
108
|
+
if bodyEl.length is 0 and (@bodyClassName? || @bodyTagName?)
|
109
|
+
newElement = @make(element,class:className,"data-auto-appended":true)
|
110
|
+
$(@el).append( newElement )
|
111
|
+
return @$(@bodyEl)
|
112
|
+
|
113
|
+
|
114
|
+
$(@el)
|
115
|
+
|
116
|
+
$wrap: (wrapper)->
|
117
|
+
if !wrapper.match(/[<>]/)
|
118
|
+
wrapper = @make("div",class:wrapper)
|
119
|
+
|
120
|
+
@$el.wrap( wrapper )
|
121
|
+
|
122
|
+
$template: (template, variables={})->
|
123
|
+
@$html( Luca.template(template,variables) )
|
124
|
+
|
125
|
+
$html: (content)->
|
126
|
+
@$bodyEl().html( content )
|
127
|
+
|
128
|
+
$append: (content)->
|
129
|
+
@$bodyEl().append(content)
|
130
|
+
|
131
|
+
# Luca containers can have toolbars,
|
132
|
+
# these will get injected before or after the bodyEl, or at the top
|
133
|
+
# or bottom of the $el
|
134
|
+
renderToolbars: ()->
|
135
|
+
_( ["top","left","right","bottom"] ).each (orientation)=>
|
136
|
+
if config = @["#{ orientation }Toolbar"]
|
137
|
+
@renderToolbar( orientation, config)
|
138
|
+
|
139
|
+
renderToolbar: (orientation="top", config={})->
|
140
|
+
config.parent = @
|
141
|
+
config.orientation = orientation
|
142
|
+
|
143
|
+
attachToolbar.call(@, config)
|
@@ -0,0 +1,104 @@
|
|
1
|
+
registry =
|
2
|
+
classes:{}
|
3
|
+
namespaces:['Luca.containers','Luca.components']
|
4
|
+
|
5
|
+
component_cache =
|
6
|
+
cid_index: {}
|
7
|
+
name_index: {}
|
8
|
+
|
9
|
+
# For container views, if a component is defined with no ctype
|
10
|
+
# then we will pick this one when using
|
11
|
+
Luca.defaultComponentType = 'view'
|
12
|
+
|
13
|
+
|
14
|
+
# When you use _.def to define a component, you say
|
15
|
+
# which class it extends() from, and with() which enhancements.
|
16
|
+
|
17
|
+
# We register that component class for you:
|
18
|
+
Luca.register = (component, prototypeName)->
|
19
|
+
Luca.trigger "component:registered", component, prototypeName
|
20
|
+
registry.classes[ component ] = prototypeName
|
21
|
+
|
22
|
+
Luca.development_mode_register = (component, prototypeName)->
|
23
|
+
existing = registry.classes[component]
|
24
|
+
|
25
|
+
if Luca.enableDevelopmentTools is true and existing?
|
26
|
+
prototypeDefinition = Luca.util.resolve( existing, window)
|
27
|
+
|
28
|
+
liveInstances = Luca.registry.findInstancesByClassName( prototypeName )
|
29
|
+
|
30
|
+
_( liveInstances ).each (instance)->
|
31
|
+
instance?.refreshCode?.call(instance, prototypeDefinition)
|
32
|
+
|
33
|
+
Luca.register( component, prototypeName )
|
34
|
+
|
35
|
+
# We create a @ctype alias for this component definition, and register
|
36
|
+
# the class in a registry.
|
37
|
+
|
38
|
+
# If you use a custom namespace like MyApp.views.ListView,
|
39
|
+
# then we will register MyApp.views as a namespace. You can
|
40
|
+
# do this yourself too.
|
41
|
+
Luca.registry.addNamespace = (identifier)->
|
42
|
+
registry.namespaces.push( identifier )
|
43
|
+
registry.namespaces = _( registry.namespaces ).uniq()
|
44
|
+
|
45
|
+
# This allows us to declare relationships between objects at definition time
|
46
|
+
# and have the instances of these objects be created at runtime when they
|
47
|
+
# are available.
|
48
|
+
#
|
49
|
+
# it also allows us to build tools to monitor what is going on inside of an
|
50
|
+
# application, which makes testing and debugging easier, and also serves as
|
51
|
+
# the basis of Luca's in browser development tools.
|
52
|
+
Luca.registry.namespaces = (resolve=true)->
|
53
|
+
_( registry.namespaces ).map (namespace)->
|
54
|
+
if resolve then Luca.util.resolve( namespace ) else namespace
|
55
|
+
|
56
|
+
# Lookup a component in the Luca component registry
|
57
|
+
# by it's ctype identifier. If it doesn't exist,
|
58
|
+
# check any other registered namespace
|
59
|
+
Luca.registry.lookup = (ctype)->
|
60
|
+
c = registry.classes[ctype]
|
61
|
+
|
62
|
+
return c if c?
|
63
|
+
|
64
|
+
className = Luca.util.classify(ctype)
|
65
|
+
|
66
|
+
parents = Luca.registry.namespaces()
|
67
|
+
|
68
|
+
fullPath = _( parents ).chain().map((parent)->
|
69
|
+
parent[className]).compact().value()?[0]
|
70
|
+
|
71
|
+
Luca.registry.findInstancesByClassName = (className)->
|
72
|
+
instances = _( component_cache.cid_index ).values()
|
73
|
+
_( instances ).select (instance)->
|
74
|
+
instance.displayName is className or instance._superClass?()?.displayName is className
|
75
|
+
|
76
|
+
Luca.registry.classes = (toString=false)->
|
77
|
+
_( registry.classes ).map (className, ctype)->
|
78
|
+
if toString
|
79
|
+
className
|
80
|
+
else
|
81
|
+
className: className
|
82
|
+
ctype: ctype
|
83
|
+
|
84
|
+
Luca.cache = (needle, component)->
|
85
|
+
component_cache.cid_index[ needle ] = component if component?
|
86
|
+
|
87
|
+
component = component_cache.cid_index[ needle ]
|
88
|
+
|
89
|
+
# optionally, cache it by tying its name to its cid for easier lookups
|
90
|
+
if component?.component_name?
|
91
|
+
Luca.trigger "component:created:#{ component.component_name }", component
|
92
|
+
component_cache.name_index[ component.component_name ] = component.cid
|
93
|
+
else if component?.name?
|
94
|
+
Luca.trigger "component:created:#{ component.component_name }", component
|
95
|
+
component_cache.name_index[ component.name ] = component.cid
|
96
|
+
|
97
|
+
return component if component?
|
98
|
+
|
99
|
+
# perform a lookup by name if the component_id didn't turn anything
|
100
|
+
lookup_id = component_cache.name_index[ needle ]
|
101
|
+
|
102
|
+
component_cache.cid_index[ lookup_id ]
|
103
|
+
|
104
|
+
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# Takes an string like "deep.nested.value" and an object like window
|
2
|
+
# and returns the value of window.deep.nested.value. useful for defining
|
3
|
+
# references on objects which don't yet exist, as strings, which get
|
4
|
+
# evaluated at runtime when such references will be available
|
5
|
+
Luca.util.resolve = (accessor, source_object)->
|
6
|
+
source_object ||= (window || global)
|
7
|
+
_( accessor.split(/\./) ).inject (obj,key)->
|
8
|
+
obj = obj?[key]
|
9
|
+
, source_object
|
10
|
+
|
11
|
+
# A better name for Luca.util.nestedValue
|
12
|
+
Luca.util.nestedValue = Luca.util.resolve
|
13
|
+
|
14
|
+
# turns a word like form_view into FormView
|
15
|
+
Luca.util.classify = (string="")->
|
16
|
+
_.string.camelize( _.string.capitalize( string ) )
|
17
|
+
|
18
|
+
# looks up a method on an object by its event trigger
|
19
|
+
# in the format of what:ever => whatEver
|
20
|
+
Luca.util.hook = (eventId="")->
|
21
|
+
parts = eventId.split(':')
|
22
|
+
prefix = parts.shift()
|
23
|
+
|
24
|
+
parts = _( parts ).map (p)-> _.string.capitalize(p)
|
25
|
+
fn = prefix + parts.join('')
|
26
|
+
|
27
|
+
Luca.util.isIE = ()->
|
28
|
+
try
|
29
|
+
Object.defineProperty({}, '', {})
|
30
|
+
return false
|
31
|
+
catch e
|
32
|
+
return true
|
33
|
+
|
34
|
+
currentNamespace = (window || global)
|
35
|
+
|
36
|
+
Luca.util.namespace = (namespace)->
|
37
|
+
return currentNamespace unless namespace?
|
38
|
+
currentNamespace = if _.isString(namespace) then Luca.util.resolve(namespace,(window||global)) else namespace
|
39
|
+
|
40
|
+
if currentNamespace?
|
41
|
+
return currentNamespace
|
42
|
+
|
43
|
+
currentNamespace = eval("(window||global).#{ namespace } = {}")
|
44
|
+
|
45
|
+
# one of the main benefits of Luca is the ability to structure your app as
|
46
|
+
# large blocks of JSON configuration. In order to convert an object into
|
47
|
+
# a Luca component, we lookup the object's class by converting its ctype / type
|
48
|
+
# property into a class that has been registered in the component registry
|
49
|
+
Luca.util.lazyComponent = (config)->
|
50
|
+
if _.isObject(config)
|
51
|
+
ctype = config.ctype || config.type
|
52
|
+
|
53
|
+
if _.isString(config)
|
54
|
+
ctype = config
|
55
|
+
|
56
|
+
componentClass = Luca.registry.lookup( ctype )
|
57
|
+
|
58
|
+
throw "Invalid Component Type: #{ ctype }. Did you forget to register it?" unless componentClass
|
59
|
+
|
60
|
+
constructor = eval( componentClass )
|
61
|
+
|
62
|
+
new constructor(config)
|
63
|
+
|
64
|
+
Luca.util.selectProperties = (iterator, object, context)->
|
65
|
+
values = _( object ).values()
|
66
|
+
_( values ).select( iterator )
|
67
|
+
|
68
|
+
Luca.util.loadScript = (url, callback) ->
|
69
|
+
script = document.createElement("script")
|
70
|
+
script.type = "text/javascript"
|
71
|
+
|
72
|
+
if (script.readyState)
|
73
|
+
script.onreadystatechange = ()->
|
74
|
+
if script.readyState == "loaded" || script.readyState == "complete"
|
75
|
+
script.onreadystatechange = null
|
76
|
+
callback()
|
77
|
+
else
|
78
|
+
script.onload = ()->
|
79
|
+
callback()
|
80
|
+
|
81
|
+
script.src = url
|
82
|
+
document.body.appendChild(script)
|