joosy 1.2.0.alpha.41 → 1.2.0.alpha.51
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/Gruntfile.coffee +27 -7
- data/bin/joosy +1 -1
- data/bower.json +3 -2
- data/build/joosy/extensions/preloaders.js +189 -0
- data/build/joosy/extensions/resources-form.js +588 -0
- data/build/joosy/extensions/resources.js +673 -0
- data/build/joosy.js +2395 -0
- data/{src/joosy/generators → generators}/base.coffee +2 -2
- data/{src/joosy/generators → generators/command}/command.coffee +16 -3
- data/generators/command/help.coffee +38 -0
- data/{src/joosy/generators → generators}/layout.coffee +0 -0
- data/{src/joosy/generators → generators}/page.coffee +0 -0
- data/{src/joosy/generators → generators}/project/base.coffee +2 -4
- data/{src/joosy/generators → generators}/project/standalone.coffee +4 -3
- data/{src/joosy/generators → generators}/project.coffee +0 -0
- data/generators/templates/application/base/application.coffee +13 -0
- data/{templates → generators/templates}/application/base/helpers/application.coffee +0 -0
- data/{templates → generators/templates}/application/base/layouts/application.coffee +0 -0
- data/{templates → generators/templates}/application/base/pages/application.coffee +0 -0
- data/{templates → generators/templates}/application/base/pages/welcome/index.coffee +0 -0
- data/{templates → generators/templates}/application/base/routes.coffee +0 -0
- data/{templates → generators/templates}/application/base/templates/layouts/application.jst.hamlc +0 -0
- data/{templates → generators/templates}/application/base/templates/pages/welcome/index.jst.hamlc +0 -0
- data/{templates → generators/templates}/application/standalone/Gruntfile.coffee +1 -0
- data/{templates → generators/templates}/application/standalone/Procfile +0 -0
- data/{templates → generators/templates}/application/standalone/_gitignore +0 -0
- data/generators/templates/application/standalone/bower.json +17 -0
- data/{templates → generators/templates}/application/standalone/package.json +0 -0
- data/{templates → generators/templates}/application/standalone/source/haml/index.haml +0 -0
- data/{templates → generators/templates}/application/standalone/source/stylesheets/application.styl +0 -0
- data/{templates → generators/templates}/layout/basic.coffee +0 -0
- data/{templates → generators/templates}/layout/namespaced.coffee +0 -0
- data/{templates → generators/templates}/page/basic.coffee +0 -0
- data/{templates → generators/templates}/page/namespaced.coffee +0 -0
- data/{templates → generators/templates}/widget/basic.coffee +0 -0
- data/{templates → generators/templates}/widget/namespaced.coffee +0 -0
- data/{src/joosy/generators → generators}/widget.coffee +0 -0
- data/lib/joosy.rb +3 -3
- data/package.json +2 -3
- data/source/joosy/application.coffee +95 -0
- data/source/joosy/events/namespace.coffee +24 -0
- data/{src → source}/joosy/extensions/preloaders/caching.coffee +0 -0
- data/{src → source}/joosy/extensions/preloaders/index.coffee +0 -0
- data/{src → source}/joosy/extensions/preloaders/inline.coffee +0 -0
- data/{src → source}/joosy/extensions/resources/base.coffee +16 -8
- data/{src → source}/joosy/extensions/resources/collection.coffee +0 -0
- data/{src → source}/joosy/extensions/resources/index.coffee +0 -0
- data/{src → source}/joosy/extensions/resources/rest.coffee +0 -0
- data/{src → source}/joosy/extensions/resources/rest_collection.coffee +0 -0
- data/{src → source}/joosy/extensions/resources-form/form.coffee +18 -18
- data/{src → source}/joosy/extensions/resources-form/helpers/form.coffee +6 -6
- data/{src → source}/joosy/extensions/resources-form/index.coffee +0 -0
- data/source/joosy/helpers/routes.coffee +10 -0
- data/source/joosy/helpers/view.coffee +115 -0
- data/{src/joosy/core → source/joosy}/helpers/widgets.coffee +1 -1
- data/{src/joosy/core → source/joosy}/joosy.coffee +59 -19
- data/source/joosy/layout.coffee +73 -0
- data/{src/joosy/core → source/joosy}/module.coffee +7 -2
- data/{src/joosy/core/modules/container.coffee → source/joosy/modules/dom.coffee} +24 -17
- data/source/joosy/modules/events.coffee +156 -0
- data/source/joosy/modules/filters.coffee +67 -0
- data/{src/joosy/core → source/joosy}/modules/log.coffee +7 -3
- data/source/joosy/modules/page/scrolling.coffee +51 -0
- data/source/joosy/modules/page/title.coffee +18 -0
- data/{src/joosy/core → source/joosy}/modules/renderer.coffee +12 -13
- data/{src/joosy/core → source/joosy}/modules/time_manager.coffee +5 -1
- data/{src/joosy/core → source/joosy}/modules/widgets_manager.coffee +9 -5
- data/source/joosy/page.coffee +68 -0
- data/{src/joosy/core → source/joosy}/resources/watcher.coffee +5 -1
- data/source/joosy/router.coffee +305 -0
- data/{src/joosy/core → source/joosy}/templaters/jst.coffee +10 -7
- data/source/joosy/widget.coffee +385 -0
- data/source/joosy.coffee +1 -0
- data/{src/vendor → source}/metamorph.coffee +0 -0
- data/spec/helpers/matchers.coffee +8 -1
- data/spec/joosy/core/application_spec.coffee +121 -20
- data/spec/joosy/core/helpers/view_spec.coffee +3 -3
- data/spec/joosy/core/helpers/widgets_spec.coffee +3 -6
- data/spec/joosy/core/joosy_spec.coffee +0 -5
- data/spec/joosy/core/layout_spec.coffee +2 -28
- data/spec/joosy/core/modules/dom_spec.coffee +133 -0
- data/spec/joosy/core/modules/events_spec.coffee +16 -9
- data/spec/joosy/core/modules/filters_spec.coffee +232 -89
- data/spec/joosy/core/modules/log_spec.coffee +2 -2
- data/spec/joosy/core/modules/renderer_spec.coffee +8 -4
- data/spec/joosy/core/page_spec.coffee +2 -201
- data/spec/joosy/core/router_spec.coffee +295 -233
- data/spec/joosy/core/templaters/jst_spec.coffee +1 -1
- data/spec/joosy/core/widget_spec.coffee +373 -34
- data/spec/joosy/environments/amd_spec.coffee +38 -0
- data/spec/joosy/environments/global_spec.coffee +21 -0
- data/spec/joosy/extensions/form/form_spec.coffee +18 -18
- data/spec/joosy/extensions/form/helpers/forms_spec.coffee +1 -1
- data/spec/joosy/extensions/resources/base_spec.coffee +23 -11
- data/tasks/joosy.coffee +6 -9
- metadata +75 -69
- data/lib/extensions/preloaders.js +0 -193
- data/lib/extensions/resources-form.js +0 -592
- data/lib/extensions/resources.js +0 -675
- data/lib/joosy.js +0 -2199
- data/spec/joosy/core/modules/container_spec.coffee +0 -153
- data/spec/joosy/core/modules/widget_manager_spec.coffee +0 -96
- data/src/joosy/core/application.coffee +0 -59
- data/src/joosy/core/helpers/view.coffee +0 -52
- data/src/joosy/core/layout.coffee +0 -174
- data/src/joosy/core/modules/events.coffee +0 -188
- data/src/joosy/core/modules/filters.coffee +0 -42
- data/src/joosy/core/page.coffee +0 -383
- data/src/joosy/core/router.coffee +0 -313
- data/src/joosy/core/widget.coffee +0 -88
- data/src/joosy.coffee +0 -1
- data/templates/application/base/application.coffee +0 -9
- data/templates/application/standalone/bower.json +0 -7
@@ -0,0 +1,385 @@
|
|
1
|
+
#= require joosy/joosy
|
2
|
+
#= require joosy/modules/log
|
3
|
+
#= require joosy/modules/events
|
4
|
+
#= require joosy/modules/dom
|
5
|
+
#= require joosy/modules/renderer
|
6
|
+
#= require joosy/modules/time_manager
|
7
|
+
#= require joosy/modules/filters
|
8
|
+
|
9
|
+
#
|
10
|
+
# Base class for all Joosy Widgets.
|
11
|
+
#
|
12
|
+
# Joosy expects you to perceive your actual application as a tree of widgets. Internally all high-level
|
13
|
+
# containers like {Layout} and {Page} are inheriting from Widget. Widget contains logic for:
|
14
|
+
#
|
15
|
+
# * Recursive nesting (widgets can contain widgets, etc.)
|
16
|
+
# * Loading and Unloading flows (proper initializations, destructions and replacements)
|
17
|
+
# * Filtering (afterLoad, beforeLoad and the family of paint filters)
|
18
|
+
#
|
19
|
+
# During the bootstrap, widgets can take either dependent or independent strategy. Dependent widgets form
|
20
|
+
# "dependent chains" that will be rendered together (HTML will be injected into DOM atomically). Such chains
|
21
|
+
# use paint filters of the top elements. Independent widgets on the other hand load on their own behalf and
|
22
|
+
# use their own paint filters. To understand this better, here is the sample:
|
23
|
+
#
|
24
|
+
# Let's say we have 4 widgets A, B, C and D nested into each other:
|
25
|
+
#
|
26
|
+
# A is the root widget
|
27
|
+
# B is nested into A. It does not define itself as an independent and therefore defaults to dependent rendering
|
28
|
+
# C is nested into B. It defines itself as an independent children
|
29
|
+
# D is nested into C. It does not define itself as an independent and therefore defaults to dependent rendering
|
30
|
+
#
|
31
|
+
# Then total chain of asynchronous callbacks goes with the following scenario.
|
32
|
+
#
|
33
|
+
# 1. A collects all the fetches from the whole tree recursively and starts them in parallel.
|
34
|
+
# 2. A runs erase on the previous same-level widget (attribute `@previos`) if one is given.
|
35
|
+
# 3. A runs beforePaint on itself when 2 is done.
|
36
|
+
# 4. A waits for step 3 and all fetches of containers in recursive dependency chain (equal to B) to complete.
|
37
|
+
# 5. A builds resulting HTML using:
|
38
|
+
# * HTML of dependency chain (B)
|
39
|
+
# * HTML of independent containers that are ready to be rendered (their own recursive dependency chain is fetched completely).
|
40
|
+
# 5. A forks every independent container that was not rendered (C).
|
41
|
+
# 6. A starts paint on itself and injects HTML into DOM.
|
42
|
+
# 7. C repeats steps 2-7 using itself as a base and D as its own recursive dependency chain
|
43
|
+
#
|
44
|
+
# @include Joosy.Modules.Log
|
45
|
+
# @include Joosy.Modules.Events
|
46
|
+
# @include Joosy.Modules.DOM
|
47
|
+
# @include Joosy.Modules.Renderer
|
48
|
+
# @include Joosy.Modules.TimeManager
|
49
|
+
# @include Joosy.Modules.Filters
|
50
|
+
#
|
51
|
+
class Joosy.Widget extends Joosy.Module
|
52
|
+
@include Joosy.Modules.Log
|
53
|
+
@include Joosy.Modules.Events
|
54
|
+
@include Joosy.Modules.DOM
|
55
|
+
@include Joosy.Modules.Renderer
|
56
|
+
@include Joosy.Modules.TimeManager
|
57
|
+
@include Joosy.Modules.Filters
|
58
|
+
|
59
|
+
#
|
60
|
+
# Extends widgets mapping
|
61
|
+
#
|
62
|
+
# Pass either widget class or instance as a value. Given lambdas are evaluated.
|
63
|
+
#
|
64
|
+
# @example
|
65
|
+
# @mapWidgets
|
66
|
+
# '.selector1': Widget1
|
67
|
+
# '.selector2': -> @widget = new Widget2
|
68
|
+
#
|
69
|
+
@mapWidgets: (map) ->
|
70
|
+
unless @::hasOwnProperty "__widgets"
|
71
|
+
@::__widgets = Object.clone(@.__super__.__widgets) || {}
|
72
|
+
Object.merge @::__widgets, map
|
73
|
+
|
74
|
+
#
|
75
|
+
# Declares widget as indepent changing the way it behaves during the bootstrap
|
76
|
+
#
|
77
|
+
@independent: ->
|
78
|
+
@::__independent = true
|
79
|
+
|
80
|
+
@registerPlainFilters \
|
81
|
+
#
|
82
|
+
# @method .beforeLoad(callback)
|
83
|
+
#
|
84
|
+
# Initialization hook that runs in the very begining of bootstrap process.
|
85
|
+
# Call it multiple times to attach several hooks.
|
86
|
+
#
|
87
|
+
'beforeLoad',
|
88
|
+
|
89
|
+
#
|
90
|
+
# @method .afterLoad(callback)
|
91
|
+
#
|
92
|
+
# Hook that runs after the section was properly loaded and injected into DOM.
|
93
|
+
# Call it multiple times to attach several hooks.
|
94
|
+
#
|
95
|
+
'afterLoad',
|
96
|
+
|
97
|
+
#
|
98
|
+
# @method .beforeUnload(callback)
|
99
|
+
#
|
100
|
+
# Hook that finalizes section desctruction.
|
101
|
+
# Call it multiple times to attach several hooks.
|
102
|
+
#
|
103
|
+
'afterUnload'
|
104
|
+
|
105
|
+
@registerSequencedFilters \
|
106
|
+
|
107
|
+
#
|
108
|
+
# @method .beforePaint(callback)
|
109
|
+
#
|
110
|
+
# Sets the method which will controll the painting preparation proccess.
|
111
|
+
#
|
112
|
+
# This method will be called right ater previous section erase and in parallel with
|
113
|
+
# new data fetching so you can use it to initiate preloader.
|
114
|
+
#
|
115
|
+
# @note Given method will be called with `complete` function as parameter. As soon as your
|
116
|
+
# preparations are done you should call that function.
|
117
|
+
#
|
118
|
+
# @example Sample before painter
|
119
|
+
# @beforePaint (complete) ->
|
120
|
+
# @$preloader.slideDown -> complete()
|
121
|
+
#
|
122
|
+
#
|
123
|
+
'beforePaint',
|
124
|
+
|
125
|
+
#
|
126
|
+
# @method .paint(callback)
|
127
|
+
#
|
128
|
+
# Sets the method which will controll the painting proccess.
|
129
|
+
#
|
130
|
+
# This method will be called after fetching, erasing and beforePaint is complete.
|
131
|
+
# It should be used to setup appearance effects of page.
|
132
|
+
#
|
133
|
+
# @note Given method will be called with `complete` function as parameter. As soon as your
|
134
|
+
# preparations are done you should call that function.
|
135
|
+
#
|
136
|
+
# @example Sample painter
|
137
|
+
# @paint (complete) ->
|
138
|
+
# @$container.fadeIn -> complete()
|
139
|
+
#
|
140
|
+
'paint',
|
141
|
+
|
142
|
+
#
|
143
|
+
# @method .erase(callback)
|
144
|
+
#
|
145
|
+
# Sets the method which will controll the erasing proccess.
|
146
|
+
#
|
147
|
+
# Use this method to setup hiding effect.
|
148
|
+
#
|
149
|
+
# @note Given method will be called with `complete` function as parameter. As soon as your
|
150
|
+
# preparations are done you should call that function.
|
151
|
+
#
|
152
|
+
# @note This method will be caled _before_ unload routines so in theory you can
|
153
|
+
# access page data from that. Think twice if you are doing it right though.
|
154
|
+
#
|
155
|
+
# @example Sample eraser
|
156
|
+
# @erase (complete) ->
|
157
|
+
# @$container.fadeOut -> complete()
|
158
|
+
#
|
159
|
+
'erase',
|
160
|
+
|
161
|
+
#
|
162
|
+
# @method .fetch(callback)
|
163
|
+
#
|
164
|
+
# Sets the method which will controll the data fetching proccess.
|
165
|
+
#
|
166
|
+
# @note Given method will be called with `complete` function as parameter. As soon as your
|
167
|
+
# preparations are done you should call that function.
|
168
|
+
#
|
169
|
+
# @example Basic usage
|
170
|
+
# @fetch (complete) ->
|
171
|
+
# $.get '/rumbas', (@data) => complete()
|
172
|
+
#
|
173
|
+
'fetch'
|
174
|
+
|
175
|
+
#
|
176
|
+
# @param [Hash] params Arbitrary parameters
|
177
|
+
# @param [Joosy.Layout] previous Same-level widget to replace
|
178
|
+
#
|
179
|
+
constructor: (@params, @previous) ->
|
180
|
+
|
181
|
+
#
|
182
|
+
# Registeres and runs widget inside specified container
|
183
|
+
#
|
184
|
+
# @param [DOM] container jQuery or direct dom node object
|
185
|
+
# @param [Joosy.Widget] widget Class or object of Joosy.Widget to register
|
186
|
+
#
|
187
|
+
registerWidget: ($container, widget) ->
|
188
|
+
if Object.isString $container
|
189
|
+
$container = @__normalizeSelector($container)
|
190
|
+
|
191
|
+
widget = @__normalizeWidget(widget)
|
192
|
+
widget.__bootstrapDefault $container
|
193
|
+
|
194
|
+
@__nestedSections ||= []
|
195
|
+
@__nestedSections.push widget
|
196
|
+
|
197
|
+
widget
|
198
|
+
|
199
|
+
#
|
200
|
+
# Unregisteres and destroys widget
|
201
|
+
#
|
202
|
+
# @param [Joosy.Widget] widget Object of Joosy.Widget to unregister
|
203
|
+
#
|
204
|
+
unregisterWidget: (widget) ->
|
205
|
+
widget.__unload()
|
206
|
+
|
207
|
+
@__nestedSections.splice @__nestedSections.indexOf(widget), 1
|
208
|
+
|
209
|
+
replaceWidget: (widget, replacement) ->
|
210
|
+
replacement = @__normalizeWidget(replacement)
|
211
|
+
replacement.previous = widget
|
212
|
+
|
213
|
+
replacement.__bootstrapDefault widget.$container
|
214
|
+
|
215
|
+
#
|
216
|
+
# @see Joosy.Router.navigate
|
217
|
+
#
|
218
|
+
navigate: ->
|
219
|
+
Joosy.Router?.navigate arguments...
|
220
|
+
|
221
|
+
#
|
222
|
+
# This is required by {Joosy.Modules.Renderer}
|
223
|
+
# Sets the base template dir to app_name/templates/widgets
|
224
|
+
#
|
225
|
+
__renderSection: ->
|
226
|
+
'widgets'
|
227
|
+
|
228
|
+
#
|
229
|
+
# Collects statically registered widgets to form default nesting map
|
230
|
+
#
|
231
|
+
__nestingMap: ->
|
232
|
+
map = {}
|
233
|
+
|
234
|
+
for selector, widget of @__widgets
|
235
|
+
widget = @__normalizeWidget(widget)
|
236
|
+
|
237
|
+
map[selector] =
|
238
|
+
instance: widget
|
239
|
+
nested: widget.__nestingMap()
|
240
|
+
|
241
|
+
map
|
242
|
+
|
243
|
+
#
|
244
|
+
# Shortcut for default bootstrap using statically registered widgets
|
245
|
+
#
|
246
|
+
# @param [jQuery] $container DOM container to inject to
|
247
|
+
#
|
248
|
+
__bootstrapDefault: ($container) ->
|
249
|
+
@__bootstrap @__nestingMap(), $container
|
250
|
+
|
251
|
+
#
|
252
|
+
# Bootstraps the section with given nestings at given container
|
253
|
+
#
|
254
|
+
# @example
|
255
|
+
# nestingMap =
|
256
|
+
# '#page':
|
257
|
+
# instance: page
|
258
|
+
# nested:
|
259
|
+
# '#widget1': {instance: widget1}
|
260
|
+
#
|
261
|
+
# layout.__bootstrap nestingMap, Joosy.Application.content()
|
262
|
+
#
|
263
|
+
# @param [Object] nestingMap Map of nested sections to bootstrap
|
264
|
+
# @param [jQuery] $container DOM container to inject into
|
265
|
+
# @param [boolean] fetch Boolean flag used to avoid double fetch during recursion
|
266
|
+
#
|
267
|
+
__bootstrap: (nestingMap, @$container, fetch=true) ->
|
268
|
+
@wait 'section:fetched section:erased', =>
|
269
|
+
@__runPaints [], =>
|
270
|
+
@__paint nestingMap, @$container
|
271
|
+
|
272
|
+
@__erase()
|
273
|
+
@__fetch(nestingMap) if fetch
|
274
|
+
|
275
|
+
#
|
276
|
+
# Recursively starts fetching for the whole nested tree. As soon as fetching is done, section
|
277
|
+
# triggers rememberable event 'section:fetched'
|
278
|
+
#
|
279
|
+
# Section can be considered fetched if (and triggers event when):
|
280
|
+
# * Its fetchers are complete
|
281
|
+
# * All the fetchers of all dependent nestings are complete
|
282
|
+
#
|
283
|
+
__fetch: (nestingMap) ->
|
284
|
+
@data = {}
|
285
|
+
|
286
|
+
@synchronize (context) =>
|
287
|
+
Object.each nestingMap, (selector, section) ->
|
288
|
+
section.instance.__fetch(section.nested)
|
289
|
+
|
290
|
+
if !section.instance.__independent
|
291
|
+
context.do (done) ->
|
292
|
+
section.instance.wait 'section:fetched', done
|
293
|
+
|
294
|
+
context.do (done) =>
|
295
|
+
@__runFetchs [], done
|
296
|
+
|
297
|
+
context.after =>
|
298
|
+
@trigger name: 'section:fetched', remember: true
|
299
|
+
|
300
|
+
#
|
301
|
+
# Runs erasing chain for the previous section and beforePaints for current
|
302
|
+
#
|
303
|
+
__erase: ->
|
304
|
+
if @previous?
|
305
|
+
@previous.__runErases [], =>
|
306
|
+
@previous.__unload()
|
307
|
+
|
308
|
+
@__runBeforePaints [], =>
|
309
|
+
@trigger name: 'section:erased', remember: true
|
310
|
+
else
|
311
|
+
@__runBeforePaints [], =>
|
312
|
+
@trigger name: 'section:erased', remember: true
|
313
|
+
|
314
|
+
#
|
315
|
+
# Builds HTML of section and its dependent nestings and injects it into DOM
|
316
|
+
#
|
317
|
+
__paint: (nestingMap, @$container) ->
|
318
|
+
@__nestedSections = []
|
319
|
+
@$container.html @__renderDefault?(@data || {})
|
320
|
+
|
321
|
+
@__load()
|
322
|
+
|
323
|
+
Object.each nestingMap, (selector, section) =>
|
324
|
+
@__nestedSections.push section.instance
|
325
|
+
|
326
|
+
$container = @__normalizeSelector(selector)
|
327
|
+
|
328
|
+
if !section.instance.__independent || section.instance.__triggeredEvents?['section:fetched']
|
329
|
+
section.instance.__paint section.nested, $container
|
330
|
+
else
|
331
|
+
section.instance.__bootstrap section.nested, $container, false
|
332
|
+
|
333
|
+
#
|
334
|
+
# Initializes section that was injected into DOM
|
335
|
+
#
|
336
|
+
__load: ->
|
337
|
+
@__assignElements()
|
338
|
+
@__delegateEvents()
|
339
|
+
@__runAfterLoads()
|
340
|
+
|
341
|
+
#
|
342
|
+
# Deinitializes section that is preparing to be removed from DOM
|
343
|
+
#
|
344
|
+
__unload: ->
|
345
|
+
section.__unload() for section in @__nestedSections
|
346
|
+
delete @__nestedSections
|
347
|
+
|
348
|
+
@__clearContainer()
|
349
|
+
@__clearTime()
|
350
|
+
@__removeMetamorphs()
|
351
|
+
@__runAfterUnloads()
|
352
|
+
delete @previous
|
353
|
+
|
354
|
+
#
|
355
|
+
# Normalizes selector and returns jQuery wrap
|
356
|
+
#
|
357
|
+
# Selector can be one of:
|
358
|
+
#
|
359
|
+
# * $container - gets raw main container
|
360
|
+
# * $elem - attempts to get values from {Joosy.Modules.DOM} mappings
|
361
|
+
# * .selector - raw CSS selectors pass as-is
|
362
|
+
#
|
363
|
+
__normalizeSelector: (selector) ->
|
364
|
+
if selector == '$container'
|
365
|
+
@$container
|
366
|
+
else
|
367
|
+
$(@__extractSelector(selector), @$container)
|
368
|
+
|
369
|
+
#
|
370
|
+
# Normalizes widget descrpition to its instance
|
371
|
+
#
|
372
|
+
# Besides already being instance it cann be either class or lambda
|
373
|
+
#
|
374
|
+
__normalizeWidget: (widget) ->
|
375
|
+
if Object.isFunction(widget) && !Joosy.Module.hasAncestor(widget, Joosy.Widget)
|
376
|
+
widget = widget.call(@)
|
377
|
+
|
378
|
+
if Joosy.Module.hasAncestor widget, Joosy.Widget
|
379
|
+
widget = new widget
|
380
|
+
|
381
|
+
widget
|
382
|
+
|
383
|
+
# AMD wrapper
|
384
|
+
if define?.amd?
|
385
|
+
define 'joosy/widget', -> Joosy.Widget
|
data/source/joosy.coffee
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
#= require joosy/application
|
File without changes
|
@@ -29,6 +29,12 @@ beforeEach ->
|
|
29
29
|
|
30
30
|
return true
|
31
31
|
|
32
|
+
toEqualHTML: (string) ->
|
33
|
+
html = @actual.replace(/>\s+</g, '><')
|
34
|
+
@message = -> "Expected '#{html}' to equal '#{string}'"
|
35
|
+
|
36
|
+
html == string
|
37
|
+
|
32
38
|
#
|
33
39
|
# Checks the exact equality of tag including attributes and content
|
34
40
|
# with the posibility to check attributes values by regexp
|
@@ -39,7 +45,8 @@ beforeEach ->
|
|
39
45
|
#
|
40
46
|
toBeTag: (tagName, content, attrs) ->
|
41
47
|
@message = =>
|
42
|
-
|
48
|
+
actual = $('<div>').append(@actual).html()
|
49
|
+
"Expected '#{actual}' to be a tag #{tagName} with attributes #{JSON.stringify attrs} and content '#{content}'"
|
43
50
|
|
44
51
|
tag = $ @actual
|
45
52
|
|
@@ -1,39 +1,140 @@
|
|
1
1
|
describe "Joosy.Application", ->
|
2
2
|
|
3
3
|
beforeEach ->
|
4
|
-
sinon.stub Joosy.Router, "
|
4
|
+
sinon.stub Joosy.Router, "setup"
|
5
5
|
@$ground.seed()
|
6
6
|
|
7
7
|
afterEach ->
|
8
|
-
Joosy.Router.
|
8
|
+
Joosy.Router.setup.restore()
|
9
|
+
Joosy.Application.reset()
|
9
10
|
|
10
11
|
it "initializes", ->
|
11
|
-
Joosy.Application.initialize '
|
12
|
+
Joosy.Application.initialize '#application', foo: {bar: 'baz'}
|
12
13
|
expect(Joosy.Application.page).toBeUndefined()
|
13
14
|
expect(Joosy.Application.selector).toEqual '#application'
|
14
|
-
expect(Joosy.Router.
|
15
|
-
expect(Joosy.Application.name).toEqual 'app'
|
15
|
+
expect(Joosy.Router.setup.callCount).toEqual 1
|
16
16
|
expect(Joosy.Application.config.foo.bar).toEqual 'baz'
|
17
17
|
expect(Joosy.Application.content()).toEqual $('#application')
|
18
18
|
|
19
|
-
it "
|
20
|
-
|
19
|
+
it "merges config", ->
|
20
|
+
Joosy.Application.initialize '#application', router: {html5: true}
|
21
|
+
expect(Joosy.Application.config.router.html5).toEqual true
|
22
|
+
expect(Joosy.Application.config.router.base).toEqual ''
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
+
describe "page changer", ->
|
25
|
+
beforeEach ->
|
26
|
+
Joosy.Application.initialize @$ground
|
24
27
|
|
25
|
-
|
26
|
-
|
28
|
+
class @Layout extends Joosy.Layout
|
29
|
+
@view (locals) -> locals.page 'div'
|
27
30
|
|
28
|
-
|
31
|
+
class @Page extends Joosy.Page
|
32
|
+
@view -> "page"
|
29
33
|
|
30
|
-
|
31
|
-
|
32
|
-
|
34
|
+
it "sets page to clean ground", ->
|
35
|
+
Joosy.Application.changePage(@Page, {foo: 'bar'})
|
36
|
+
expect(Joosy.Application.page instanceof @Page).toBeTruthy()
|
37
|
+
expect(Joosy.Application.page.params).toEqual foo: 'bar'
|
38
|
+
expect(@$ground.html()).toEqual 'page'
|
33
39
|
|
34
|
-
|
40
|
+
it "changes from page to page", ->
|
41
|
+
Joosy.Application.changePage(@Page, {foo: 'bar'})
|
42
|
+
expect(@$ground.html()).toEqual 'page'
|
43
|
+
page = Joosy.Application.page
|
35
44
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
45
|
+
Joosy.Application.changePage(@Page, {foo: 'bar'})
|
46
|
+
expect(@$ground.html()).toEqual 'page'
|
47
|
+
expect(Joosy.Application.page.previous).toEqual page
|
48
|
+
|
49
|
+
it "sets layouted page to clean ground", ->
|
50
|
+
@Page.layout @Layout
|
51
|
+
|
52
|
+
Joosy.Application.changePage(@Page, {foo: 'bar'})
|
53
|
+
expect(Joosy.Application.page instanceof @Page).toBeTruthy()
|
54
|
+
expect(Joosy.Application.page.params).toEqual foo: 'bar'
|
55
|
+
expect(Joosy.Application.page.layout.params).toEqual foo: 'bar'
|
56
|
+
expect(@$ground.html()).toBeTag 'div', 'page', id: /__joosy\d+/
|
57
|
+
|
58
|
+
it "changes from layouted page to layouted page", ->
|
59
|
+
@Page.layout @Layout
|
60
|
+
|
61
|
+
Joosy.Application.changePage(@Page, {foo: 'bar'})
|
62
|
+
expect(@$ground.html()).toBeTag 'div', 'page', id: /__joosy\d+/
|
63
|
+
page = Joosy.Application.page
|
64
|
+
layout = page.layout
|
65
|
+
|
66
|
+
Joosy.Application.changePage(@Page, {foo: 'bar'})
|
67
|
+
expect(@$ground.html()).toBeTag 'div', 'page', id: /__joosy\d+/
|
68
|
+
expect(Joosy.Application.page.previous).toEqual page
|
69
|
+
expect(Joosy.Application.page.layout).toEqual layout
|
70
|
+
|
71
|
+
it "changes from layouted page to page", ->
|
72
|
+
@Page.layout @Layout
|
73
|
+
|
74
|
+
Joosy.Application.changePage(@Page, {foo: 'bar'})
|
75
|
+
expect(@$ground.html()).toBeTag 'div', 'page', id: /__joosy\d+/
|
76
|
+
page = Joosy.Application.page
|
77
|
+
layout = page.layout
|
78
|
+
|
79
|
+
class Page extends Joosy.Page
|
80
|
+
@view -> "page"
|
81
|
+
|
82
|
+
Joosy.Application.changePage(Page, {foo: 'bar'})
|
83
|
+
expect(@$ground.html()).toEqual 'page'
|
84
|
+
expect(Joosy.Application.page.previous).toEqual layout
|
85
|
+
expect(Joosy.Application.page.layout).toBeUndefined()
|
86
|
+
|
87
|
+
it "passes @data to @view", ->
|
88
|
+
class Layout extends Joosy.Layout
|
89
|
+
@fetch (complete) ->
|
90
|
+
expect(@data).toEqual {}
|
91
|
+
@data.foo = 'bar'
|
92
|
+
complete()
|
93
|
+
|
94
|
+
@view (locals) ->
|
95
|
+
expect(locals.foo).toEqual 'bar'
|
96
|
+
|
97
|
+
class Page extends Joosy.Page
|
98
|
+
@layout Layout
|
99
|
+
|
100
|
+
@fetch (complete) ->
|
101
|
+
expect(@data).toEqual {}
|
102
|
+
@data.foo = 'bar'
|
103
|
+
complete()
|
104
|
+
|
105
|
+
@view (locals) ->
|
106
|
+
expect(locals.foo).toEqual 'bar'
|
107
|
+
|
108
|
+
Joosy.Application.changePage Page
|
109
|
+
|
110
|
+
it "sequences paint hooks", ->
|
111
|
+
spies = []
|
112
|
+
11.times -> spies.push sinon.spy()
|
113
|
+
|
114
|
+
class Layout extends Joosy.Layout
|
115
|
+
@beforePaint (complete) -> spies[0](); complete()
|
116
|
+
@fetch (complete) -> spies[2](); complete()
|
117
|
+
@paint (complete) -> spies[3](); complete()
|
118
|
+
|
119
|
+
@view spies[4]
|
120
|
+
|
121
|
+
class PageA extends Joosy.Page
|
122
|
+
@layout Layout
|
123
|
+
|
124
|
+
@fetch (complete) -> spies[1](); complete()
|
125
|
+
@erase (complete) -> spies[6](); complete()
|
126
|
+
@view spies[5]
|
127
|
+
|
128
|
+
class PageB extends Joosy.Page
|
129
|
+
@layout Layout
|
130
|
+
|
131
|
+
@beforePaint (complete) -> spies[7](); complete()
|
132
|
+
@fetch (complete) -> spies[8](); complete()
|
133
|
+
@paint (complete) -> spies[9](); complete()
|
134
|
+
|
135
|
+
@view spies[10]
|
136
|
+
|
137
|
+
Joosy.Application.changePage PageA
|
138
|
+
Joosy.Application.changePage PageB
|
139
|
+
|
140
|
+
expect(spies).toBeSequenced()
|
@@ -4,11 +4,11 @@ describe "Joosy.Helpers.View", ->
|
|
4
4
|
h = Joosy.Helpers.Application
|
5
5
|
|
6
6
|
it "renders tag with string content", ->
|
7
|
-
tag = h.
|
7
|
+
tag = h.contentTag 'div', 'content', {id: 'id'}
|
8
8
|
expect(tag).toEqual '<div id="id">content</div>'
|
9
9
|
|
10
10
|
it "renders tag with lambda content", ->
|
11
|
-
tag = h.
|
12
|
-
h.
|
11
|
+
tag = h.contentTag 'div', {id: 'id'}, ->
|
12
|
+
h.contentTag 'div', 'content', {id: 'id2'}
|
13
13
|
|
14
14
|
expect(tag).toEqual '<div id="id"><div id="id2">content</div></div>'
|
@@ -7,15 +7,12 @@ describe "Joosy.Helpers.Widgets", ->
|
|
7
7
|
class @Widget extends Joosy.Widget
|
8
8
|
@view -> "test"
|
9
9
|
|
10
|
-
|
11
|
-
class @Renderer extends Joosy.Module
|
12
|
-
@include Joosy.Modules.Renderer
|
13
|
-
@include Joosy.Modules.TimeManager
|
14
|
-
@include Joosy.Modules.WidgetsManager
|
10
|
+
class @Renderer extends Joosy.Page
|
15
11
|
|
16
12
|
@renderer = new @Renderer
|
17
13
|
@widget = new @Widget
|
18
|
-
@template = (context) =>
|
14
|
+
@template = (context) =>
|
15
|
+
context.widget 'div', @widget
|
19
16
|
|
20
17
|
it "renders widget tag", ->
|
21
18
|
runs ->
|
@@ -1,10 +1,5 @@
|
|
1
1
|
describe "Joosy", ->
|
2
2
|
|
3
|
-
it "initializes", ->
|
4
|
-
expect(Joosy.Application.config.debug).toBeFalsy()
|
5
|
-
expect(Joosy.Modules).toBeDefined()
|
6
|
-
expect(Joosy.Resources).toBeDefined()
|
7
|
-
|
8
3
|
it "generates proper UUIDs", ->
|
9
4
|
uuids = []
|
10
5
|
2.times -> uuids.push Joosy.uuid()
|
@@ -2,13 +2,7 @@ describe "Joosy.Layout", ->
|
|
2
2
|
|
3
3
|
beforeEach ->
|
4
4
|
class @Layout extends Joosy.Layout
|
5
|
-
@layout = new @Layout
|
6
|
-
|
7
|
-
it "has appropriate accessors", ->
|
8
|
-
callbackNames = ['beforePaint', 'paint', 'erase']
|
9
|
-
callbackNames.each (callbackName) =>
|
10
|
-
@Layout[callbackName] 'callback'
|
11
|
-
expect(@Layout::['__' + callbackName]).toEqual 'callback'
|
5
|
+
@layout = new @Layout $('#application')
|
12
6
|
|
13
7
|
it "generates uid", ->
|
14
8
|
@layout.page()
|
@@ -18,29 +12,9 @@ describe "Joosy.Layout", ->
|
|
18
12
|
@layout.page()
|
19
13
|
expect(@layout.content().selector).toEqual '#' + @layout.uid
|
20
14
|
|
21
|
-
it "has default view", ->
|
22
|
-
expect(@layout.__renderDefault instanceof Function).toBeTruthy()
|
23
|
-
|
24
15
|
it "integrates with Router", ->
|
25
16
|
target = sinon.stub Joosy.Router, 'navigate'
|
26
17
|
@layout.navigate 'there'
|
27
18
|
expect(target.callCount).toEqual 1
|
28
19
|
expect(target.alwaysCalledWithExactly 'there').toBeTruthy()
|
29
|
-
Joosy.Router.navigate.restore()
|
30
|
-
|
31
|
-
it "loads", ->
|
32
|
-
spies = []
|
33
|
-
spies.push sinon.spy(@layout, '__assignElements')
|
34
|
-
spies.push sinon.spy(@layout, '__delegateEvents')
|
35
|
-
spies.push sinon.spy(@layout, '__setupWidgets')
|
36
|
-
spies.push sinon.spy(@layout, '__runAfterLoads')
|
37
|
-
@layout.__load(@$ground)
|
38
|
-
expect(spies).toBeSequenced()
|
39
|
-
|
40
|
-
it "unloads", ->
|
41
|
-
spies = []
|
42
|
-
spies.push sinon.spy(@layout, '__clearTime')
|
43
|
-
spies.push sinon.spy(@layout, '__unloadWidgets')
|
44
|
-
spies.push sinon.spy(@layout, '__runAfterUnloads')
|
45
|
-
@layout.__unload()
|
46
|
-
expect(spies).toBeSequenced()
|
20
|
+
Joosy.Router.navigate.restore()
|