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.
Files changed (149) hide show
  1. data/.gitignore +3 -0
  2. data/.rvmrc +1 -0
  3. data/CHANGELOG +51 -2
  4. data/README.md +10 -247
  5. data/ROADMAP +6 -2
  6. data/app.rb +16 -2
  7. data/assets/javascripts/dependencies/bootstrap.min.js +7 -1
  8. data/assets/javascripts/dependencies/codemirror-coffeescript.js +347 -0
  9. data/assets/javascripts/dependencies/codemirror-css.js +124 -0
  10. data/assets/javascripts/dependencies/codemirror-html.js +410 -0
  11. data/assets/javascripts/dependencies/codemirror-javascript.js +361 -0
  12. data/assets/javascripts/dependencies/codemirror-less.js +232 -0
  13. data/assets/javascripts/dependencies/codemirror-vim.js +500 -0
  14. data/assets/javascripts/dependencies/codemirror.js +3076 -0
  15. data/assets/javascripts/dependencies.coffee +0 -1
  16. data/assets/javascripts/luca-ui-base.coffee +10 -3
  17. data/assets/javascripts/luca-ui-bootstrap.js +1 -0
  18. data/assets/javascripts/luca-ui-development-tools.coffee +9 -0
  19. data/assets/javascripts/luca-ui.coffee +6 -1
  20. data/assets/javascripts/sandbox/application.coffee +51 -0
  21. data/assets/javascripts/sandbox/router.coffee +14 -0
  22. data/assets/javascripts/sandbox/templates/main.luca +33 -0
  23. data/assets/javascripts/sandbox/templates/sandbox/navigation.luca +1 -0
  24. data/assets/javascripts/sandbox/templates/sandbox.luca +1 -0
  25. data/assets/javascripts/sandbox/views/top_navigation.coffee +4 -0
  26. data/assets/javascripts/sandbox.coffee +2 -2
  27. data/assets/stylesheets/bootstrap.min.css +395 -297
  28. data/assets/stylesheets/codemirror-blackboard.css +25 -0
  29. data/assets/stylesheets/codemirror-monokai.css +33 -0
  30. data/assets/stylesheets/codemirror.css +126 -0
  31. data/assets/stylesheets/luca-ui-bootstrap.css +0 -1
  32. data/assets/stylesheets/luca-ui-development-tools.css +5 -0
  33. data/assets/stylesheets/sandbox/sandbox.scss +1 -3
  34. data/assets/stylesheets/themes/amelia-bootstrap.css +826 -0
  35. data/assets/stylesheets/themes/slate-bootstrap.css +797 -0
  36. data/assets/stylesheets/themes/superhero-bootstrap.css +830 -0
  37. data/lib/luca/code_browser.rb +55 -0
  38. data/lib/luca/rails/version.rb +1 -1
  39. data/lib/luca/rails.rb +1 -0
  40. data/spec/components/fields/checkbox_array_spec.coffee +46 -0
  41. data/spec/components/form_view_spec.coffee +10 -4
  42. data/spec/containers/card_view_spec.coffee +7 -0
  43. data/spec/core/collection_spec.coffee +58 -4
  44. data/spec/core/container_spec.coffee +6 -6
  45. data/spec/core/view_spec.coffee +93 -7
  46. data/spec/framework_spec.coffee +15 -12
  47. data/src/components/application.coffee +126 -18
  48. data/src/components/base_toolbar.coffee +2 -2
  49. data/src/components/collection_loader_view.coffee +1 -2
  50. data/src/components/collection_view.coffee +77 -0
  51. data/src/components/controller.coffee +1 -4
  52. data/src/components/fields/button_field.coffee +1 -1
  53. data/src/components/fields/checkbox_array.coffee +2 -2
  54. data/src/components/fields/checkbox_field.coffee +3 -1
  55. data/src/components/fields/file_upload_field.coffee +1 -1
  56. data/src/components/fields/hidden_field.coffee +1 -1
  57. data/src/components/fields/select_field.coffee +1 -1
  58. data/src/components/fields/text_area_field.coffee +1 -1
  59. data/src/components/fields/text_field.coffee +10 -6
  60. data/src/components/fields/type_ahead_field.coffee +18 -5
  61. data/src/components/form_button_toolbar.coffee +1 -2
  62. data/src/components/form_view.coffee +44 -62
  63. data/src/components/grid_view.coffee +27 -20
  64. data/src/components/load_mask.coffee +3 -0
  65. data/src/components/nav_bar.coffee +26 -0
  66. data/src/components/record_manager.coffee +1 -3
  67. data/src/components/router.coffee +1 -1
  68. data/src/components/template.coffee +3 -15
  69. data/src/components/toolbar_dialog.coffee +25 -0
  70. data/src/containers/card_view.coffee +22 -23
  71. data/src/containers/column_view.coffee +1 -6
  72. data/src/containers/modal_view.coffee +20 -71
  73. data/src/containers/panel_toolbar.coffee +156 -0
  74. data/src/containers/panel_view.coffee +1 -1
  75. data/src/containers/split_view.coffee +1 -3
  76. data/src/containers/tab_view.coffee +29 -29
  77. data/src/containers/viewport.coffee +38 -3
  78. data/src/core/collection.coffee +80 -48
  79. data/src/core/container.coffee +153 -72
  80. data/src/core/core.coffee +181 -0
  81. data/src/core/field.coffee +4 -2
  82. data/src/core/model.coffee +1 -1
  83. data/src/core/observer.coffee +3 -3
  84. data/src/core/panel.coffee +143 -0
  85. data/src/core/registry.coffee +104 -0
  86. data/src/core/util.coffee +82 -0
  87. data/src/core/view.coffee +158 -85
  88. data/src/framework.coffee +112 -178
  89. data/src/index.coffee +0 -255
  90. data/src/managers/collection_manager.coffee +1 -0
  91. data/src/samples/definition.coffee +49 -0
  92. data/src/stylesheets/base.scss +0 -78
  93. data/src/stylesheets/components/form_view.scss +8 -3
  94. data/src/stylesheets/components/grid_view.scss +3 -7
  95. data/src/stylesheets/components/load_mask.scss +14 -0
  96. data/src/stylesheets/components/toolbar.scss +0 -15
  97. data/src/stylesheets/containers/container.scss +14 -2
  98. data/src/stylesheets/containers/panels.scss +23 -0
  99. data/src/stylesheets/tools/class_browser.scss +32 -0
  100. data/src/stylesheets/tools/code_editor.scss +24 -0
  101. data/src/stylesheets/tools/component_tester.scss +8 -0
  102. data/src/stylesheets/tools/console.scss +26 -0
  103. data/src/templates/components/collection_loader_view.luca +1 -1
  104. data/src/templates/components/form_view.luca +2 -13
  105. data/src/templates/components/grid_view.luca +0 -2
  106. data/src/templates/components/load_mask.luca +3 -0
  107. data/src/templates/components/nav_bar.luca +2 -0
  108. data/src/templates/containers/tab_view.luca +1 -0
  109. data/src/templates/fields/text_field.luca +4 -1
  110. data/src/tools/class_browser.coffee +39 -0
  111. data/src/tools/code_editor.coffee +258 -0
  112. data/src/tools/code_mirror_field.coffee +57 -0
  113. data/src/tools/coffee_script_editor.coffee +60 -0
  114. data/src/tools/collection_inspector.coffee +4 -0
  115. data/src/tools/component_tester.coffee +472 -0
  116. data/src/tools/components/class_browser_detail.coffee +10 -0
  117. data/src/tools/components/class_browser_list.coffee +74 -0
  118. data/src/tools/console.coffee +147 -0
  119. data/src/tools/development_console.coffee +147 -0
  120. data/src/tools/models/components.coffee +63 -0
  121. data/src/tools/templates/component_tester/help.luca +14 -0
  122. data/vendor/assets/javascripts/luca-ui-base.js +1389 -611
  123. data/vendor/assets/javascripts/luca-ui-bootstrap.js +9 -0
  124. data/vendor/assets/javascripts/luca-ui-development-tools.js +18719 -0
  125. data/vendor/assets/javascripts/luca-ui-spec.js +2065 -878
  126. data/vendor/assets/javascripts/luca-ui.js +1759 -852
  127. data/vendor/assets/javascripts/luca-ui.min.js +3 -3
  128. data/vendor/assets/stylesheets/luca-ui-bootstrap.css +494 -440
  129. data/vendor/assets/stylesheets/luca-ui-development-tools.css +224 -0
  130. data/vendor/assets/stylesheets/luca-ui-spec.css +99 -140
  131. data/vendor/assets/stylesheets/luca-ui.css +99 -140
  132. data/views/index.erb +6 -3
  133. metadata +60 -18
  134. data/assets/javascripts/dependencies/jquery-console.js +0 -649
  135. data/assets/javascripts/development-console.coffee +0 -2
  136. data/assets/javascripts/sandbox/sandbox.coffee +0 -16
  137. data/assets/javascripts/sandbox/templates/features/collection_helpers.luca +0 -33
  138. data/assets/javascripts/sandbox/templates/features/form_demo_code.luca +0 -48
  139. data/assets/javascripts/sandbox/templates/features/grid_demo_code.luca +0 -24
  140. data/assets/javascripts/sandbox/templates/features/introduction.luca +0 -11
  141. data/assets/javascripts/sandbox/templates/features/view_helpers.luca +0 -43
  142. data/assets/javascripts/sandbox/templates/navigation.luca +0 -8
  143. data/assets/javascripts/sandbox/views/form_demo.coffee +0 -47
  144. data/assets/javascripts/sandbox/views/grid_demo.coffee +0 -23
  145. data/assets/javascripts/sandbox/views/pages/collection_events_sample.coffee +0 -1
  146. data/assets/javascripts/sandbox/views/pages/pages_controller.coffee +0 -38
  147. data/src/components/collection_inspector.coffee +0 -2
  148. data/src/components/development_console.coffee +0 -59
  149. 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
+
@@ -1,4 +1,4 @@
1
- _.component('Luca.core.Field').extends('Luca.View').with
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')
@@ -4,7 +4,7 @@
4
4
  # few useful patterns:
5
5
  #
6
6
  # - computed properties support
7
- _.component('Luca.Model').extends('Backbone.Model').with
7
+ _.def('Luca.Model').extends('Backbone.Model').with
8
8
  initialize: ()->
9
9
  Backbone.Model::initialize @, arguments
10
10
 
@@ -4,10 +4,10 @@ class Luca.Observer
4
4
  @type = @options.type
5
5
 
6
6
  if @options.debugAll
7
- @bind "event", (t, args...)=>
8
- console.log "Observed #{ @type } #{ (t.name || t.id || t.cid) }", t, _(args).flatten()
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)