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.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/Gruntfile.coffee +27 -7
  4. data/bin/joosy +1 -1
  5. data/bower.json +3 -2
  6. data/build/joosy/extensions/preloaders.js +189 -0
  7. data/build/joosy/extensions/resources-form.js +588 -0
  8. data/build/joosy/extensions/resources.js +673 -0
  9. data/build/joosy.js +2395 -0
  10. data/{src/joosy/generators → generators}/base.coffee +2 -2
  11. data/{src/joosy/generators → generators/command}/command.coffee +16 -3
  12. data/generators/command/help.coffee +38 -0
  13. data/{src/joosy/generators → generators}/layout.coffee +0 -0
  14. data/{src/joosy/generators → generators}/page.coffee +0 -0
  15. data/{src/joosy/generators → generators}/project/base.coffee +2 -4
  16. data/{src/joosy/generators → generators}/project/standalone.coffee +4 -3
  17. data/{src/joosy/generators → generators}/project.coffee +0 -0
  18. data/generators/templates/application/base/application.coffee +13 -0
  19. data/{templates → generators/templates}/application/base/helpers/application.coffee +0 -0
  20. data/{templates → generators/templates}/application/base/layouts/application.coffee +0 -0
  21. data/{templates → generators/templates}/application/base/pages/application.coffee +0 -0
  22. data/{templates → generators/templates}/application/base/pages/welcome/index.coffee +0 -0
  23. data/{templates → generators/templates}/application/base/routes.coffee +0 -0
  24. data/{templates → generators/templates}/application/base/templates/layouts/application.jst.hamlc +0 -0
  25. data/{templates → generators/templates}/application/base/templates/pages/welcome/index.jst.hamlc +0 -0
  26. data/{templates → generators/templates}/application/standalone/Gruntfile.coffee +1 -0
  27. data/{templates → generators/templates}/application/standalone/Procfile +0 -0
  28. data/{templates → generators/templates}/application/standalone/_gitignore +0 -0
  29. data/generators/templates/application/standalone/bower.json +17 -0
  30. data/{templates → generators/templates}/application/standalone/package.json +0 -0
  31. data/{templates → generators/templates}/application/standalone/source/haml/index.haml +0 -0
  32. data/{templates → generators/templates}/application/standalone/source/stylesheets/application.styl +0 -0
  33. data/{templates → generators/templates}/layout/basic.coffee +0 -0
  34. data/{templates → generators/templates}/layout/namespaced.coffee +0 -0
  35. data/{templates → generators/templates}/page/basic.coffee +0 -0
  36. data/{templates → generators/templates}/page/namespaced.coffee +0 -0
  37. data/{templates → generators/templates}/widget/basic.coffee +0 -0
  38. data/{templates → generators/templates}/widget/namespaced.coffee +0 -0
  39. data/{src/joosy/generators → generators}/widget.coffee +0 -0
  40. data/lib/joosy.rb +3 -3
  41. data/package.json +2 -3
  42. data/source/joosy/application.coffee +95 -0
  43. data/source/joosy/events/namespace.coffee +24 -0
  44. data/{src → source}/joosy/extensions/preloaders/caching.coffee +0 -0
  45. data/{src → source}/joosy/extensions/preloaders/index.coffee +0 -0
  46. data/{src → source}/joosy/extensions/preloaders/inline.coffee +0 -0
  47. data/{src → source}/joosy/extensions/resources/base.coffee +16 -8
  48. data/{src → source}/joosy/extensions/resources/collection.coffee +0 -0
  49. data/{src → source}/joosy/extensions/resources/index.coffee +0 -0
  50. data/{src → source}/joosy/extensions/resources/rest.coffee +0 -0
  51. data/{src → source}/joosy/extensions/resources/rest_collection.coffee +0 -0
  52. data/{src → source}/joosy/extensions/resources-form/form.coffee +18 -18
  53. data/{src → source}/joosy/extensions/resources-form/helpers/form.coffee +6 -6
  54. data/{src → source}/joosy/extensions/resources-form/index.coffee +0 -0
  55. data/source/joosy/helpers/routes.coffee +10 -0
  56. data/source/joosy/helpers/view.coffee +115 -0
  57. data/{src/joosy/core → source/joosy}/helpers/widgets.coffee +1 -1
  58. data/{src/joosy/core → source/joosy}/joosy.coffee +59 -19
  59. data/source/joosy/layout.coffee +73 -0
  60. data/{src/joosy/core → source/joosy}/module.coffee +7 -2
  61. data/{src/joosy/core/modules/container.coffee → source/joosy/modules/dom.coffee} +24 -17
  62. data/source/joosy/modules/events.coffee +156 -0
  63. data/source/joosy/modules/filters.coffee +67 -0
  64. data/{src/joosy/core → source/joosy}/modules/log.coffee +7 -3
  65. data/source/joosy/modules/page/scrolling.coffee +51 -0
  66. data/source/joosy/modules/page/title.coffee +18 -0
  67. data/{src/joosy/core → source/joosy}/modules/renderer.coffee +12 -13
  68. data/{src/joosy/core → source/joosy}/modules/time_manager.coffee +5 -1
  69. data/{src/joosy/core → source/joosy}/modules/widgets_manager.coffee +9 -5
  70. data/source/joosy/page.coffee +68 -0
  71. data/{src/joosy/core → source/joosy}/resources/watcher.coffee +5 -1
  72. data/source/joosy/router.coffee +305 -0
  73. data/{src/joosy/core → source/joosy}/templaters/jst.coffee +10 -7
  74. data/source/joosy/widget.coffee +385 -0
  75. data/source/joosy.coffee +1 -0
  76. data/{src/vendor → source}/metamorph.coffee +0 -0
  77. data/spec/helpers/matchers.coffee +8 -1
  78. data/spec/joosy/core/application_spec.coffee +121 -20
  79. data/spec/joosy/core/helpers/view_spec.coffee +3 -3
  80. data/spec/joosy/core/helpers/widgets_spec.coffee +3 -6
  81. data/spec/joosy/core/joosy_spec.coffee +0 -5
  82. data/spec/joosy/core/layout_spec.coffee +2 -28
  83. data/spec/joosy/core/modules/dom_spec.coffee +133 -0
  84. data/spec/joosy/core/modules/events_spec.coffee +16 -9
  85. data/spec/joosy/core/modules/filters_spec.coffee +232 -89
  86. data/spec/joosy/core/modules/log_spec.coffee +2 -2
  87. data/spec/joosy/core/modules/renderer_spec.coffee +8 -4
  88. data/spec/joosy/core/page_spec.coffee +2 -201
  89. data/spec/joosy/core/router_spec.coffee +295 -233
  90. data/spec/joosy/core/templaters/jst_spec.coffee +1 -1
  91. data/spec/joosy/core/widget_spec.coffee +373 -34
  92. data/spec/joosy/environments/amd_spec.coffee +38 -0
  93. data/spec/joosy/environments/global_spec.coffee +21 -0
  94. data/spec/joosy/extensions/form/form_spec.coffee +18 -18
  95. data/spec/joosy/extensions/form/helpers/forms_spec.coffee +1 -1
  96. data/spec/joosy/extensions/resources/base_spec.coffee +23 -11
  97. data/tasks/joosy.coffee +6 -9
  98. metadata +75 -69
  99. data/lib/extensions/preloaders.js +0 -193
  100. data/lib/extensions/resources-form.js +0 -592
  101. data/lib/extensions/resources.js +0 -675
  102. data/lib/joosy.js +0 -2199
  103. data/spec/joosy/core/modules/container_spec.coffee +0 -153
  104. data/spec/joosy/core/modules/widget_manager_spec.coffee +0 -96
  105. data/src/joosy/core/application.coffee +0 -59
  106. data/src/joosy/core/helpers/view.coffee +0 -52
  107. data/src/joosy/core/layout.coffee +0 -174
  108. data/src/joosy/core/modules/events.coffee +0 -188
  109. data/src/joosy/core/modules/filters.coffee +0 -42
  110. data/src/joosy/core/page.coffee +0 -383
  111. data/src/joosy/core/router.coffee +0 -313
  112. data/src/joosy/core/widget.coffee +0 -88
  113. data/src/joosy.coffee +0 -1
  114. data/templates/application/base/application.coffee +0 -9
  115. 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
@@ -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
- "Expected #{@actual} to be a tag #{tagName} with attributes #{JSON.stringify attrs} and content '#{content}'"
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, "__setupRoutes"
4
+ sinon.stub Joosy.Router, "setup"
5
5
  @$ground.seed()
6
6
 
7
7
  afterEach ->
8
- Joosy.Router.__setupRoutes.restore()
8
+ Joosy.Router.setup.restore()
9
+ Joosy.Application.reset()
9
10
 
10
11
  it "initializes", ->
11
- Joosy.Application.initialize 'app', '#application', foo: {bar: 'baz'}
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.__setupRoutes.callCount).toEqual 1
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 "manages pages", ->
20
- spy = sinon.spy()
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
- class Page1
23
- constructor: spy
24
+ describe "page changer", ->
25
+ beforeEach ->
26
+ Joosy.Application.initialize @$ground
24
27
 
25
- class Page2
26
- constructor: spy
28
+ class @Layout extends Joosy.Layout
29
+ @view (locals) -> locals.page 'div'
27
30
 
28
- Joosy.Application.setCurrentPage(Page1, {foo: 'bar'})
31
+ class @Page extends Joosy.Page
32
+ @view -> "page"
29
33
 
30
- expect(Joosy.Application.page instanceof Page1).toBeTruthy()
31
- expect(spy.callCount).toEqual 1
32
- expect(spy.args[0]).toEqual [{foo: 'bar'}, undefined]
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
- Joosy.Application.setCurrentPage(Page2, {bar: 'baz'})
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
- expect(Joosy.Application.page instanceof Page2).toBeTruthy()
37
- expect(spy.callCount).toEqual 2
38
- expect(spy.args[1][0]).toEqual {bar: 'baz'}
39
- expect(spy.args[1][1] instanceof Page1).toBeTruthy()
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.tag 'div', {id: 'id'}, 'content'
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.tag 'div', {id: 'id'}, ->
12
- h.tag 'div', {id: 'id2'}, 'content'
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
- # Least possible configuration capable of using helper
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) => context.widget 'div', @widget
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()