luca 0.9.2 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. data/.gitignore +1 -0
  2. data/.rvmrc +1 -1
  3. data/CHANGELOG +46 -2
  4. data/Gemfile +1 -1
  5. data/Gemfile.lock +2 -2
  6. data/Guardfile +1 -1
  7. data/README.md +64 -27
  8. data/ROADMAP +17 -2
  9. data/Rakefile +49 -1
  10. data/app.rb +38 -2
  11. data/assets/javascripts/luca-ui-base.coffee +1 -20
  12. data/assets/javascripts/luca-ui-full.js +3 -0
  13. data/assets/javascripts/luca-ui.coffee +0 -5
  14. data/assets/javascripts/sandbox/application.coffee +24 -18
  15. data/assets/javascripts/sandbox/router.coffee +16 -6
  16. data/assets/javascripts/sandbox/templates/builder/component_list.luca +1 -0
  17. data/assets/javascripts/sandbox/templates/builder.luca +2 -0
  18. data/assets/javascripts/sandbox/templates/main.luca +4 -3
  19. data/assets/javascripts/sandbox/templates/sandbox/docs_index.luca +1 -0
  20. data/assets/javascripts/sandbox/templates/sandbox/navigation.luca +6 -1
  21. data/assets/javascripts/sandbox/templates/sandbox/readme.luca +30 -0
  22. data/assets/javascripts/sandbox/views/builder/builder_canvas.coffee +3 -0
  23. data/assets/javascripts/sandbox/views/builder/builder_editor.coffee +6 -0
  24. data/assets/javascripts/sandbox/views/builder/component_list.coffee +38 -0
  25. data/assets/javascripts/sandbox/views/builder/project_browser.coffee +14 -0
  26. data/assets/javascripts/sandbox/views/builder.coffee +133 -0
  27. data/assets/javascripts/sandbox/views/docs_controller.coffee +7 -0
  28. data/assets/javascripts/sandbox/views/inspector/instance_filter.coffee +18 -0
  29. data/assets/javascripts/sandbox/{collections/sample.coffee → views/inspector/instance_list.coffee} +0 -0
  30. data/assets/javascripts/sandbox/views/inspector.coffee +11 -0
  31. data/assets/javascripts/sandbox.coffee +2 -0
  32. data/assets/stylesheets/luca-ui-full.css +3 -0
  33. data/assets/stylesheets/sandbox/builder.scss +79 -0
  34. data/assets/stylesheets/sandbox/sandbox.scss +2 -1
  35. data/docs/application.md +41 -0
  36. data/docs/collection.md +79 -0
  37. data/docs/collection_manager.md +76 -0
  38. data/docs/container_philosophy.md +122 -0
  39. data/docs/event_binding_helpers.md +164 -0
  40. data/docs/method_caching_and_computed_properties.md +77 -0
  41. data/docs/view.md +119 -0
  42. data/lib/luca/rails/version.rb +1 -1
  43. data/lib/luca/template.rb +9 -9
  44. data/site/assets/bootstrap.min.js +7 -0
  45. data/site/assets/luca-ui-bootstrap.css +19 -1
  46. data/site/assets/luca-ui-development-tools.css +10 -0
  47. data/site/assets/luca-ui-development-tools.min.js +15 -0
  48. data/site/assets/luca-ui-full.min.js +8 -0
  49. data/site/assets/luca-ui.min.js +4 -0
  50. data/site/assets/sandbox.css +52 -4
  51. data/site/assets/sandbox.js +368 -30
  52. data/site/docs/application.html +41 -0
  53. data/site/docs/caching.html +43 -0
  54. data/site/docs/collection.html +75 -0
  55. data/site/docs/collection_manager.html +71 -0
  56. data/site/docs/containers.html +118 -0
  57. data/site/docs/events.html +153 -0
  58. data/site/docs/view.html +128 -0
  59. data/site/img/glyphicons-halflings-white.png +0 -0
  60. data/site/img/glyphicons-halflings.png +0 -0
  61. data/site/source-map.js +1 -0
  62. data/spec/core/view_spec.coffee +5 -17
  63. data/spec/managers/collection_manager_spec.coffee +4 -7
  64. data/src/components/application.coffee +202 -77
  65. data/src/components/base_toolbar.coffee +1 -1
  66. data/src/components/collection_view.coffee +38 -10
  67. data/src/components/controller.coffee +24 -1
  68. data/src/components/fields/checkbox_field.coffee +9 -12
  69. data/src/components/fields/label_field.coffee +14 -0
  70. data/src/components/fields/select_field.coffee +2 -2
  71. data/src/components/fields/text_field.coffee +12 -7
  72. data/src/components/fields/type_ahead_field.coffee +1 -0
  73. data/src/components/form_view.coffee +44 -25
  74. data/src/components/page_controller.coffee +2 -0
  75. data/src/containers/card_view.coffee +4 -1
  76. data/src/containers/column_view.coffee +2 -1
  77. data/src/containers/modal_view.coffee +6 -2
  78. data/src/containers/page_view.coffee +2 -0
  79. data/src/containers/panel_toolbar.coffee +0 -5
  80. data/src/containers/viewport.coffee +28 -10
  81. data/src/core/collection.coffee +7 -1
  82. data/src/core/container.coffee +57 -30
  83. data/src/core/core.coffee +0 -186
  84. data/src/core/field.coffee +11 -3
  85. data/src/core/model.coffee +31 -16
  86. data/src/core/panel.coffee +6 -46
  87. data/src/core/registry.coffee +19 -2
  88. data/src/core/script_loader.coffee +32 -0
  89. data/src/core/view.coffee +112 -139
  90. data/src/define.coffee +110 -0
  91. data/src/framework.coffee +8 -2
  92. data/src/luca.coffee +22 -0
  93. data/src/managers/collection_manager.coffee +65 -31
  94. data/src/modules/load_mask.coffee +47 -0
  95. data/src/plugins/development_tool_helpers.coffee +21 -0
  96. data/src/plugins/events.coffee +54 -0
  97. data/src/stylesheets/components/viewport.scss +15 -0
  98. data/src/stylesheets/containers/container.scss +1 -4
  99. data/src/stylesheets/tools/component_tester.scss +18 -0
  100. data/src/templates/fields/select_field.luca +6 -5
  101. data/src/templates/fields/text_field.luca +10 -9
  102. data/src/tools/application_inspector.coffee +2 -0
  103. data/src/tools/coffee_script_editor.coffee +28 -6
  104. data/src/tools/collections/components.coffee +59 -0
  105. data/src/tools/collections/instances.coffee +15 -0
  106. data/src/tools/component_tester.coffee +12 -22
  107. data/src/tools/console.coffee +22 -4
  108. data/src/tools/models/components.coffee +16 -54
  109. data/src/tools/models/instance.coffee +2 -0
  110. data/src/{core/util.coffee → util.coffee} +10 -1
  111. data/vendor/assets/javascripts/luca-ui-base.js +132 -137
  112. data/vendor/assets/javascripts/luca-ui-development-tools.js +191 -219
  113. data/vendor/assets/javascripts/luca-ui-development-tools.min.js +2 -2
  114. data/vendor/assets/javascripts/luca-ui-full.js +4680 -0
  115. data/vendor/assets/javascripts/luca-ui-full.min.js +8 -0
  116. data/vendor/assets/javascripts/luca-ui-spec.js +291 -225
  117. data/vendor/assets/javascripts/luca-ui.js +1001 -724
  118. data/vendor/assets/javascripts/luca-ui.min.js +4 -4
  119. data/vendor/assets/stylesheets/luca-ui-bootstrap.css +19 -1
  120. data/vendor/assets/stylesheets/luca-ui-development-tools.css +10 -0
  121. data/vendor/assets/stylesheets/luca-ui-full.css +1334 -0
  122. data/vendor/assets/stylesheets/luca-ui-spec.css +19 -1
  123. data/vendor/assets/stylesheets/luca-ui.css +19 -1
  124. data/views/index.erb +2 -5
  125. metadata +58 -9
  126. data/lib/sprockets/luca_template.rb +0 -49
  127. data/src/tools/class_browser.coffee +0 -39
  128. data/src/tools/components/class_browser_detail.coffee +0 -10
  129. data/src/tools/components/class_browser_list.coffee +0 -74
@@ -0,0 +1,164 @@
1
+ ## Event Binding Syntactic Sugar
2
+
3
+ `Luca.Events` provides you with some additional event binding sugar.
4
+
5
+ **once**
6
+
7
+ `once` is how you would run one function in response to an event, but only once.
8
+
9
+ ```coffeescript
10
+ view = new Luca.View()
11
+
12
+ view.once "event:gets:triggered", ()->
13
+ alert('sup baby')
14
+
15
+ view.trigger("event:gets:triggered")
16
+ ```
17
+
18
+ **defer until**
19
+
20
+ `defer` is similar to `once`, but with syntax I like a little better:
21
+
22
+ ```coffeescript
23
+ _.def("MyView").extends("Luca.View").with
24
+ initialize: ()->
25
+ @defer(@setup).until("event:gets:triggered")
26
+ ```
27
+
28
+ If you want to defer a callback until an event gets triggered on some other object:
29
+
30
+ ```coffeescript
31
+
32
+ _.def("MyView").extends("Luca.View").with
33
+
34
+ initialize:()->
35
+ @defer(@setup).until(@someObject,"triggers:an:event")
36
+
37
+ setup: ()->
38
+
39
+ ```
40
+
41
+ ## Component Bindings
42
+
43
+ Luca provides a number of configuration API for its components
44
+ which facilitate the binding of a component's methods to events that
45
+ occur on instances of the CollectionManager and Application objects.
46
+
47
+ For Luca.core.Container classes there is also a component events
48
+ binding API that allows you to declare in your container which events
49
+ to listen for on that container's components
50
+
51
+ ## Auto Context Binding For Event Handlers
52
+
53
+ By setting the @bindAllEvents property to true on your prototype definitions,
54
+ all event handler methods on your view will automatically be bound to the context
55
+ of the view.
56
+
57
+ ```coffeescript
58
+ _.def('MyApp.views.AutoBoundView').extends('Luca.View').with
59
+
60
+ bindAllEvents: true
61
+
62
+ events:
63
+ "click a.btn" : "clickHandler"
64
+ "click a.btn.btn-danger" : "dangerHandler"
65
+
66
+ initialize:()->
67
+ # You no longer need to do this
68
+ # if you want to have these handlers run
69
+ # in the context of this view
70
+ _.bindAll @, "clickHandler", "dangerHandler"
71
+
72
+ ```
73
+
74
+ ## Collection Manager Event Binding
75
+
76
+ Luca Applications which use the Luca.CollectionManager have the benefit of
77
+ a declarative event binding syntax which allows you bind to events on collections
78
+ by their name. This saves you from having to create a reference to the collection
79
+ in some method, and setup a callback binding. By simply providing a @collectionEvents
80
+ configuration property on your views, you can eliminate a lot of boilerplate in your components.
81
+
82
+ The format of the @collectionEvents hash is a key which is made up of the collection's name and the event
83
+ separated by a space, and either a function or a name of a method on your view.
84
+
85
+ ```coffeescript
86
+ SamplesCollection = Backbone.Collection.extend
87
+ name: "samples"
88
+ url: "/api/v1/samples"
89
+
90
+ _.def("MyView").extends("Luca.View").with
91
+ # NOTE: you may omit this property and
92
+ # it will use Luca.CollectionManager.get() to
93
+ # get the main instance.
94
+ collectionManager: "main"
95
+
96
+ collectionEvents:
97
+ "samples reset" : "samplesResetHandler"
98
+
99
+ samplesResetHandler: (collection)->
100
+ if collection.length > 1
101
+ @doSomething()
102
+ ```
103
+ ## Application Event Binding
104
+
105
+ Similar to the CollectionManager event binding API, there is a similar API for binding to the global application
106
+ object. Most applications will have a single application instance, that is either available on the global object
107
+ or through a call to `Luca.getApplication()`.
108
+
109
+ It is in the Application instance that global state tracking should occur. Should your views want to respond to changes
110
+ in global application state, you can provide an @applicationEvents configuration property. The format is a key value
111
+ pair, where the key represents the event being triggered by the application, and the value is a name of a method on
112
+ your view or an anonymous function.
113
+
114
+ ```coffeescript
115
+ App = new Luca.Application
116
+ name: "main"
117
+
118
+ defaultState:
119
+ currentMode: "solid"
120
+
121
+ _.def("AppBoundView").extends("Luca.View").with
122
+ # NOTE: you may omit this and it will use Luca.getApplication()
123
+ app: "main"
124
+
125
+ applicationEvents:
126
+ "change:currentMode" : "modeChangeHandler"
127
+
128
+ modeChangeHandler: ()->
129
+ @doSomething()
130
+ ```
131
+
132
+ ## Luca.core.Container Component Events
133
+
134
+ Containers are special views whose only purpose is to render multiple components in a specified configuration, and handle
135
+ all of the communication between the components. This is what allows Luca components to be extremely re-usable, because they
136
+ never know about views that exist outside of them.
137
+
138
+ By providing a @componentEvents configuration property on your container, you can bind to events on the components in your container
139
+ and relay information about them to other members of the container. The format is a key value pair where the key is a string which
140
+ contains the name of the component and the event it triggers, separated by a space. The value is a name of a method on your view or an anonymous function.
141
+
142
+ ```coffeescript
143
+ # ctype = component_one
144
+ _.def("ComponentOne").extends("Luca.View").with
145
+ name:"one"
146
+ eventHandler: ()->
147
+ @trigger "custom:event"
148
+
149
+ # ctype = component_two
150
+ _.def("ComponentTwo").extends("ComponentOne").with
151
+ name:"two"
152
+ eventHandler: ()->
153
+ @trigger "some:other:event"
154
+
155
+ _.def("MyContainer").extends("Luca.core.Container").with
156
+ components:["component_two","component_one"]
157
+ componentEvents:
158
+ "one custom:event" : "customEventHandler"
159
+
160
+ # when component named one fires an event
161
+ # we can handle it here, pass it to two, whatever
162
+ customEventHandler: ()->
163
+ Luca('two').eventHandler()
164
+ ```
@@ -0,0 +1,77 @@
1
+ # Method Caching and Computed Properties on Luca Collection and Model
2
+
3
+ The concept of computed properties ( on the model ) or cached methods ( on the collection )
4
+ optimizes for cases where you call a method that performs calculations or some other operations
5
+ whose value is dependent on the model and its underlying attributes.
6
+
7
+ ## Cached Methods on Luca.Collection
8
+
9
+ Luca provides a configuration API for Luca.Collection where you specify the method whose value
10
+ you wish to cache, and the change events which get bubbled up from the models that would change
11
+ the value, in essence expiring the cache. In addition to change events, standard events on the
12
+ collection for when a model is added or removed will expire the cached value.
13
+
14
+ ```coffeescript
15
+ _.def("MyCollection").extends("Luca.Collection").with
16
+ name:"my_collection"
17
+
18
+ cachedMethods:[
19
+ "expensiveMethod:attributeOne,attributeTwo",
20
+ "anotherExpensiveMethod"
21
+ ]
22
+
23
+ expensiveMethod: ()->
24
+ @map (model)-> model.get('attributeOne') + model.getAttribute('two')
25
+
26
+ anotherExpensiveMethod: ()->
27
+ @map (model)-> model.value()
28
+ ```
29
+
30
+ In the example above, the `expensiveMethod` is dependent on the `attributeOne` and `attributeTwo` attributes
31
+ on each of the models in the collection, therefor if any of these values change, the cache needs to be expired and new value recalculated.
32
+
33
+ The `anotherExpensiveMethod` call is not dependent on any specific values, so will only expire any time a new model
34
+ is added or removed, or the collection is reset.
35
+
36
+
37
+ Example:
38
+
39
+ ```coffeescript
40
+ _.def("Users").extends("Luca.Collection").with
41
+ name: 'users'
42
+
43
+ cachedMethods: [
44
+ "averageAge:age"
45
+ ]
46
+
47
+ averageAge: ()->
48
+ sum = @reduce (acc, user) ->
49
+ acc + user.get('age')
50
+ , 0
51
+ Math.floor(sum / @size)
52
+ ```
53
+ An `averageAge` will be cached and recalculated only when either
54
+ membership of the collection will change or `age` attribute on either member
55
+
56
+ ## Computed Properties on Luca.Model
57
+
58
+ ```coffeescript
59
+ _.def("MyModel").extends("Luca.Model").with
60
+ computed:
61
+ "expensive" : ["dependencyOne","dependencyTwo"]
62
+
63
+ expensive: ()->
64
+ @get("dependencyOne") + @get("dependencyTwo")
65
+ ```
66
+
67
+ In the example above, `expensive` method will be converted to the `expensive` property which is be computed/updated on initialization and every time any of its dependent properties will change. That `expensive` property will act as any other attribute on the model (responds to `get` operations, can be available in `toJSON()` etc).
68
+
69
+ Example:
70
+
71
+ ```coffeescript
72
+ _.def("User").extends("Luca.Model").with
73
+ computed:
74
+ "fullName": ["firstName","lastName"]
75
+ fullName: ()->
76
+ @get("firstName") + @get("lastName")
77
+ ```
data/docs/view.md ADDED
@@ -0,0 +1,119 @@
1
+ # Luca.View
2
+
3
+ The `Luca.View` class is the base class for Luca components. A number of patterns and optimizations that are helpful in your view classes have been extracted into the base class.
4
+
5
+ ## Hooks
6
+
7
+ In Backbone, views trigger events, and we can bind to them as normally, and that this is good. Often we are binding our view's methods to events that get triggered. In Luca, hooks are events you can declare on your component definition which will be automatically called if events get triggered with names which match the pattern. This saves you the work of having to set up event binding logic manually.
8
+
9
+ For example:
10
+
11
+ ```coffeescript
12
+ _.def("Luca.View").extends("Backbone.View").with
13
+ hooks:[
14
+ "after:initialize" # => will call the @afterInitialize method if it exists
15
+ "before:render" # => @beforeRender
16
+ "after:render" # => @afterRender
17
+ "first:activation" # => @firstActivation
18
+ "activation" # => @activation
19
+ "deactivation" # => @deactivation
20
+ ]
21
+ ```
22
+
23
+ **Note on extending hook methods**
24
+
25
+ If you want to maintain the functionality of the component you are extending from, you will have to remember to call the prototype method like such:
26
+
27
+ ```coffeescript
28
+ _.def("MyView").extends("Luca.View").with
29
+ beforeRender: ()->
30
+ @_super("beforeRender", @, arguments)
31
+
32
+ # or, if you prefer
33
+ Luca.View::beforeRender?.apply(@, arguments)
34
+ ```
35
+
36
+ ## The @render() method
37
+
38
+ The default implementation of @render() simply appends the view's `@$el` to the DOM element represented by the `$(@container)` property on the view.
39
+
40
+ Whatever method you choose to implement for your `@render()` call should behave similar to how the Backbone.View::render() expects, in that it should return an instance of the view.
41
+
42
+ Additionally, the call to `@render()` will trigger `before:render` and `after:render` as which, on a Luca.View is configured as a hook. So any `@beforeRender()` and `@afterRender()` method will get called as well, if they exist.
43
+
44
+ ## Before Render
45
+
46
+ Since in Luca, the actual render method just attaches the view to its container, setup related methods for building your view's content are best put in the `beforeRender()` method. In addition to this, there are other options available for filling the content of the view, like `@bodyTemplate`.
47
+
48
+ ## Luca.template helper
49
+
50
+ `Luca.template()` is a util function which allows you reference your client side template system. It accepts a name of a template ( which, if not found, it will attempt to match one for you ) and an object of interpolations to pass to the template function
51
+
52
+ `Luca.available_templates()` is a util function, useful for debugging, to see which templates are available to you.
53
+
54
+ ## Configuration Options
55
+
56
+ - `@additionalClassNames` - an array of CSS classes to apply to the view's `@$el`. This is helpful for inheritance of views.
57
+
58
+ - `@name` - Setting a name property on your view, will allow you to reference the instance of that view later.
59
+
60
+ ```coffeescript
61
+ view = new Luca.View(name:"my_view")
62
+
63
+ Luca("my_view") is view # => true
64
+
65
+ ```
66
+
67
+ - `@wrapperClass` - automatically wraps the view with a div with this as the CSS class.
68
+
69
+ - `@bodyTemplate` - will apply the content of the template to your view
70
+
71
+ - `@bindAllEvents` - true or false automatically bind all event handler methods to the context of your view's instance
72
+
73
+ - `@applicationEvents` - configuration similar to the DOM `@events` configuration on Backbone.View. Used to bind to events triggered by the `Luca.Application.get()` object. You can customize which application you use by setting `@app` to either reference the app, or to the name of a given application.
74
+
75
+ - `@collectionEvents` - configuration similar to the DOM `@events` configuration on Backbone.View. Used to bind to events triggered by the `Luca.CollectionManager.get()` object.
76
+
77
+ ## Luca.View::$bodyEl()
78
+
79
+ In your `Luca.View` definitions, If you set the `@bodyTemplate` property to one of the available templates, then on `initialize` the view will set the HTML of its DOM element to the contents of the template.
80
+
81
+ This is useful in cases where there is a fair amount of structural, or otherwise static DOM content in your view, and one of the standard `Luca.core.Container` components is not suited for what you want to do. The `Luca.components.Panel` view is basically just a `Luca.View` which has additional DOM containers for footers and headers. It accomplishes this through the use of the `@bodyClassName` and `@bodyTagName` properties.
82
+
83
+ `@bodyClassName` and `@bodyTagName` work the same way the `@className` and `@tagName` properties work on standard Backbone views. They are used to create a DOM element via `Backbone.View.prototype.make(@bodyTagName,class:@bodyClassName,id:@bodyId`
84
+
85
+ If you use `view.$bodyEl()` instead of the standard `view.$el()` that ships with Backbone, all of the standard DOM manipulation methods available will be scoped to the CSS selector that corresponds to the actual body element of your view.
86
+
87
+ ## Deferrable Rendering
88
+
89
+ The jury is still out as to whether or not deferrable rendering is a useful pattern, or whether it is too complex. The use case it was trying to optimize is for views which can only be rendered in response to an event being fired on another object. Such as `Backbone.Collection::fetch`.
90
+
91
+ If this is what you are doing, then this feature is for you.
92
+
93
+ The options available for views which use the `@deferrable` property are as follows:
94
+
95
+ - `@deferrable` - if you set a reference to an object, such as a collection, on the @deferrable property, then the call to `view.render()` will actually just set up an event binding to the `reset` event of your collection, and it will automatically call `fetch` for you on that collection.
96
+
97
+ If you set `@deferrable` to true then the view will expect a `@collection` property.
98
+
99
+ - `@deferrable_method` - a call to `@render()` on a `@deferrable` view will automatically call this method on the `@deferrable` object.
100
+
101
+ - `@deferrable_trigger` - if you use the deferrable system , by default, it will automatically call the `@deferrable_method` on your `@deferrable` object when you call `@render()`. However, if you want to defer this method being fired even later, just set the `@deferrable_trigger` property to whatever trigger your view will listen for.
102
+
103
+ A useful example would be for views which get rendered hidden, and activated if and only if the user does a specific action. ( For example, a TabView activating a secondary tab ). If that action triggers an event, and you want to delay the render process if and only if that event is triggered.
104
+
105
+ ## Helpers
106
+
107
+ - `view.$template` calls `view.$.html()` on your view, with whatever is returned from the template. Delegates to `Luca.template(templateName, customizationHash)`
108
+
109
+ - `view.$wrap` the same as `view.$el.wrap()` -- accepts a CSS class name string, or a DOM element
110
+
111
+ - `view.$append` the same as `view.$el.append()`
112
+
113
+ - `view.$container` - references `$( view.container )`. Note: the @container property is set on a view when it belongs to the `@components` property of a `Luca.core.Container` instance. It is just a standard CSS selector.
114
+
115
+ - `view.registerEvent()` manipulates your `@events` configuration on your Backbone.View and then calls `@delegateEvents` to make sure they are live.
116
+
117
+ ## Backbone Component Helpers
118
+
119
+ Views which have properties on them referencing other views, models, or collections, can access those objects by calling `view.models()` or `view.views()` or `view.collections()`. This is mainly useful for introspection, debugging, or what not.
@@ -1,6 +1,6 @@
1
1
  module Luca
2
2
  module Rails
3
- VERSION = "0.9.2"
3
+ VERSION = "0.9.4"
4
4
  end
5
5
  end
6
6
 
data/lib/luca/template.rb CHANGED
@@ -2,7 +2,11 @@ require 'tilt'
2
2
 
3
3
  module Luca
4
4
  class Template < Tilt::Template
5
- attr_accessor :namespace
5
+
6
+ def self.namespace
7
+ 'JST'
8
+ end
9
+
6
10
  def self.default_mime_type
7
11
  'application/javascript'
8
12
  end
@@ -20,7 +24,6 @@ module Luca
20
24
  def prepare
21
25
  options = @options.merge(:filename => eval_file, :line => line, :escape_attrs => false)
22
26
  @engine = ::Haml::Engine.new(data, options)
23
- self.namespace = "window.JST"
24
27
  end
25
28
 
26
29
  def evaluate(scope, locals, &block)
@@ -28,15 +31,12 @@ module Luca
28
31
  code = EJS.compile(compiled)
29
32
  tmpl = scope.logical_path
30
33
 
31
- tmpl.gsub! /^.*\/templates\//, ''
34
+ namespace = self.class.namespace
32
35
 
36
+ tmpl.gsub! /^.*\/templates\//, ''
37
+
33
38
  <<-JST
34
-
35
- (function() {
36
- #{namespace} || (#{namespace} = {});
37
- #{namespace}[#{ tmpl.inspect }] = #{indent(code)};
38
- }).call(this);
39
-
39
+ (function() {#{namespace} || (#{namespace} = {}); #{namespace}[#{ tmpl.inspect }] = #{indent(code)}; }).call(this);
40
40
  JST
41
41
  end
42
42
 
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Bootstrap.js by @fat & @mdo
3
+ * plugins: bootstrap-transition.js, bootstrap-modal.js, bootstrap-dropdown.js, bootstrap-tooltip.js, bootstrap-popover.js, bootstrap-alert.js, bootstrap-button.js, bootstrap-collapse.js, bootstrap-typeahead.js
4
+ * Copyright 2012 Twitter, Inc.
5
+ * http://www.apache.org/licenses/LICENSE-2.0.txt
6
+ */
7
+ !function(a){a(function(){a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery),!function(a){function c(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),d.call(b)},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),d.call(b)})}function d(a){this.$element.hide().trigger("hidden"),e.call(this)}function e(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('<div class="modal-backdrop '+d+'" />').appendTo(document.body),this.options.backdrop!="static"&&this.$backdrop.click(a.proxy(this.hide,this)),e&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),e?this.$backdrop.one(a.support.transition.end,b):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,a.proxy(f,this)):f.call(this)):b&&b()}function f(){this.$backdrop.remove(),this.$backdrop=null}function g(){var b=this;this.isShown&&this.options.keyboard?a(document).on("keyup.dismiss.modal",function(a){a.which==27&&b.hide()}):this.isShown||a(document).off("keyup.dismiss.modal")}var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this))};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;a("body").addClass("modal-open"),this.isShown=!0,g.call(this),e.call(this,function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in"),c?b.$element.one(a.support.transition.end,function(){b.$element.trigger("shown")}):b.$element.trigger("shown")})},hide:function(b){b&&b.preventDefault();var e=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,a("body").removeClass("modal-open"),g.call(this),this.$element.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?c.call(this):d.call(this)}},a.fn.modal=function(c){return this.each(function(){var d=a(this),e=d.data("modal"),f=a.extend({},a.fn.modal.defaults,d.data(),typeof c=="object"&&c);e||d.data("modal",e=new b(this,f)),typeof c=="string"?e[c]():f.show&&e.show()})},a.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},a.fn.modal.Constructor=b,a(function(){a("body").on("click.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({},e.data(),c.data());b.preventDefault(),e.modal(f)})})}(window.jQuery),!function(a){function d(){a(b).parent().removeClass("open")}var b='[data-toggle="dropdown"]',c=function(b){var c=a(b).on("click.dropdown.data-api",this.toggle);a("html").on("click.dropdown.data-api",function(){c.parent().removeClass("open")})};c.prototype={constructor:c,toggle:function(b){var c=a(this),e,f,g;if(c.is(".disabled, :disabled"))return;return f=c.attr("data-target"),f||(f=c.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,"")),e=a(f),e.length||(e=c.parent()),g=e.hasClass("open"),d(),g||e.toggleClass("open"),!1}},a.fn.dropdown=function(b){return this.each(function(){var d=a(this),e=d.data("dropdown");e||d.data("dropdown",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.dropdown.Constructor=c,a(function(){a("html").on("click.dropdown.data-api",d),a("body").on("click.dropdown",".dropdown form",function(a){a.stopPropagation()}).on("click.dropdown.data-api",b,c.prototype.toggle)})}(window.jQuery),!function(a){var b=function(a,b){this.init("tooltip",a,b)};b.prototype={constructor:b,init:function(b,c,d){var e,f;this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.enabled=!0,this.options.trigger!="manual"&&(e=this.options.trigger=="hover"?"mouseenter":"focus",f=this.options.trigger=="hover"?"mouseleave":"blur",this.$element.on(e,this.options.selector,a.proxy(this.enter,this)),this.$element.on(f,this.options.selector,a.proxy(this.leave,this))),this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(b){return b=a.extend({},a.fn[this.type].defaults,b,this.$element.data()),b.delay&&typeof b.delay=="number"&&(b.delay={show:b.delay,hide:b.delay}),b},enter:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);if(!c.options.delay||!c.options.delay.show)return c.show();clearTimeout(this.timeout),c.hoverState="in",this.timeout=setTimeout(function(){c.hoverState=="in"&&c.show()},c.options.delay.show)},leave:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);if(!c.options.delay||!c.options.delay.hide)return c.hide();clearTimeout(this.timeout),c.hoverState="out",this.timeout=setTimeout(function(){c.hoverState=="out"&&c.hide()},c.options.delay.hide)},show:function(){var a,b,c,d,e,f,g;if(this.hasContent()&&this.enabled){a=this.tip(),this.setContent(),this.options.animation&&a.addClass("fade"),f=typeof this.options.placement=="function"?this.options.placement.call(this,a[0],this.$element[0]):this.options.placement,b=/in/.test(f),a.remove().css({top:0,left:0,display:"block"}).appendTo(b?this.$element:document.body),c=this.getPosition(b),d=a[0].offsetWidth,e=a[0].offsetHeight;switch(b?f.split(" ")[1]:f){case"bottom":g={top:c.top+c.height,left:c.left+c.width/2-d/2};break;case"top":g={top:c.top-e,left:c.left+c.width/2-d/2};break;case"left":g={top:c.top+c.height/2-e/2,left:c.left-d};break;case"right":g={top:c.top+c.height/2-e/2,left:c.left+c.width}}a.css(g).addClass(f).addClass("in")}},isHTML:function(a){return typeof a!="string"||a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3||/^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(a)},setContent:function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.isHTML(b)?"html":"text"](b),a.removeClass("fade in top bottom left right")},hide:function(){function d(){var b=setTimeout(function(){c.off(a.support.transition.end).remove()},500);c.one(a.support.transition.end,function(){clearTimeout(b),c.remove()})}var b=this,c=this.tip();c.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d():c.remove()},fixTitle:function(){var a=this.$element;(a.attr("title")||typeof a.attr("data-original-title")!="string")&&a.attr("data-original-title",a.attr("title")||"").removeAttr("title")},hasContent:function(){return this.getTitle()},getPosition:function(b){return a.extend({},b?{top:0,left:0}:this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight})},getTitle:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||(typeof c.title=="function"?c.title.call(b[0]):c.title),a},tip:function(){return this.$tip=this.$tip||a(this.options.template)},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(){this[this.tip().hasClass("in")?"hide":"show"]()}},a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("tooltip"),f=typeof c=="object"&&c;e||d.data("tooltip",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover",title:"",delay:0}}(window.jQuery),!function(a){var b=function(a,b){this.init("popover",a,b)};b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype,{constructor:b,setContent:function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.isHTML(b)?"html":"text"](b),a.find(".popover-content > *")[this.isHTML(c)?"html":"text"](c),a.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-content")||(typeof c.content=="function"?c.content.call(b[0]):c.content),a},tip:function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip}}),a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("popover"),f=typeof c=="object"&&c;e||d.data("popover",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.defaults=a.extend({},a.fn.tooltip.defaults,{placement:"right",content:"",template:'<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'})}(window.jQuery),!function(a){var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function f(){e.trigger("closed").remove()}var c=a(this),d=c.attr("data-target"),e;d||(d=c.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),e=a(d),b&&b.preventDefault(),e.length||(e=c.hasClass("alert")?c:c.parent()),e.trigger(b=a.Event("close"));if(b.isDefaultPrevented())return;e.removeClass("in"),a.support.transition&&e.hasClass("fade")?e.on(a.support.transition.end,f):f()},a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("alert");e||d.data("alert",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.alert.Constructor=c,a(function(){a("body").on("click.alert.data-api",b,c.prototype.close)})}(window.jQuery),!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.button.defaults,c)};b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.data(),e=c.is("input")?"val":"html";a+="Text",d.resetText||c.data("resetText",c[e]()),c[e](d[a]||this.options[a]),setTimeout(function(){a=="loadingText"?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.parent('[data-toggle="buttons-radio"]');a&&a.find(".active").removeClass("active"),this.$element.toggleClass("active")},a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("button"),f=typeof c=="object"&&c;e||d.data("button",e=new b(this,f)),c=="toggle"?e.toggle():c&&e.setState(c)})},a.fn.button.defaults={loadingText:"loading..."},a.fn.button.Constructor=b,a(function(){a("body").on("click.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle")})})}(window.jQuery),!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.collapse.defaults,c),this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.prototype={constructor:b,dimension:function(){var a=this.$element.hasClass("width");return a?"width":"height"},show:function(){var b,c,d,e;if(this.transitioning)return;b=this.dimension(),c=a.camelCase(["scroll",b].join("-")),d=this.$parent&&this.$parent.find("> .accordion-group > .in");if(d&&d.length){e=d.data("collapse");if(e&&e.transitioning)return;d.collapse("hide"),e||d.data("collapse",null)}this.$element[b](0),this.transition("addClass",a.Event("show"),"shown"),this.$element[b](this.$element[0][c])},hide:function(){var b;if(this.transitioning)return;b=this.dimension(),this.reset(this.$element[b]()),this.transition("removeClass",a.Event("hide"),"hidden"),this.$element[b](0)},reset:function(a){var b=this.dimension();return this.$element.removeClass("collapse")[b](a||"auto")[0].offsetWidth,this.$element[a!==null?"addClass":"removeClass"]("collapse"),this},transition:function(b,c,d){var e=this,f=function(){c.type=="show"&&e.reset(),e.transitioning=0,e.$element.trigger(d)};this.$element.trigger(c);if(c.isDefaultPrevented())return;this.transitioning=1,this.$element[b]("in"),a.support.transition&&this.$element.hasClass("collapse")?this.$element.one(a.support.transition.end,f):f()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}},a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("collapse"),f=typeof c=="object"&&c;e||d.data("collapse",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.collapse.defaults={toggle:!0},a.fn.collapse.Constructor=b,a(function(){a("body").on("click.collapse.data-api","[data-toggle=collapse]",function(b){var c=a(this),d,e=c.attr("data-target")||b.preventDefault()||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=a(e).data("collapse")?"toggle":c.data();a(e).collapse(f)})})}(window.jQuery),!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.typeahead.defaults,c),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.$menu=a(this.options.menu).appendTo("body"),this.source=this.options.source,this.shown=!1,this.listen()};b.prototype={constructor:b,select:function(){var a=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(a)).change(),this.hide()},updater:function(a){return a},show:function(){var b=a.extend({},this.$element.offset(),{height:this.$element[0].offsetHeight});return this.$menu.css({top:b.top+b.height,left:b.left}),this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(b){var c=this,d,e;return this.query=this.$element.val(),this.query?(d=a.grep(this.source,function(a){return c.matcher(a)}),d=this.sorter(d),d.length?this.render(d.slice(0,this.options.items)).show():this.shown?this.hide():this):this.shown?this.hide():this},matcher:function(a){return~a.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(a){var b=[],c=[],d=[],e;while(e=a.shift())e.toLowerCase().indexOf(this.query.toLowerCase())?~e.indexOf(this.query)?c.push(e):d.push(e):b.push(e);return b.concat(c,d)},highlighter:function(a){var b=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return a.replace(new RegExp("("+b+")","ig"),function(a,b){return"<strong>"+b+"</strong>"})},render:function(b){var c=this;return b=a(b).map(function(b,d){return b=a(c.options.item).attr("data-value",d),b.find("a").html(c.highlighter(d)),b[0]}),b.first().addClass("active"),this.$menu.html(b),this},next:function(b){var c=this.$menu.find(".active").removeClass("active"),d=c.next();d.length||(d=a(this.$menu.find("li")[0])),d.addClass("active")},prev:function(a){var b=this.$menu.find(".active").removeClass("active"),c=b.prev();c.length||(c=this.$menu.find("li").last()),c.addClass("active")},listen:function(){this.$element.on("blur",a.proxy(this.blur,this)).on("keypress",a.proxy(this.keypress,this)).on("keyup",a.proxy(this.keyup,this)),(a.browser.webkit||a.browser.msie)&&this.$element.on("keydown",a.proxy(this.keypress,this)),this.$menu.on("click",a.proxy(this.click,this)).on("mouseenter","li",a.proxy(this.mouseenter,this))},keyup:function(a){switch(a.keyCode){case 40:case 38:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}a.stopPropagation(),a.preventDefault()},keypress:function(a){if(!this.shown)return;switch(a.keyCode){case 9:case 13:case 27:a.preventDefault();break;case 38:if(a.type!="keydown")break;a.preventDefault(),this.prev();break;case 40:if(a.type!="keydown")break;a.preventDefault(),this.next()}a.stopPropagation()},blur:function(a){var b=this;setTimeout(function(){b.hide()},150)},click:function(a){a.stopPropagation(),a.preventDefault(),this.select()},mouseenter:function(b){this.$menu.find(".active").removeClass("active"),a(b.currentTarget).addClass("active")}},a.fn.typeahead=function(c){return this.each(function(){var d=a(this),e=d.data("typeahead"),f=typeof c=="object"&&c;e||d.data("typeahead",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>'},a.fn.typeahead.Constructor=b,a(function(){a("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);if(c.data("typeahead"))return;b.preventDefault(),c.typeahead(c.data())})})}(window.jQuery)
@@ -847,8 +847,16 @@ button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-ap
847
847
  .with-mask .load-mask .progress {
848
848
  margin: 50px auto;
849
849
  width: 50%; }
850
+ html.luca-ui-fullscreen, body.luca-ui-fullscreen {
851
+ height: 100%; }
852
+
853
+ .luca-ui-fullscreen .fluid-viewport-wrapper {
854
+ padding-top: 40px; }
855
+ .luca-ui-fullscreen .luca-ui-viewport, .luca-ui-fullscreen .fullscreen-container {
856
+ min-height: 100%;
857
+ height: auto !important;
858
+ height: 100%; }
850
859
  .toolbar-container {
851
- overflow: hidden;
852
860
  clear: both; }
853
861
 
854
862
  .toolbar-container.top {
@@ -1286,6 +1294,16 @@ ul.typeahead.dropdown-menu {
1286
1294
  .font-large .CodeMirror {
1287
1295
  font-size: 18px;
1288
1296
  line-height: 1.7; }
1297
+
1298
+ #component_tester #editor_container .toolbar-container.bottom {
1299
+ margin: 0px; }
1300
+ #component_tester #editor_container .toolbar-container.bottom .luca-ui-toolbar {
1301
+ margin: 0px;
1302
+ padding: 0px; }
1303
+ #component_tester [data-luca-owner="component_detail"] {
1304
+ max-height: 600px;
1305
+ overflow: scroll;
1306
+ min-height: 400px; }
1289
1307
  .luca-ui-console .CodeMirror {
1290
1308
  font-family: "Monaco";
1291
1309
  font-size: 14px;
@@ -196,6 +196,16 @@ ul.typeahead.dropdown-menu {
196
196
  .font-large .CodeMirror {
197
197
  font-size: 18px;
198
198
  line-height: 1.7; }
199
+
200
+ #component_tester #editor_container .toolbar-container.bottom {
201
+ margin: 0px; }
202
+ #component_tester #editor_container .toolbar-container.bottom .luca-ui-toolbar {
203
+ margin: 0px;
204
+ padding: 0px; }
205
+ #component_tester [data-luca-owner="component_detail"] {
206
+ max-height: 600px;
207
+ overflow: scroll;
208
+ min-height: 400px; }
199
209
  .luca-ui-console .CodeMirror {
200
210
  font-family: "Monaco";
201
211
  font-size: 14px;