joosy 0.1.0.alpha → 1.0.0.RC1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. data/.codoopts +5 -0
  2. data/.gitignore +2 -0
  3. data/Gemfile +15 -2
  4. data/Gemfile.lock +102 -81
  5. data/Guardfile +16 -16
  6. data/LICENSE +22 -0
  7. data/MIT-LICENSE +2 -2
  8. data/README.md +118 -0
  9. data/app/assets/javascripts/joosy/core/application.js.coffee +53 -0
  10. data/app/assets/javascripts/joosy/core/form.js.coffee +338 -0
  11. data/app/assets/javascripts/joosy/core/helpers/form.js.coffee +72 -0
  12. data/app/assets/javascripts/joosy/core/helpers/view.js.coffee +42 -0
  13. data/app/assets/javascripts/joosy/core/helpers/widgets.js.coffee +14 -0
  14. data/app/assets/javascripts/joosy/core/joosy.js.coffee +184 -0
  15. data/app/assets/javascripts/joosy/core/layout.js.coffee +168 -0
  16. data/app/assets/javascripts/joosy/core/modules/container.js.coffee +124 -0
  17. data/app/assets/javascripts/joosy/core/modules/events.js.coffee +122 -0
  18. data/app/assets/javascripts/joosy/core/modules/filters.js.coffee +39 -0
  19. data/app/assets/javascripts/joosy/core/modules/log.js.coffee +36 -0
  20. data/app/assets/javascripts/joosy/core/modules/module.js.coffee +117 -0
  21. data/app/assets/javascripts/joosy/core/modules/renderer.js.coffee +200 -0
  22. data/app/assets/javascripts/joosy/core/modules/time_manager.js.coffee +46 -0
  23. data/app/assets/javascripts/joosy/core/modules/widgets_manager.js.coffee +87 -0
  24. data/app/assets/javascripts/joosy/core/page.js.coffee +387 -0
  25. data/app/assets/javascripts/joosy/core/preloader.js.coffee +13 -0
  26. data/app/assets/javascripts/joosy/core/resource/collection.js.coffee +175 -0
  27. data/app/assets/javascripts/joosy/core/resource/generic.js.coffee +303 -0
  28. data/app/assets/javascripts/joosy/core/resource/rest.js.coffee +244 -0
  29. data/app/assets/javascripts/joosy/core/resource/rest_collection.js.coffee +24 -0
  30. data/app/assets/javascripts/joosy/core/router.js.coffee +201 -0
  31. data/app/assets/javascripts/joosy/core/templaters/rails_jst.js.coffee +37 -0
  32. data/app/assets/javascripts/joosy/core/widget.js.coffee +85 -0
  33. data/app/assets/javascripts/joosy/preloaders/caching.js.coffee +169 -0
  34. data/app/assets/javascripts/joosy/preloaders/inline.js.coffee +56 -0
  35. data/{vendor → app}/assets/javascripts/joosy.js.coffee +0 -1
  36. data/app/helpers/joosy/sprockets_helper.rb +39 -12
  37. data/joosy.gemspec +4 -3
  38. data/lib/joosy/rails/engine.rb +12 -1
  39. data/lib/joosy/rails/version.rb +2 -2
  40. data/lib/joosy.rb +9 -0
  41. data/lib/rails/generators/joosy/application_generator.rb +15 -3
  42. data/lib/rails/generators/joosy/joosy_base.rb +2 -2
  43. data/lib/rails/generators/joosy/layout_generator.rb +8 -1
  44. data/lib/rails/generators/joosy/page_generator.rb +21 -6
  45. data/lib/rails/generators/joosy/preloader_generator.rb +14 -7
  46. data/lib/rails/generators/joosy/resource_generator.rb +29 -0
  47. data/lib/rails/generators/joosy/templates/app/helpers/application.js.coffee +4 -0
  48. data/lib/rails/generators/joosy/templates/app/layouts/application.js.coffee +1 -0
  49. data/lib/rails/generators/joosy/templates/app/layouts/template.js.coffee +1 -1
  50. data/lib/rails/generators/joosy/templates/app/pages/application.js.coffee +1 -1
  51. data/lib/rails/generators/joosy/templates/app/pages/template.js.coffee +3 -3
  52. data/lib/rails/generators/joosy/templates/app/pages/welcome/index.js.coffee +22 -0
  53. data/lib/rails/generators/joosy/templates/app/resources/template.js.coffee +2 -0
  54. data/lib/rails/generators/joosy/templates/app/routes.js.coffee +7 -1
  55. data/lib/rails/generators/joosy/templates/app/templates/layouts/application.jst.hamlc +2 -0
  56. data/lib/rails/generators/joosy/templates/app/templates/pages/welcome/index.jst.hamlc +7 -0
  57. data/lib/rails/generators/joosy/templates/app/widgets/template.js.coffee +2 -2
  58. data/lib/rails/generators/joosy/templates/app.js.coffee +4 -0
  59. data/lib/rails/generators/joosy/templates/app_preloader.js.coffee.erb +9 -12
  60. data/lib/rails/generators/joosy/templates/app_resources_predefiner.js.coffee.erb +11 -0
  61. data/lib/rails/generators/joosy/templates/preload.html.erb +5 -6
  62. data/lib/rails/generators/joosy/templates/preload.html.haml +3 -5
  63. data/lib/rails/generators/joosy/widget_generator.rb +8 -1
  64. data/lib/rails/resources_with_joosy.rb +11 -0
  65. data/spec/javascripts/helpers/spec_helper.js.coffee +25 -0
  66. data/spec/javascripts/joosy/core/application_spec.js.coffee +40 -0
  67. data/spec/javascripts/joosy/core/form_spec.js.coffee +200 -0
  68. data/spec/javascripts/joosy/core/helpers/forms_spec.js.coffee +103 -0
  69. data/spec/javascripts/joosy/core/helpers/view_spec.js.coffee +10 -0
  70. data/spec/javascripts/joosy/core/joosy_spec.js.coffee +97 -0
  71. data/spec/javascripts/joosy/core/layout_spec.js.coffee +50 -0
  72. data/spec/javascripts/joosy/core/modules/container_spec.js.coffee +32 -27
  73. data/spec/javascripts/joosy/core/modules/events_spec.js.coffee +55 -18
  74. data/spec/javascripts/joosy/core/modules/filters_spec.js.coffee +28 -27
  75. data/spec/javascripts/joosy/core/modules/log_spec.js.coffee +3 -3
  76. data/spec/javascripts/joosy/core/modules/module_spec.js.coffee +6 -15
  77. data/spec/javascripts/joosy/core/modules/renderer_spec.js.coffee +203 -0
  78. data/spec/javascripts/joosy/core/modules/time_manager_spec.js.coffee +12 -7
  79. data/spec/javascripts/joosy/core/modules/widget_manager_spec.js.coffee +31 -17
  80. data/spec/javascripts/joosy/core/page_spec.js.coffee +178 -0
  81. data/spec/javascripts/joosy/core/resource/collection_spec.js.coffee +84 -0
  82. data/spec/javascripts/joosy/core/resource/generic_spec.js.coffee +149 -0
  83. data/spec/javascripts/joosy/core/resource/rest_collection_spec.js.coffee +31 -0
  84. data/spec/javascripts/joosy/core/resource/rest_spec.js.coffee +171 -0
  85. data/spec/javascripts/joosy/core/router_spec.js.coffee +143 -0
  86. data/spec/javascripts/joosy/core/templaters/rails_jst_spec.js.coffee +25 -0
  87. data/spec/javascripts/joosy/core/widget_spec.js.coffee +40 -0
  88. data/spec/javascripts/joosy/preloaders/caching_spec.js.coffee +36 -0
  89. data/spec/javascripts/joosy/preloaders/inline_spec.js.coffee +16 -0
  90. data/spec/javascripts/support/assets/coolface.jpg +0 -0
  91. data/spec/javascripts/support/assets/okay.jpg +0 -0
  92. data/spec/javascripts/support/assets/test.js +1 -0
  93. data/spec/javascripts/support/sinon-ie-1.3.1.js +82 -0
  94. data/vendor/assets/javascripts/jquery.form.js +978 -963
  95. data/vendor/assets/javascripts/metamorph.js +409 -0
  96. data/vendor/assets/javascripts/sugar.js +1057 -366
  97. metadata +95 -50
  98. data/README.rdoc +0 -3
  99. data/lib/joosy/forms.rb +0 -47
  100. data/lib/joosy-rails.rb +0 -5
  101. data/lib/rails/generators/joosy/templates/preload.html.slim +0 -21
  102. data/tmp/javascripts/.gitignore +0 -1
  103. data/tmp/spec/javascripts/helpers/.gitignore +0 -1
  104. data/vendor/assets/javascripts/base64.js +0 -135
  105. data/vendor/assets/javascripts/inflection.js +0 -656
  106. data/vendor/assets/javascripts/joosy/core/application.js.coffee +0 -26
  107. data/vendor/assets/javascripts/joosy/core/form.js.coffee +0 -87
  108. data/vendor/assets/javascripts/joosy/core/joosy.js.coffee +0 -62
  109. data/vendor/assets/javascripts/joosy/core/layout.js.coffee +0 -38
  110. data/vendor/assets/javascripts/joosy/core/modules/container.js.coffee +0 -51
  111. data/vendor/assets/javascripts/joosy/core/modules/events.js.coffee +0 -17
  112. data/vendor/assets/javascripts/joosy/core/modules/filters.js.coffee +0 -39
  113. data/vendor/assets/javascripts/joosy/core/modules/log.js.coffee +0 -12
  114. data/vendor/assets/javascripts/joosy/core/modules/module.js.coffee +0 -28
  115. data/vendor/assets/javascripts/joosy/core/modules/time_manager.js.coffee +0 -23
  116. data/vendor/assets/javascripts/joosy/core/modules/widgets_manager.js.coffee +0 -45
  117. data/vendor/assets/javascripts/joosy/core/page.js.coffee +0 -136
  118. data/vendor/assets/javascripts/joosy/core/resource/rest.js.coffee +0 -69
  119. data/vendor/assets/javascripts/joosy/core/resource/rest_collection.js.coffee +0 -42
  120. data/vendor/assets/javascripts/joosy/core/router.js.coffee +0 -75
  121. data/vendor/assets/javascripts/joosy/core/widget.js.coffee +0 -35
  122. data/vendor/assets/javascripts/joosy/preloader/development.js.coffee +0 -27
  123. data/vendor/assets/javascripts/joosy/preloader/production.js.coffee +0 -84
@@ -0,0 +1,168 @@
1
+ #= require joosy/core/joosy
2
+ #= require joosy/core/modules/module
3
+ #= require joosy/core/modules/log
4
+ #= require joosy/core/modules/events
5
+ #= require joosy/core/modules/container
6
+ #= require joosy/core/modules/renderer
7
+ #= require joosy/core/modules/time_manager
8
+ #= require joosy/core/modules/widgets_manager
9
+ #= require joosy/core/modules/filters
10
+
11
+ #
12
+ # Base class for all of your Joosy Layouts.
13
+ # @see http://guides.joosy.ws/guides/layouts-pages-and-routing.html
14
+ #
15
+ # @example Sample application layout
16
+ # class @ApplicationLayout extends Joosy.Layout
17
+ # @view 'application'
18
+ #
19
+ # @include Joosy.Modules.Log
20
+ # @include Joosy.Modules.Events
21
+ # @include Joosy.Modules.Container
22
+ # @include Joosy.Modules.Renderer
23
+ # @include Joosy.Modules.TimeManager
24
+ # @include Joosy.Modules.WidgetsManager
25
+ # @include Joosy.Modules.Filters
26
+ #
27
+ class Joosy.Layout extends Joosy.Module
28
+ @include Joosy.Modules.Log
29
+ @include Joosy.Modules.Events
30
+ @include Joosy.Modules.Container
31
+ @include Joosy.Modules.Renderer
32
+ @include Joosy.Modules.TimeManager
33
+ @include Joosy.Modules.WidgetsManager
34
+ @include Joosy.Modules.Filters
35
+
36
+ @view 'default'
37
+
38
+ #
39
+ # Sets the method which will controll the painting preparation proccess.
40
+ #
41
+ # This method will be called right ater previous layout {Joosy.Layout.erase} and in parallel with
42
+ # layout data fetching so you can use it to initiate preloader.
43
+ #
44
+ # @note Given method will be called with `complete` function as parameter. As soon as your
45
+ # preparations are done you should call that function.
46
+ #
47
+ # @example Sample before painter
48
+ # @beforePaint (complete) ->
49
+ # if !@data # checks if parallel fetching finished
50
+ # $('preloader').slideDown -> complete()
51
+ #
52
+ #
53
+ @beforePaint: (callback) ->
54
+ @::__beforePaint = callback
55
+
56
+ #
57
+ # Sets the method which will controll the painting proccess.
58
+ #
59
+ # This method will be called after fetching, erasing and beforePaint is complete.
60
+ # It should be used to setup appearance effects of layout.
61
+ #
62
+ # @note Given method will be called with `complete` function as parameter. As soon as your
63
+ # preparations are done you should call that function.
64
+ #
65
+ # @example Sample painter
66
+ # @paint (complete) ->
67
+ # @container.fadeIn -> complete()
68
+ #
69
+ @paint: (callback) ->
70
+ @::__paint = callback
71
+
72
+ #
73
+ # Sets the method which will controll the erasing proccess.
74
+ #
75
+ # Use this method to setup hiding effect.
76
+ #
77
+ # @note Given method will be called with `complete` function as parameter. As soon as your
78
+ # preparations are done you should call that function.
79
+ #
80
+ # @note This method will be caled _before_ unload routines so in theory you can
81
+ # access layout data from that. Think twice if you are doing it right though.
82
+ #
83
+ # @example Sample eraser
84
+ # @erase (complete) ->
85
+ # @container.fadeOut -> complete()
86
+ #
87
+ @erase: (callback) ->
88
+ @::__erase = callback
89
+
90
+ #
91
+ # Sets the method which will controll the data fetching proccess.
92
+ #
93
+ # @note Given method will be called with `complete` function as parameter. As soon as your
94
+ # preparations are done you should call that function.
95
+ #
96
+ # @note You are strongly encouraged to NOT fetch anything with Layout!
97
+ # Use {Joosy.Page.fetch}
98
+ #
99
+ # @example Basic usage
100
+ # @fetch (complete) ->
101
+ # $.get '/rumbas', (@data) => complete()
102
+ #
103
+ @fetch: (callback) ->
104
+ @::__fetch = callback
105
+
106
+ #
107
+ # Defaults to `false` to ease beforePaint state check.
108
+ #
109
+ data: false
110
+
111
+ #
112
+ # @param [Hash] params List of route params
113
+ #
114
+ constructor: (@params) ->
115
+
116
+ #
117
+ # @see Joosy.Router.navigate
118
+ #
119
+ navigate: (args...) ->
120
+ Joosy.Router.navigate(args...)
121
+
122
+ #
123
+ # This is required by {Joosy.Modules.Renderer}
124
+ # Sets the base template dir to app_name/templates/layouts
125
+ #
126
+ __renderSection: ->
127
+ 'layouts'
128
+
129
+ #
130
+ # Layout bootstrap proccess.
131
+ #
132
+ # * {Joosy.Modules.Container.refreshElements}
133
+ # * {Joosy.Modules.Container.__delegateEvents}
134
+ # * {Joosy.Modules.WidgetsManager.__setupWidgets}
135
+ #
136
+ __load: (@container) ->
137
+ @refreshElements()
138
+ @__delegateEvents()
139
+ @__setupWidgets()
140
+ @__runAfterLoads()
141
+
142
+ #
143
+ # Layout destruction proccess.
144
+ #
145
+ # * {Joosy.Modules.TimeManager.__clearTime}
146
+ # * {Joosy.Modules.WidgetsManager.__unloadWidgets}
147
+ # * {Joosy.Modules.Renderer.__removeMetamorphs}
148
+ #
149
+ __unload: ->
150
+ @__clearTime()
151
+ @__unloadWidgets()
152
+ @__removeMetamorphs()
153
+ @__runAfterUnloads()
154
+
155
+ #
156
+ # @todo Rename this shit already. We are not going to release having function that marks
157
+ # element with UUID called `yield`.
158
+ #
159
+ yield: ->
160
+ @uuid = Joosy.uuid()
161
+
162
+ #
163
+ # Gets layout element.
164
+ #
165
+ # @return [jQuery]
166
+ #
167
+ content: ->
168
+ $("##{@uuid}")
@@ -0,0 +1,124 @@
1
+ #
2
+ # DOM container handling, DOM elements and DOM events bindings
3
+ #
4
+ # @note Requires implementor to contain DOM node at @container propert
5
+ #
6
+ # @mixin
7
+ #
8
+ Joosy.Modules.Container =
9
+ events: false
10
+ elements: false
11
+
12
+ eventSplitter: /^(\S+)\s*(.*)$/
13
+
14
+ onRefresh: (callback) ->
15
+ @__onRefreshes = [] unless @hasOwnProperty "__onRefreshes"
16
+ @__onRefreshes.push callback
17
+
18
+ $: (selector) ->
19
+ $(selector, @container)
20
+
21
+ #
22
+ # Rebinds selectors defined in 'elements' hash to object properties
23
+ #
24
+ # @example Sample elements
25
+ # elements:
26
+ # foo: '.foo'
27
+ # bar: '.bar'
28
+ #
29
+ refreshElements: ->
30
+ @__collectElements().each (key, value) =>
31
+ # TODO: Check for possible collisions?
32
+ @[key] = @$(value)
33
+
34
+ if @hasOwnProperty "__onRefreshes"
35
+ @__onRefreshes.each (callback) => callback.apply @
36
+ @__onRefreshes = []
37
+
38
+ #
39
+ # Clears old HTML links, set the new HTML from the callback and refreshes elements
40
+ #
41
+ # @param [Function] htmlCallback `() -> String` callback that will generate new HTML
42
+ #
43
+ reloadContainer: (htmlCallback) ->
44
+ @__removeMetamorphs?()
45
+ @container.html htmlCallback()
46
+ @refreshElements()
47
+
48
+ #
49
+ # Fills container with given data removing all events
50
+ #
51
+ # @param [jQuery] container jQuery entity of container to update
52
+ # @param [String] data HTML to inject
53
+ #
54
+ swapContainer: (container, data) ->
55
+ container.unbind().off()
56
+ container.html data
57
+ container
58
+
59
+ #
60
+ # Gathers 'elements' from current and super classes
61
+ #
62
+ __collectElements: ->
63
+ elements = Object.extended @elements || {}
64
+
65
+ klass = this
66
+ while klass = klass.constructor.__super__
67
+ Joosy.Module.merge elements, klass.elements, false
68
+
69
+ elements
70
+
71
+ #
72
+ # Gathers 'events' from current and super classes
73
+ #
74
+ __collectEvents: ->
75
+ events = Object.extended @events || {}
76
+
77
+ klass = this
78
+ while klass = klass.constructor.__super__
79
+ Joosy.Module.merge events, klass.events, false
80
+
81
+ events
82
+
83
+ #
84
+ # Converts '$...' notation to selector from 'elements'
85
+ #
86
+ # @param [String] selector Selector to convert
87
+ #
88
+ __extractSelector: (selector) ->
89
+ if r = selector.match /\$([A-z]+)/
90
+ selector = @__collectElements()[r[1]]
91
+
92
+ selector
93
+
94
+ #
95
+ # Bings events defined in 'events' to container
96
+ #
97
+ # @example Sample events
98
+ # events:
99
+ # 'click': -> # this will raise on container click
100
+ # 'click .foo': -> # this will raise on .foo click
101
+ # 'click $foo': -> #this will search for selector of foo element
102
+ #
103
+ __delegateEvents: ->
104
+ module = this
105
+ events = @__collectEvents()
106
+
107
+ events.each (key, method) =>
108
+ unless Object.isFunction method
109
+ method = @[method]
110
+ callback = (event) ->
111
+ method.call module, this, event
112
+
113
+ match = key.match @eventSplitter
114
+ eventName = match[1]
115
+ selector = @__extractSelector match[2]
116
+
117
+ if selector == ""
118
+ @container.bind eventName, callback
119
+ Joosy.Modules.Log.debugAs @, "#{eventName} binded on container"
120
+ else if selector == undefined
121
+ throw new Error "Unknown element #{match[2]} in #{Joosy.Module.__className @constructor} (maybe typo?)"
122
+ else
123
+ @container.on eventName, selector, callback
124
+ Joosy.Modules.Log.debugAs @, "#{eventName} binded on #{selector}"
@@ -0,0 +1,122 @@
1
+ #
2
+ # Basic events implementation
3
+ #
4
+ # @mixin
5
+ #
6
+ Joosy.Modules.Events =
7
+
8
+ #
9
+ # Waits for the list of given events to happen at least once. Then runs callback.
10
+ #
11
+ # @param [String] events List of events to wait for separated by space
12
+ # @param [Function] callback Action to run when all events were triggered at least once
13
+ #
14
+ wait: (events, callback) ->
15
+ events = events.split /\s+/ if Object.isString events
16
+
17
+ @__oneShotEvents ||= []
18
+ @__oneShotEvents.push [events, callback]
19
+
20
+ #
21
+ # Binds action to run each time any of given even was triggered
22
+ #
23
+ # @param [String] events List of events separated by space
24
+ # @param [Function] callback Action to run on trigger
25
+ #
26
+ bind: (events, callback) ->
27
+ events = events.split /\s+/
28
+
29
+ @__boundEvents ||= []
30
+ @__boundEvents.push [events, callback]
31
+
32
+ #
33
+ # Unbinds action from runing on trigger
34
+ #
35
+ # @param [Function] target Action to unbind
36
+ #
37
+ unbind: (target) ->
38
+ for [events, callback], index in @__boundEvents
39
+ if callback == target
40
+ @__boundEvents.splice index, 1
41
+ return
42
+
43
+ #
44
+ # Triggers event for {bind} and {wait}
45
+ #
46
+ # @param [String] Name of event to trigger
47
+ #
48
+ trigger: (event, data...) ->
49
+ Joosy.Modules.Log.debugAs @, "Event #{event} triggered"
50
+ if @__oneShotEvents
51
+ fire = []
52
+ for [events, callback], index in @__oneShotEvents
53
+ events.remove event
54
+ if events.length == 0
55
+ fire.push index
56
+ fire.each (index) =>
57
+ callback = @__oneShotEvents[index][1]
58
+ @__oneShotEvents.removeAt index
59
+ callback data...
60
+ if @__boundEvents
61
+ for [events, callback] in @__boundEvents
62
+ if events.has event
63
+ callback data...
64
+
65
+ #
66
+ # Runs set of callbacks finializing with result callback
67
+ #
68
+ # @example Basic usage
69
+ # Joosy.synchronize (context) ->
70
+ # contet.do (done) -> done()
71
+ # contet.do (done) -> done()
72
+ # content.after ->
73
+ # console.log 'Success!'
74
+ #
75
+ # @param [Function] block Configuration block (see example)
76
+ #
77
+ synchronize: (block) ->
78
+ context = new Joosy.Modules.Events.SynchronizationContext(this)
79
+ block.call(this, context)
80
+
81
+ @wait context.expectations, => context.after.call(this)
82
+
83
+ context.actions.each (data) =>
84
+ data[0].call this, =>
85
+ @trigger data[1]
86
+
87
+ #
88
+ # Internal representation of {Joosy.Modules.Events.synchronize} context
89
+ #
90
+ # @see Joosy.Modules.Events.synchronize
91
+ #
92
+ class Joosy.Modules.Events.SynchronizationContext
93
+ @uid = 0
94
+
95
+ constructor: (@parent) ->
96
+ @expectations = []
97
+ @actions = []
98
+
99
+ #
100
+ # Internal simple counter to separate given synchronization actions
101
+ #
102
+ uid: ->
103
+ @constructor.uid += 1
104
+
105
+ #
106
+ # Registeres another async function that should be synchronized
107
+ #
108
+ # @param [Function] action `(Function) -> null` to call.
109
+ # Should call given function to mark itself complete.
110
+ #
111
+ do: (action) ->
112
+ event = "synchro-#{@uid()}"
113
+ @expectations.push event
114
+ @actions.push [action, event]
115
+
116
+ #
117
+ # Registers finalizer: the action that will be called when all do-functions
118
+ # marked themselves as complete.
119
+ #
120
+ # @param [Function] after Function to call.
121
+ #
122
+ after: (@after) ->
@@ -0,0 +1,39 @@
1
+ #
2
+ # Filters registration routines
3
+ #
4
+ # @mixin
5
+ #
6
+ Joosy.Modules.Filters =
7
+
8
+ #
9
+ # Defines static registration routines
10
+ #
11
+ # @example Set of methods
12
+ # class Test
13
+ # @beforeLoad -> # supposed to run before load and control loading queue
14
+ # @afterLoad -> # supposed to run after load to finalize loading
15
+ # @afterUnload -> # supposed to run after unload to collect garbage
16
+ #
17
+ # # private
18
+ #
19
+ # @__runBeforeLoads() # Runs filters registered as beforeLoad
20
+ # @__runAfterLoads() # Runs filters registered as afterLoad
21
+ # @__runAfterUnloads() # Runs filters registered as afterUnload
22
+ #
23
+ included: ->
24
+ ['beforeLoad', 'afterLoad', 'afterUnload'].each (filter) =>
25
+ @[filter] = (callback) ->
26
+ unless @::hasOwnProperty "__#{filter}s"
27
+ @::["__#{filter}s"] = [].concat @.__super__["__#{filter}s"] || []
28
+ @::["__#{filter}s"].push callback
29
+
30
+
31
+ ['beforeLoad', 'afterLoad', 'afterUnload'].each (filter) =>
32
+ Joosy.Modules.Filters["__run#{filter.camelize(true)}s"] = (opts...) ->
33
+ return true unless @["__#{filter}s"]
34
+
35
+ @["__#{filter}s"].reduce (flag, func) =>
36
+ unless Object.isFunction func
37
+ func = @[func]
38
+ flag && func.apply(@, opts) != false
39
+ , true
@@ -0,0 +1,36 @@
1
+ #
2
+ # Wrappers for console.log
3
+ #
4
+ # @mixin
5
+ #
6
+ Joosy.Modules.Log =
7
+
8
+ #
9
+ # Checks if console is available and proxies given arguments directly to `console.log`
10
+ #
11
+ log: (args...) ->
12
+ return unless console?
13
+
14
+ if console.log.apply?
15
+ args.unshift "Joosy>"
16
+ console.log args...
17
+ else
18
+ console.log args.first()
19
+
20
+ #
21
+ # Runs `log` if debug is active
22
+ #
23
+ debug: (args...) ->
24
+ return unless Joosy.debug
25
+ @log args...
26
+
27
+ #
28
+ # Logs given message wrapping it with description of given object (class name)
29
+ #
30
+ # @param [Object] context The class required to be described in log message
31
+ # @param [String] string Message to log
32
+ #
33
+ debugAs: (context, string, args...) ->
34
+ return unless Joosy.debug
35
+ context = Joosy.Module.__className(context) || 'unknown context'
36
+ @debug "#{context}> #{string}", args...
@@ -0,0 +1,117 @@
1
+ moduleKeywords = ['included', 'extended']
2
+
3
+ #
4
+ # Base Joosy class extending Coffee class with module-like injections
5
+ # and other tiny stuff.
6
+ #
7
+ class Joosy.Module
8
+ #
9
+ # Sets the default namespace for all Joosy descendants.
10
+ # This is used in {Joosy.namespace} magic.
11
+ #
12
+ @__namespace__: []
13
+
14
+ #
15
+ # Gets Object/Class class name.
16
+ #
17
+ # @note Never use this to make some magical auto-suggestions!!!
18
+ # Remember: minifcation will rename your classes. Therefore it
19
+ # is only intended for development debugging purposes.
20
+ #
21
+ # @note Go @jashkenas Go! Give us https://github.com/jashkenas/coffee-script/issues/2052.
22
+ # Please go vote for this feature if you are reading this. It will
23
+ # give us ability to eleminate a lot of boilerplate for you.
24
+ #
25
+ # @return [String]
26
+ #
27
+ @__className: (klass) ->
28
+ unless Object.isFunction(klass)
29
+ klass = klass.constructor
30
+
31
+ if klass.name?
32
+ klass.name
33
+ else
34
+ klass.toString().replace /^function ([a-zA-Z]+)\([\s\S]+/, '$1'
35
+
36
+ #
37
+ # Determines if class A has class B in its ancestors.
38
+ #
39
+ # @param [Class] what Class to check againt
40
+ # @param [Class] klass Possible ancestor to search for
41
+ #
42
+ # @return [Boolean]
43
+ #
44
+ @hasAncestor: (what, klass) ->
45
+ unless what? && klass?
46
+ return false
47
+
48
+ [what, klass] = [what.prototype, klass.prototype]
49
+
50
+ while what
51
+ if what == klass
52
+ return true
53
+ what = what.constructor?.__super__
54
+
55
+ false
56
+
57
+ @alias: (method, feature, action) ->
58
+ chained = "#{method}Without#{feature.camelize()}"
59
+
60
+ @::[chained] = @::[method]
61
+ @::[method] = action
62
+
63
+ @aliasStatic: (method, feature, action) ->
64
+ chained = "#{method}Without#{feature.camelize()}"
65
+
66
+ @[chained] = @[method]
67
+ @[method] = action
68
+
69
+ #
70
+ # Simple and fast shallow merge implementation.
71
+ #
72
+ # This is here due to: https://github.com/andrewplummer/Sugar/issues/100.
73
+ # This bug was closed and we got some performance but this implementation is
74
+ # still like 10x fater for basic tasks.
75
+ #
76
+ # @param [Object] destination Object to extend
77
+ # @param [Object] source Source of new properties
78
+ # @param [Boolean] unsafe Determines if we should rewrite destination properties
79
+ #
80
+ # @return [Object] The new and mighty destination Object
81
+ #
82
+ @merge: (destination, source, unsafe=true) ->
83
+ for key, value of source
84
+ if source.hasOwnProperty(key)
85
+ if unsafe || !destination.hasOwnProperty(key)
86
+ destination[key] = value
87
+ destination
88
+
89
+ #
90
+ # Mixes given object as dynamic methods
91
+ #
92
+ # @param [Object] object Module object
93
+ #
94
+ @include: (object) ->
95
+ unless object
96
+ throw new Error 'include(object) requires obj'
97
+
98
+ Object.each object, (key, value) =>
99
+ if key not in moduleKeywords
100
+ this::[key] = value
101
+
102
+ object.included?.apply this
103
+ null
104
+
105
+ #
106
+ # Mixes given object as static methods
107
+ #
108
+ # @param [Object] object Module object
109
+ #
110
+ @extend: (object) ->
111
+ unless object
112
+ throw new Error 'extend(object) requires object'
113
+
114
+ @merge this, object
115
+
116
+ object.extended?.apply this
117
+ null