luca 0.8.599 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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,39 @@
1
+ # The Class Browser takes a map of your application's source code and the
2
+ # classes it defines and allows you to view and even edit the source code
3
+ # for a given class in the browser.
4
+
5
+ # We do this by combining the functionality of a Luca CollectionList View
6
+ # which inspects the Luca component registry, and a CodeMirror Editor instance
7
+ # which compiles coffeescript and evaluates it on the fly. The Luca Framework
8
+ # is capable of updating all of the application components with the changes
9
+ # you make to their code.
10
+ _.def("Luca.tools.ClassBrowser").extends("Luca.containers.SplitView").with
11
+
12
+ name: "class_browser"
13
+
14
+ className: "luca-class-browser row"
15
+
16
+ layout:["span3","span9"]
17
+ # Composite views can be made up by specifying a list of components
18
+ # either as a collection of object configurations, or as a list
19
+ # of names corresponding to component types. The various types of
20
+ # Luca containers will handle rendering these components and arranging
21
+ # them visually
22
+ components:["class_browser_list","class_browser_detail"]
23
+
24
+ # The container is responsible for handling communication between components.
25
+ # We provide a nice API for this via the @componentEvents property.
26
+ componentEvents:
27
+ "class_browser_list component:loaded" : "loadSourceCode"
28
+
29
+ bottomToolbar:
30
+ buttons:[
31
+ label: "Add New"
32
+ icon: "plus"
33
+ color: "primary"
34
+ white: true
35
+ align: 'right'
36
+ ]
37
+
38
+ loadSourceCode: (model, response)->
39
+ Luca("class_browser_detail").loadComponent( model )
@@ -0,0 +1,258 @@
1
+ BuffersModel = Luca.Model.extend
2
+ defaults:
3
+ _current: "default"
4
+ _namespace: "default"
5
+ _compiled: []
6
+
7
+ initialize: (@attributes={})->
8
+ Luca.Model::initialize.apply(@, arguments)
9
+ @fetch(silent:true)
10
+
11
+ requireCompilation: ()->
12
+ @get("_compiled")
13
+
14
+ bufferKeys: ()->
15
+ return @bufferNames if @bufferNames?
16
+
17
+ for key, value of @attributes when !key.match(/_/)
18
+ key
19
+
20
+ namespacedBuffer: (key)->
21
+ "#{ @get('_namespace') }:#{ key }"
22
+
23
+ bufferValues: ()->
24
+ _( @attributes ).pick( @bufferKeys() )
25
+
26
+ fetch: (options={})->
27
+ options.silent ||= true
28
+
29
+ _( @bufferKeys() ).each (key)=>
30
+ value = localStorage?.getItem( @namespacedBuffer(key) )
31
+ @set(key, value, silent: options.silent is true) if value?
32
+
33
+ @
34
+
35
+ persist: ()->
36
+ _( @bufferKeys() ).each (key)=>
37
+ value = @get(key)
38
+ localStorage?.setItem( @namespacedBuffer(key), value)
39
+
40
+ @
41
+
42
+ currentContent: ()->
43
+ current = @get("_current")
44
+ @get(current)
45
+
46
+ compilers =
47
+ coffeescript: (code)->
48
+ CoffeeScript.compile code, bare: true
49
+ default: (code)->
50
+ code
51
+
52
+ _.def("Luca.tools.CodeEditor").extends("Luca.components.Panel").with
53
+ name: "code_editor"
54
+
55
+ id: "editor_container"
56
+
57
+ autoBindEventHandlers: true
58
+
59
+ bodyClassName: "codemirror-wrapper"
60
+
61
+ defaultValue: ''
62
+
63
+ compilationEnabled: false
64
+
65
+ bufferNamespace: "luca:code"
66
+
67
+ namespace: (set, options={})->
68
+ if set?
69
+ @bufferNamespace = set
70
+ @buffers?.set("_namespace", set, silent: (options.silent is true) )
71
+
72
+ @bufferNamespace
73
+
74
+ initialize: (@options)->
75
+ @_super("initialize", @, arguments)
76
+
77
+ _.bindAll @, "onCompiledCodeChange", "onBufferChange", "onEditorChange", "stripTabs"
78
+
79
+ @mode ||= "coffeescript"
80
+ @theme ||= "monokai"
81
+ @keyMap ||= "vim"
82
+ @lineWrapping ||= true
83
+
84
+ @compiler = compilers[@mode] || compilers.default
85
+
86
+ @setupBuffers()
87
+
88
+ setWrap: (@lineWrapping)->
89
+ @editor.setOption("lineWrapping", @lineWrapping)
90
+
91
+ setMode: (@mode)->
92
+ @editor.setOption("mode", @mode)
93
+ @
94
+
95
+ setKeyMap: (@keyMap)->
96
+ @editor.setOption("keyMap", @keyMap)
97
+ @
98
+
99
+ setTheme: (@theme)->
100
+ @editor.setOption("theme",@theme)
101
+ @
102
+
103
+ setupBuffers: ()->
104
+ attributes = _.extend(@currentBuffers || {},_compiled:@compiledBuffers,_namespace:@namespace())
105
+ @buffers = new BuffersModel(attributes)
106
+
107
+ editor = @
108
+
109
+ _( @buffers.bufferKeys() ).each (key)=>
110
+ @buffers.bind "change:#{ key }", ()=>
111
+ @onBufferChange.apply(@, arguments)
112
+
113
+ _( @buffers.requireCompilation() ).each (key)=>
114
+ @buffers.bind "change:compiled_#{ key }", @onCompiledCodeChange
115
+
116
+ # handle switching of the buffers. when the editor
117
+ # is told to switch buffers, we will get the current content
118
+ # in that buffer, and update the code mirror instance
119
+ @buffers.bind "change:_current", (model,value)=>
120
+ editor.trigger "buffer:change"
121
+ editor.editor.setValue( @buffers.currentContent() || "" )
122
+
123
+ @monitorChanges = true
124
+
125
+ currentBuffer: ()->
126
+ @buffers.get("_current")
127
+
128
+ loadBuffer: (bufferName, autoSave=true)->
129
+ @saveBuffer() if autoSave
130
+ @buffers.set("_current", bufferName)
131
+
132
+ saveBuffer: ()->
133
+ localStorage.setItem( @buffers.namespacedBuffer( @currentBuffer() ), @editor.getValue())
134
+ @buffers.set( @currentBuffer(), @editor.getValue() )
135
+
136
+ getBuffer: (buffer, compiled=false)->
137
+ buffer ||= @currentBuffer()
138
+ code = @buffers.get( buffer )
139
+
140
+ return code unless compiled is true
141
+
142
+ compiledCode = @buffers.get("compiled_#{ buffer }")
143
+
144
+ if _.string.isBlank(compiledCode)
145
+ compiledCode = @compileCode(code, buffer)
146
+
147
+ return compiledCode
148
+
149
+ editorOptions: ()->
150
+ mode: @mode
151
+ theme: @theme
152
+ keyMap: @keyMap
153
+ lineNumbers: true
154
+ gutter: true
155
+ autofocus: true
156
+ onChange: @onEditorChange
157
+ onKeyEvent: @stripTabs
158
+ passDelay: 50
159
+ autoClearEmptyLines: true
160
+ smartIndent: false
161
+ tabSize: 2
162
+ electricChars: false
163
+
164
+
165
+ beforeRender: ()->
166
+ Luca.components.Panel::beforeRender?.apply(@, arguments)
167
+
168
+ styles =
169
+ "min-height": @minHeight
170
+ background:'#272822'
171
+ color:'#f8f8f2'
172
+
173
+ @$bodyEl().css(styles)
174
+
175
+ @$html "<textarea></textarea>"
176
+
177
+ afterRender: ()->
178
+ _.defer ()=>
179
+ @editor = window.CodeMirror.fromTextArea( @$('textarea')[0], @editorOptions())
180
+ @restore()
181
+ @enableTabStripping = true
182
+
183
+ save: ()->
184
+ @saveBuffer()
185
+
186
+ restore: ()->
187
+ @editor.setValue("")
188
+ @editor.refresh()
189
+
190
+ replaceTabWithSpace: ()->
191
+
192
+ stripTabs: (editor, keyEvent)->
193
+ if keyEvent?.keyCode is 9
194
+ coords = @editor.cursorCoords()
195
+ cleansed = @getValue().replace(/\t/g,' ')
196
+ @setValue(cleansed)
197
+ @editor.setCursor( coords )
198
+
199
+ false
200
+
201
+ onEditorChange: ()->
202
+ if @monitorChanges
203
+ @save()
204
+
205
+ onBufferChange: (model, newValue, changes)->
206
+ previous = model.previousAttributes()
207
+
208
+ _( @buffers.bufferKeys() ).each (key)=>
209
+ if previous[key] isnt @buffers.get(key)
210
+
211
+ if _( @buffers.requireCompilation() ).include(key)
212
+ result = @compileCode( @buffers.get(key), key )
213
+ if result.success is true
214
+ @buffers.persist(key)
215
+ @buffers.set("compiled_#{ key }", result.compiled, silent: true)
216
+ else
217
+ @trigger "code:change:#{ key }", @buffers.get(key)
218
+ @buffers.persist(key)
219
+
220
+ @buffers.change()
221
+
222
+ onCompiledCodeChange: (model, newValue, changes)->
223
+ changedBuffers = _( model.changedAttributes() ).keys()
224
+ @trigger "code:change", changedBuffers
225
+ for changed in changedBuffers
226
+ @trigger "code:change:#{ changed }", changed
227
+
228
+ compileCode: (code, buffer)->
229
+ buffer ||= @currentBuffer()
230
+ code ||= @getBuffer(buffer, false)
231
+
232
+ compiled = ""
233
+
234
+ result =
235
+ success: true
236
+ compiled: ""
237
+
238
+ try
239
+ compiled = @compiler.call(@, code)
240
+ @trigger "compile:success", code, compiled
241
+ result.compiled = compiled
242
+ catch error
243
+ @trigger "compile:error", error, code
244
+ result.success = false
245
+ result.compiled = @buffers.get("compiled_#{ buffer }")
246
+
247
+ result
248
+
249
+ getCompiledCode: (buffer)->
250
+ buffer = @getBuffer(buffer)
251
+ _.string.strip( @compileCode(buffer) )
252
+
253
+ getValue: ()->
254
+ @editor.getValue()
255
+
256
+ setValue: (value)->
257
+ value = value.replace(/\t/g, ' ')
258
+ @editor.setValue( value )
@@ -0,0 +1,57 @@
1
+ defaultOptions =
2
+ readOnly: false
3
+ lineNumbers: true
4
+ gutter: true
5
+ autofocus: false
6
+ passDelay: 50
7
+ autoClearEmptyLines: true
8
+ smartIndent: false
9
+ tabSize: 2
10
+ electricChars: false
11
+
12
+ Luca.define("Luca.tools.CodeMirrorField").extends("Luca.components.Panel").with
13
+ bodyClassName: "codemirror-wrapper"
14
+ preProcessors: []
15
+ postProcessors: []
16
+
17
+ codemirrorOptions: ()->
18
+ options = _.clone( defaultOptions )
19
+
20
+ customOptions =
21
+ mode: @mode || "coffeescript"
22
+ theme: @theme || "monokai"
23
+ keyMap: @keyMap || "basic"
24
+ lineNumbers: if @lineNumbers? then @lineNumbers else defaultOptions.lineNumbers
25
+ readOnly: if @readOnly? then @readOnly else defaultOptions.readOnly
26
+ gutter: if @gutter? then @gutter else defaultOptions.gutter
27
+ lineWrapping: @lineWrapping is true
28
+ onChange: ()=>
29
+ @trigger "editor:change", @
30
+ @onEditorChange?.call(@)
31
+
32
+ customOptions.onKeyEvent = _.bind(@onKeyEvent,@) if @onKeyEvent?
33
+
34
+ _.extend(options, customOptions)
35
+
36
+ getCodeMirror: ()->
37
+ @instance
38
+
39
+ getValue: (processed=true)->
40
+ value = @getCodeMirror().getValue()
41
+
42
+ setValue: (value="", processed=true)->
43
+ @getCodeMirror().setValue( value )
44
+
45
+ afterRender: ()->
46
+ @instance = CodeMirror( @$bodyEl()[0], @codemirrorOptions() )
47
+ @setMaxHeight()
48
+ @setHeight()
49
+
50
+ setMaxHeight: (maxHeight=undefined, grow=true)->
51
+ maxHeight ||= @maxHeight
52
+ return unless maxHeight?
53
+ @$('.CodeMirror-scroll').css('max-height', maxHeight)
54
+ @$('.CodeMirror-scroll').css('height', maxHeight) if grow is true
55
+
56
+ setHeight: (height=undefined)->
57
+ @$('.CodeMirror-scroll').css('height', height) if height?
@@ -0,0 +1,60 @@
1
+ _.def("Luca.tools.CoffeeEditor").extends("Luca.tools.CodeMirrorField").with
2
+ name : "coffeescript_editor"
3
+
4
+ compileOptions:
5
+ bare: true
6
+
7
+ hooks:[
8
+ "editor:change"
9
+ ]
10
+
11
+ initialize: (@options)->
12
+ Luca.tools.CodeMirrorField::initialize.apply(@, arguments)
13
+
14
+ _.bindAll(@, "editorChange")
15
+
16
+ editor = @
17
+
18
+ @state = new Luca.Model
19
+ currentMode: "coffeescript"
20
+ coffeescript:""
21
+ javascript:""
22
+
23
+ @state.bind "change:coffeescript", (model)->
24
+ editor.trigger("change:coffeescript")
25
+ code = model.get("coffeescript")
26
+
27
+ editor.compile code, (compiled)->
28
+ model.set('javascript',compiled)
29
+
30
+ @state.bind "change:javascript", (model)->
31
+ editor.onJavascriptChange?.call(editor, model.get('javascript') )
32
+
33
+ compile: (code, callback)->
34
+ response = {}
35
+ code ||= @getValue()
36
+
37
+ try
38
+ compiled = CoffeeScript.compile(code, @compileOptions)
39
+ callback?.call(@, compiled)
40
+ response =
41
+ success: true
42
+ compiled: compiled
43
+ catch error
44
+ @trigger("compile:error", error, code)
45
+
46
+ response =
47
+ success: false
48
+ compiled: ''
49
+ message: error.message
50
+
51
+ currentMode: ()->
52
+ @state.get("currentMode")
53
+
54
+ fixTabs: ()->
55
+ value = @getValue(false)
56
+ debugger
57
+
58
+ editorChange: ()->
59
+ @fixTabs()
60
+ @state.set( @currentMode(), @getValue() )
@@ -0,0 +1,4 @@
1
+ _.def("Luca.tools.CollectionInspector").extends("Luca.View").with
2
+ name: "collection_inspector"
3
+
4
+ className: "collection-inspector"