joosy 1.2.0.alpha.38 → 1.2.0.alpha.41
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gruntfile.coffee +15 -7
- data/bower.json +4 -3
- data/lib/extensions/resources.js +11 -3
- data/lib/joosy.js +235 -300
- data/package.json +3 -3
- data/spec/helpers/ground.coffee +33 -0
- data/spec/helpers/matchers.coffee +65 -0
- data/spec/joosy/core/application_spec.coffee +8 -8
- data/spec/joosy/core/helpers/view_spec.coffee +9 -5
- data/spec/joosy/core/helpers/widgets_spec.coffee +43 -10
- data/spec/joosy/core/joosy_spec.coffee +42 -50
- data/spec/joosy/core/layout_spec.coffee +30 -34
- data/spec/joosy/core/modules/container_spec.coffee +79 -76
- data/spec/joosy/core/modules/events_spec.coffee +148 -81
- data/spec/joosy/core/modules/filters_spec.coffee +68 -49
- data/spec/joosy/core/modules/log_spec.coffee +13 -5
- data/spec/joosy/core/modules/module_spec.coffee +24 -14
- data/spec/joosy/core/modules/renderer_spec.coffee +95 -89
- data/spec/joosy/core/modules/time_manager_spec.coffee +11 -16
- data/spec/joosy/core/modules/widget_manager_spec.coffee +89 -71
- data/spec/joosy/core/page_spec.coffee +201 -137
- data/spec/joosy/core/templaters/jst_spec.coffee +62 -0
- data/spec/joosy/core/widget_spec.coffee +25 -29
- data/spec/joosy/extensions/form/form_spec.coffee +3 -1
- data/spec/joosy/extensions/resources/base_spec.coffee +3 -0
- data/spec/joosy/extensions/resources/collection_spec.coffee +3 -0
- data/spec/joosy/extensions/resources/rest_collection_spec.coffee +3 -0
- data/spec/joosy/extensions/resources/rest_spec.coffee +3 -0
- data/src/joosy/core/application.coffee +1 -7
- data/src/joosy/core/helpers/view.coffee +12 -0
- data/src/joosy/core/helpers/widgets.coffee +19 -9
- data/src/joosy/core/joosy.coffee +0 -23
- data/src/joosy/core/layout.coffee +7 -5
- data/src/joosy/core/module.coffee +24 -4
- data/src/joosy/core/modules/container.coffee +29 -28
- data/src/joosy/core/modules/events.coffee +85 -72
- data/src/joosy/core/modules/filters.coffee +3 -1
- data/src/joosy/core/modules/renderer.coffee +91 -74
- data/src/joosy/core/modules/widgets_manager.coffee +12 -9
- data/src/joosy/core/page.coffee +7 -14
- data/src/joosy/core/templaters/{rails_jst.coffee → jst.coffee} +21 -19
- data/src/joosy/core/widget.coffee +3 -3
- data/src/joosy/extensions/resources/base.coffee +8 -3
- data/src/joosy/extensions/resources/rest.coffee +8 -0
- data/src/joosy/extensions/resources/rest_collection.coffee +1 -0
- data/tasks/joosy.coffee +46 -17
- data/templates/application/base/pages/welcome/index.coffee +5 -5
- data/templates/application/base/templates/layouts/application.jst.hamlc +2 -2
- data/templates/application/base/templates/pages/welcome/index.jst.hamlc +2 -2
- data/templates/application/standalone/Gruntfile.coffee +3 -1
- metadata +6 -5
- data/spec/helpers/helper.coffee +0 -68
- data/spec/joosy/core/templaters/rails_jst_spec.coffee +0 -25
data/package.json
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
"keywords": [
|
5
5
|
"joosy"
|
6
6
|
],
|
7
|
-
"version": "1.2.0-alpha.
|
7
|
+
"version": "1.2.0-alpha.41",
|
8
8
|
"author": "Boris Staal <boris@staal.io>",
|
9
9
|
"homepage": "http://joosy.ws/",
|
10
10
|
"repository": {
|
@@ -18,16 +18,16 @@
|
|
18
18
|
"node": ">=0.4.0"
|
19
19
|
},
|
20
20
|
"dependencies": {
|
21
|
+
"bower": "~1.0.0",
|
21
22
|
"sugar": "~1.3.8",
|
22
23
|
"coffee-script": "~1.6.3",
|
23
24
|
"command-router": "0.0.5",
|
24
25
|
"resolve": "~0.4.0",
|
25
26
|
"ejs": "~0.8.4",
|
26
|
-
"
|
27
|
+
"commander": "~2.0.0",
|
27
28
|
"commander": "~1.2.0",
|
28
29
|
"colors": "~0.6.0-1",
|
29
30
|
"grunt": "~0.4.1",
|
30
|
-
"bower": "~0.10.0",
|
31
31
|
"mincer": "~0.4.6",
|
32
32
|
"connect": "~2.7.11",
|
33
33
|
"haml-coffee": "~1.11.1",
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#
|
2
|
+
# DOM builders
|
3
|
+
#
|
4
|
+
beforeEach ->
|
5
|
+
@$body = $('body')
|
6
|
+
@$ground = $('<div/>').attr('id', 'ground')
|
7
|
+
|
8
|
+
@$body.append @$ground
|
9
|
+
|
10
|
+
@$ground.seed = @seedGround = =>
|
11
|
+
@$ground.html """
|
12
|
+
<div id="application" class="application">
|
13
|
+
<div id="header" class="header" />
|
14
|
+
<div id="wrapper" class="wrapper">
|
15
|
+
<div id="content" class="content">
|
16
|
+
<div id="post1" class="post" />
|
17
|
+
<div id="post2" class="post" />
|
18
|
+
<div id="post3" class="post" />
|
19
|
+
</div>
|
20
|
+
<div id="sidebar" class="sidebar">
|
21
|
+
<div id="widget1" class="widget" />
|
22
|
+
<div id="widget2" class="widget" />
|
23
|
+
</div>
|
24
|
+
</div>
|
25
|
+
<div id="footer" class="footer" />
|
26
|
+
</div>
|
27
|
+
"""
|
28
|
+
|
29
|
+
#
|
30
|
+
# DOM cleanup
|
31
|
+
#
|
32
|
+
afterEach ->
|
33
|
+
@$ground.remove()
|
@@ -0,0 +1,65 @@
|
|
1
|
+
beforeEach ->
|
2
|
+
@addMatchers
|
3
|
+
|
4
|
+
#
|
5
|
+
# Checks whether listed array of callbacks was
|
6
|
+
# called in exact order one by one
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# [ (->), (->), (->) ].toBesequenced()
|
10
|
+
#
|
11
|
+
toBeSequenced: ->
|
12
|
+
# Are we working with array?
|
13
|
+
if !Object.isArray(@actual) || @actual.length == 0
|
14
|
+
@message = -> 'Not array or empty array given'
|
15
|
+
return false
|
16
|
+
|
17
|
+
# Was every spy called just once?
|
18
|
+
for spy, i in @actual
|
19
|
+
unless spy.callCount == 1
|
20
|
+
@message = -> "Spy ##{i} was called #{spy.callCount} times instead of just one"
|
21
|
+
return false
|
22
|
+
|
23
|
+
# Were they called in a proper order?
|
24
|
+
if @actual.length > 1
|
25
|
+
for spy, i in @actual.from(1)
|
26
|
+
unless spy.calledAfter @actual[i]
|
27
|
+
@message = -> "Spy ##{i+1} wasn't called after spy ##{i}"
|
28
|
+
return false
|
29
|
+
|
30
|
+
return true
|
31
|
+
|
32
|
+
#
|
33
|
+
# Checks the exact equality of tag including attributes and content
|
34
|
+
# with the posibility to check attributes values by regexp
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
# tag = "<div class='foo' id='bar'>foo</div>"
|
38
|
+
# tag.toBeTag 'div', 'foo', class: 'foo', id: /\S+/
|
39
|
+
#
|
40
|
+
toBeTag: (tagName, content, attrs) ->
|
41
|
+
@message = =>
|
42
|
+
"Expected #{@actual} to be a tag #{tagName} with attributes #{JSON.stringify attrs} and content '#{content}'"
|
43
|
+
|
44
|
+
tag = $ @actual
|
45
|
+
|
46
|
+
# Is it alone?
|
47
|
+
flag = tag.length == 1
|
48
|
+
|
49
|
+
# Tag name matches?
|
50
|
+
flag &&= tag[0].nodeName == tagName.toUpperCase()
|
51
|
+
|
52
|
+
# Content matches?
|
53
|
+
flag &&= tag.html() == content if content != false
|
54
|
+
|
55
|
+
# Same number of attributes?
|
56
|
+
flag &&= tag[0].attributes.length == Object.keys(attrs).length
|
57
|
+
|
58
|
+
# Attributes match?
|
59
|
+
for name, val of attrs
|
60
|
+
if val.constructor == RegExp
|
61
|
+
flag &&= tag.attr(name).match(val)
|
62
|
+
else
|
63
|
+
flag &&= tag.attr(name) == val
|
64
|
+
|
65
|
+
flag
|
@@ -1,27 +1,27 @@
|
|
1
1
|
describe "Joosy.Application", ->
|
2
2
|
|
3
3
|
beforeEach ->
|
4
|
-
sinon.stub
|
5
|
-
|
4
|
+
sinon.stub Joosy.Router, "__setupRoutes"
|
5
|
+
@$ground.seed()
|
6
6
|
|
7
7
|
afterEach ->
|
8
8
|
Joosy.Router.__setupRoutes.restore()
|
9
9
|
|
10
|
-
it "
|
11
|
-
Joosy.Application.initialize 'app', '#application',
|
10
|
+
it "initializes", ->
|
11
|
+
Joosy.Application.initialize 'app', '#application', foo: {bar: 'baz'}
|
12
12
|
expect(Joosy.Application.page).toBeUndefined()
|
13
13
|
expect(Joosy.Application.selector).toEqual '#application'
|
14
14
|
expect(Joosy.Router.__setupRoutes.callCount).toEqual 1
|
15
15
|
expect(Joosy.Application.name).toEqual 'app'
|
16
|
-
expect(Joosy.Application.config.
|
17
|
-
|
18
|
-
it "should set container", ->
|
16
|
+
expect(Joosy.Application.config.foo.bar).toEqual 'baz'
|
19
17
|
expect(Joosy.Application.content()).toEqual $('#application')
|
20
18
|
|
21
|
-
it "
|
19
|
+
it "manages pages", ->
|
22
20
|
spy = sinon.spy()
|
21
|
+
|
23
22
|
class Page1
|
24
23
|
constructor: spy
|
24
|
+
|
25
25
|
class Page2
|
26
26
|
constructor: spy
|
27
27
|
|
@@ -1,10 +1,14 @@
|
|
1
1
|
describe "Joosy.Helpers.View", ->
|
2
2
|
|
3
|
+
# Shortcut
|
3
4
|
h = Joosy.Helpers.Application
|
4
5
|
|
5
|
-
it "renders tag with string
|
6
|
-
|
6
|
+
it "renders tag with string content", ->
|
7
|
+
tag = h.tag 'div', {id: 'id'}, 'content'
|
8
|
+
expect(tag).toEqual '<div id="id">content</div>'
|
7
9
|
|
8
|
-
it "renders tag with lambda
|
9
|
-
|
10
|
-
|
10
|
+
it "renders tag with lambda content", ->
|
11
|
+
tag = h.tag 'div', {id: 'id'}, ->
|
12
|
+
h.tag 'div', {id: 'id2'}, 'content'
|
13
|
+
|
14
|
+
expect(tag).toEqual '<div id="id"><div id="id2">content</div></div>'
|
@@ -1,17 +1,50 @@
|
|
1
1
|
describe "Joosy.Helpers.Widgets", ->
|
2
2
|
|
3
|
-
h = Joosy.Helpers.Application
|
4
|
-
|
5
3
|
beforeEach ->
|
6
|
-
|
4
|
+
@$ground.seed()
|
5
|
+
|
6
|
+
# Widget we are going to include using helper
|
7
|
+
class @Widget extends Joosy.Widget
|
8
|
+
@view -> "test"
|
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
|
15
|
+
|
16
|
+
@renderer = new @Renderer
|
17
|
+
@widget = new @Widget
|
18
|
+
@template = (context) => context.widget 'div', @widget
|
19
|
+
|
20
|
+
it "renders widget tag", ->
|
21
|
+
runs ->
|
22
|
+
@$ground.find('#header').html @renderer.render(@template)
|
7
23
|
|
8
|
-
|
9
|
-
|
24
|
+
expect(@$ground.find('#header').html()).toBeTag 'div', '',
|
25
|
+
id: /__joosy\d+/
|
10
26
|
|
11
27
|
it "renders widget tag", ->
|
12
|
-
|
13
|
-
|
28
|
+
runs ->
|
29
|
+
@template = (context) => context.widget 'div', {class: 'test'}, @widget
|
30
|
+
|
31
|
+
@$ground.find('#header').html @renderer.render(@template)
|
32
|
+
|
33
|
+
expect(@$ground.find('#header').html()).toBeTag 'div', '',
|
34
|
+
id: /__joosy\d+/
|
35
|
+
class: 'test'
|
36
|
+
|
37
|
+
it "bootstraps widget", ->
|
38
|
+
runs ->
|
39
|
+
@$ground.find('#header').html @renderer.render(@template)
|
40
|
+
|
41
|
+
# At the first step only the container will be injected into HTML
|
42
|
+
expect(@$ground.find('#header').html()).toBeTag 'div', '',
|
43
|
+
id: /__joosy\d+/
|
44
|
+
|
45
|
+
waits 0
|
14
46
|
|
15
|
-
|
16
|
-
|
17
|
-
|
47
|
+
runs ->
|
48
|
+
# But at the next asynchronous tick, widget will be emerged
|
49
|
+
expect(@$ground.find('#header').html()).toBeTag 'div', 'test',
|
50
|
+
id: /__joosy\d+/
|
@@ -1,41 +1,60 @@
|
|
1
1
|
describe "Joosy", ->
|
2
2
|
|
3
|
-
it "
|
3
|
+
it "initializes", ->
|
4
4
|
expect(Joosy.Application.config.debug).toBeFalsy()
|
5
5
|
expect(Joosy.Modules).toBeDefined()
|
6
6
|
expect(Joosy.Resources).toBeDefined()
|
7
7
|
|
8
|
-
it "
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
expect(
|
13
|
-
|
8
|
+
it "generates proper UUIDs", ->
|
9
|
+
uuids = []
|
10
|
+
2.times -> uuids.push Joosy.uuid()
|
11
|
+
expect(uuids.unique().length).toEqual(2)
|
12
|
+
expect(uuids[0]).toMatch /[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}/
|
13
|
+
|
14
|
+
it "generates proper UIDs", ->
|
15
|
+
uids = []
|
16
|
+
5.times -> uids.push Joosy.uid()
|
17
|
+
expect(uids.unique().length).toEqual(5)
|
18
|
+
|
19
|
+
it "builds proper URLs", ->
|
20
|
+
expect(Joosy.buildUrl 'http://www.org').toEqual('http://www.org')
|
21
|
+
expect(Joosy.buildUrl 'http://www.org#hash').toEqual('http://www.org#hash')
|
22
|
+
expect(Joosy.buildUrl 'http://www.org', {foo: 'bar'}).toEqual('http://www.org?foo=bar')
|
23
|
+
expect(Joosy.buildUrl 'http://www.org?bar=baz', {foo: 'bar'}).toEqual('http://www.org?bar=baz&foo=bar')
|
14
24
|
|
15
|
-
|
16
|
-
|
17
|
-
|
25
|
+
describe "namespacer", ->
|
26
|
+
it "declares", ->
|
27
|
+
Joosy.namespace 'Namespaces.Test1'
|
28
|
+
Joosy.namespace 'Namespaces.Test2', ->
|
29
|
+
@bingo = 'bongo'
|
18
30
|
|
19
|
-
|
20
|
-
|
31
|
+
expect(window.Namespaces.Test1).toBeDefined()
|
32
|
+
expect(window.Namespaces.Test2.bingo).toEqual('bongo')
|
21
33
|
|
22
|
-
|
23
|
-
|
34
|
+
it "imprints path", ->
|
35
|
+
Joosy.namespace 'Irish', ->
|
36
|
+
class @Pub extends Joosy.Module
|
24
37
|
|
25
|
-
|
26
|
-
|
27
|
-
expect(Keltic.Pub.__namespace__).toEqual ["Keltic"]
|
38
|
+
Joosy.namespace 'British', ->
|
39
|
+
class @Pub extends Joosy.Module
|
28
40
|
|
29
|
-
|
30
|
-
|
41
|
+
Joosy.namespace 'Keltic', ->
|
42
|
+
class @Pub extends Irish.Pub
|
31
43
|
|
32
|
-
|
44
|
+
expect(Irish.Pub.__namespace__).toEqual ["Irish"]
|
45
|
+
expect(British.Pub.__namespace__).toEqual ["British"]
|
46
|
+
expect(Keltic.Pub.__namespace__).toEqual ["Keltic"]
|
33
47
|
|
34
|
-
|
48
|
+
Joosy.namespace 'Deeply.Nested', ->
|
49
|
+
class @Klass extends Joosy.Module
|
35
50
|
|
36
|
-
|
51
|
+
expect(Deeply.Nested.Klass.__namespace__).toEqual ["Deeply", "Nested"]
|
37
52
|
|
38
|
-
|
53
|
+
class @Flat extends Joosy.Module
|
54
|
+
|
55
|
+
expect(@Flat.__namespace__).toEqual []
|
56
|
+
|
57
|
+
it "declares helpers", ->
|
39
58
|
Joosy.helpers 'Hoge', ->
|
40
59
|
@fuga = ->
|
41
60
|
"piyo"
|
@@ -43,30 +62,3 @@ describe "Joosy", ->
|
|
43
62
|
expect(window.Joosy.Helpers).toBeDefined()
|
44
63
|
expect(window.Joosy.Helpers.Hoge).toBeDefined()
|
45
64
|
expect(window.Joosy.Helpers.Hoge.fuga()).toBe "piyo"
|
46
|
-
|
47
|
-
it "should generate proper UUIDs", ->
|
48
|
-
uuids = []
|
49
|
-
2.times ->
|
50
|
-
uuids.push Joosy.uuid()
|
51
|
-
expect(uuids.unique().length).toEqual(2)
|
52
|
-
expect(uuids[0]).toMatch /[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}/
|
53
|
-
|
54
|
-
it "should build proper URLs", ->
|
55
|
-
expect(Joosy.buildUrl 'http://www.org').toEqual('http://www.org')
|
56
|
-
expect(Joosy.buildUrl 'http://www.org#hash').toEqual('http://www.org#hash')
|
57
|
-
expect(Joosy.buildUrl 'http://www.org', {foo: 'bar'}).toEqual('http://www.org?foo=bar')
|
58
|
-
expect(Joosy.buildUrl 'http://www.org?bar=baz', {foo: 'bar'}).toEqual('http://www.org?bar=baz&foo=bar')
|
59
|
-
|
60
|
-
it "should preload images", ->
|
61
|
-
path = "/spec/javascripts/support/assets/"
|
62
|
-
images = [path+"okay.jpg", path+"okay.jpg"]
|
63
|
-
|
64
|
-
callback = sinon.spy()
|
65
|
-
|
66
|
-
runs -> Joosy.preloadImages path+"coolface.jpg", callback
|
67
|
-
waits(150)
|
68
|
-
runs -> expect(callback.callCount).toEqual(1)
|
69
|
-
|
70
|
-
runs -> Joosy.preloadImages images, callback
|
71
|
-
waits(150)
|
72
|
-
runs -> expect(callback.callCount).toEqual(2)
|
@@ -1,50 +1,46 @@
|
|
1
1
|
describe "Joosy.Layout", ->
|
2
2
|
|
3
3
|
beforeEach ->
|
4
|
-
class @
|
5
|
-
@
|
4
|
+
class @Layout extends Joosy.Layout
|
5
|
+
@layout = new @Layout
|
6
6
|
|
7
|
-
it "
|
8
|
-
|
9
|
-
|
10
|
-
@
|
11
|
-
expect(@
|
7
|
+
it "has appropriate accessors", ->
|
8
|
+
callbackNames = ['beforePaint', 'paint', 'erase']
|
9
|
+
callbackNames.each (callbackName) =>
|
10
|
+
@Layout[callbackName] 'callback'
|
11
|
+
expect(@Layout::['__' + callbackName]).toEqual 'callback'
|
12
12
|
|
13
|
-
it "
|
14
|
-
@
|
15
|
-
expect(@
|
13
|
+
it "generates uid", ->
|
14
|
+
@layout.page()
|
15
|
+
expect(@layout.uid).toBeDefined()
|
16
16
|
|
17
|
-
it "
|
17
|
+
it "uses uid as selector", ->
|
18
|
+
@layout.page()
|
19
|
+
expect(@layout.content().selector).toEqual '#' + @layout.uid
|
20
|
+
|
21
|
+
it "has default view", ->
|
22
|
+
expect(@layout.__renderDefault instanceof Function).toBeTruthy()
|
23
|
+
|
24
|
+
it "integrates with Router", ->
|
18
25
|
target = sinon.stub Joosy.Router, 'navigate'
|
19
|
-
@
|
26
|
+
@layout.navigate 'there'
|
20
27
|
expect(target.callCount).toEqual 1
|
21
28
|
expect(target.alwaysCalledWithExactly 'there').toBeTruthy()
|
22
29
|
Joosy.Router.navigate.restore()
|
23
30
|
|
24
|
-
it "
|
31
|
+
it "loads", ->
|
25
32
|
spies = []
|
26
|
-
spies.push sinon.spy(@
|
27
|
-
spies.push sinon.spy(@
|
28
|
-
spies.push sinon.spy(@
|
29
|
-
spies.push sinon.spy(@
|
30
|
-
@
|
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)
|
31
38
|
expect(spies).toBeSequenced()
|
32
39
|
|
33
|
-
it "
|
40
|
+
it "unloads", ->
|
34
41
|
spies = []
|
35
|
-
spies.push sinon.spy(@
|
36
|
-
spies.push sinon.spy(@
|
37
|
-
spies.push sinon.spy(@
|
38
|
-
@
|
42
|
+
spies.push sinon.spy(@layout, '__clearTime')
|
43
|
+
spies.push sinon.spy(@layout, '__unloadWidgets')
|
44
|
+
spies.push sinon.spy(@layout, '__runAfterUnloads')
|
45
|
+
@layout.__unload()
|
39
46
|
expect(spies).toBeSequenced()
|
40
|
-
|
41
|
-
it "should generate uuid", ->
|
42
|
-
sinon.spy Joosy, 'uuid'
|
43
|
-
@box.yield()
|
44
|
-
expect(Joosy.uuid.callCount).toEqual 1
|
45
|
-
expect(@box.uuid).toBeDefined()
|
46
|
-
Joosy.uuid.restore()
|
47
|
-
|
48
|
-
it "should uuid as selector", ->
|
49
|
-
@box.yield()
|
50
|
-
expect(@box.content().selector).toEqual '#' + @box.uuid
|