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,18 @@
|
|
1
|
+
Joosy.Modules.Page_Title =
|
2
|
+
|
3
|
+
#
|
4
|
+
# Sets the page HTML title.
|
5
|
+
#
|
6
|
+
# @note Title will be reverted on unload.
|
7
|
+
#
|
8
|
+
# @param [String] title Title to set.
|
9
|
+
#
|
10
|
+
title: (title, separator=' / ') ->
|
11
|
+
@afterLoad ->
|
12
|
+
titleStr = if Object.isFunction(title) then title.apply(@) else title
|
13
|
+
titleStr = titleStr.join(separator) if Object.isArray(titleStr)
|
14
|
+
@__previousTitle = document.title
|
15
|
+
document.title = titleStr
|
16
|
+
|
17
|
+
@afterUnload ->
|
18
|
+
document.title = @__previousTitle
|
@@ -1,6 +1,5 @@
|
|
1
|
-
#= require
|
2
|
-
#=
|
3
|
-
#= require vendor/metamorph
|
1
|
+
#= require metamorph
|
2
|
+
#= require joosy/joosy
|
4
3
|
|
5
4
|
#
|
6
5
|
# Core DOM rendering mechanics
|
@@ -8,13 +7,6 @@
|
|
8
7
|
# @mixin
|
9
8
|
#
|
10
9
|
Joosy.Modules.Renderer =
|
11
|
-
|
12
|
-
#
|
13
|
-
# Default behavior for non-set view (empty template?)
|
14
|
-
#
|
15
|
-
__renderDefault: ->
|
16
|
-
throw new Error "#{Joosy.Module.__className @constructor} does not have an attached template"
|
17
|
-
|
18
10
|
#
|
19
11
|
# Defines class-level helpers: @view and @helpers
|
20
12
|
#
|
@@ -84,9 +76,12 @@ Joosy.Modules.Renderer =
|
|
84
76
|
unless @__helpersInstance
|
85
77
|
@__assignHelpers()
|
86
78
|
|
87
|
-
@__helpersInstance =
|
79
|
+
@__helpersInstance = {}
|
88
80
|
@__helpersInstance.__renderer = @
|
89
81
|
|
82
|
+
Joosy.Module.merge @__helpersInstance, Joosy.Helpers.Application
|
83
|
+
Joosy.Module.merge @__helpersInstance, Joosy.Helpers.Routes if Joosy.Helpers.Routes?
|
84
|
+
|
90
85
|
if @__helpers
|
91
86
|
for helper in @__helpers
|
92
87
|
Joosy.Module.merge @__helpersInstance, helper
|
@@ -117,8 +112,8 @@ Joosy.Modules.Renderer =
|
|
117
112
|
|
118
113
|
if Object.isString template
|
119
114
|
if @__renderSection?
|
120
|
-
template = Joosy.
|
121
|
-
template = Joosy.
|
115
|
+
template = Joosy.templater().resolveTemplate @__renderSection(), template, this
|
116
|
+
template = Joosy.templater().buildView template
|
122
117
|
else if !Object.isFunction template
|
123
118
|
throw new Error "#{Joosy.Module.__className @}> template (maybe @view) does not look like a string or lambda"
|
124
119
|
|
@@ -209,3 +204,7 @@ Joosy.Modules.Renderer =
|
|
209
204
|
remove stackPointer
|
210
205
|
else
|
211
206
|
remove stackPointer
|
207
|
+
|
208
|
+
# AMD wrapper
|
209
|
+
if define?.amd?
|
210
|
+
define 'joosy/modules/renderer', -> Joosy.Modules.Renderer
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#= require joosy/
|
1
|
+
#= require joosy/joosy
|
2
2
|
|
3
3
|
#
|
4
4
|
# Comfortable and clever wrappers for timeouts management
|
@@ -46,3 +46,7 @@ Joosy.Modules.TimeManager =
|
|
46
46
|
if @__timeouts
|
47
47
|
for entry in @__timeouts
|
48
48
|
window.clearTimeout entry
|
49
|
+
|
50
|
+
# AMD wrapper
|
51
|
+
if define?.amd?
|
52
|
+
define 'joosy/modules/time_manager', -> Joosy.Modules.TimeManager
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#= require joosy/
|
1
|
+
#= require joosy/joosy
|
2
2
|
|
3
3
|
#
|
4
4
|
# Widgets management routines
|
@@ -51,10 +51,10 @@ Joosy.Modules.WidgetsManager =
|
|
51
51
|
|
52
52
|
Object.each @__widgets, (selector, widget) =>
|
53
53
|
if selector == '$container'
|
54
|
-
activeSelector =
|
54
|
+
activeSelector = @$container
|
55
55
|
else
|
56
56
|
selector = @__extractSelector(selector) if @__extractSelector?
|
57
|
-
activeSelector = $(selector,
|
57
|
+
activeSelector = $(selector, @$container)
|
58
58
|
|
59
59
|
registered[selector] = Object.extended()
|
60
60
|
|
@@ -64,7 +64,7 @@ Joosy.Modules.WidgetsManager =
|
|
64
64
|
else
|
65
65
|
instance = widget.call this, index
|
66
66
|
|
67
|
-
if Joosy.
|
67
|
+
if Joosy.debug()
|
68
68
|
registered[selector][Joosy.Module.__className instance] ||= 0
|
69
69
|
registered[selector][Joosy.Module.__className instance] += 1
|
70
70
|
|
@@ -72,7 +72,7 @@ Joosy.Modules.WidgetsManager =
|
|
72
72
|
|
73
73
|
@__widgets = {}
|
74
74
|
|
75
|
-
if Joosy.
|
75
|
+
if Joosy.debug()
|
76
76
|
registered.each (selector, value) =>
|
77
77
|
value.each (widget, count) =>
|
78
78
|
Joosy.Modules.Log.debugAs @, "Widget #{widget} registered at '#{selector}'. Elements: #{count}"
|
@@ -84,3 +84,7 @@ Joosy.Modules.WidgetsManager =
|
|
84
84
|
if @__activeWidgets
|
85
85
|
for widget in @__activeWidgets
|
86
86
|
widget.__unload()
|
87
|
+
|
88
|
+
# AMD wrapper
|
89
|
+
if define?.amd?
|
90
|
+
define 'joosy/modules/widgets_manager', -> Joosy.Modules.WidgetsManager
|
@@ -0,0 +1,68 @@
|
|
1
|
+
#= require joosy/joosy
|
2
|
+
#= require joosy/widget
|
3
|
+
#= require joosy/layout
|
4
|
+
#= require joosy/modules/page/scrolling
|
5
|
+
#= require joosy/modules/page/title
|
6
|
+
|
7
|
+
#
|
8
|
+
# Base class for Joosy Pages.
|
9
|
+
#
|
10
|
+
# @example Sample application page
|
11
|
+
# class @RumbaPage extends Joosy.Page
|
12
|
+
# @view 'rumba'
|
13
|
+
#
|
14
|
+
# @include Joosy.Modules.Page_Scrolling
|
15
|
+
# @extend Joosy.Modules.Page_Title
|
16
|
+
#
|
17
|
+
class Joosy.Page extends Joosy.Widget
|
18
|
+
#
|
19
|
+
# Sets layout for current page
|
20
|
+
#
|
21
|
+
# @param [Class] layoutClass Layout to use
|
22
|
+
#
|
23
|
+
@layout: (layoutClass) ->
|
24
|
+
@::__layoutClass = layoutClass
|
25
|
+
|
26
|
+
@include Joosy.Modules.Page_Scrolling
|
27
|
+
@extend Joosy.Modules.Page_Title
|
28
|
+
|
29
|
+
#
|
30
|
+
# @params [Hash] params Route params
|
31
|
+
# @params [Joosy.Page] previous Previous page to unload
|
32
|
+
#
|
33
|
+
constructor: (@params, @previous) ->
|
34
|
+
@layoutShouldChange = @previous?.__layoutClass != @__layoutClass
|
35
|
+
|
36
|
+
@halted = !@__runBeforeLoads()
|
37
|
+
@layout = switch
|
38
|
+
when @layoutShouldChange && @__layoutClass
|
39
|
+
new @__layoutClass(params, @previous?.layout)
|
40
|
+
when !@layoutShouldChange
|
41
|
+
@previous?.layout
|
42
|
+
|
43
|
+
# If the page has no layout defined while the previous had one
|
44
|
+
# we should declare ourselves as a relpacement to the layout, not the page
|
45
|
+
@previous = @previous.layout if @layoutShouldChange && !@layout
|
46
|
+
|
47
|
+
######
|
48
|
+
###### Widget extensions
|
49
|
+
######
|
50
|
+
|
51
|
+
#
|
52
|
+
# This is required by {Joosy.Modules.Renderer}
|
53
|
+
# Sets the base template dir to app_name/templates/pages
|
54
|
+
#
|
55
|
+
__renderSection: ->
|
56
|
+
'pages'
|
57
|
+
|
58
|
+
#
|
59
|
+
# Unlike widget that injects straightforwardly into given container
|
60
|
+
# page injects itself into the content of Layout and uses given container
|
61
|
+
# as a fallback for cases when no Layout has been set
|
62
|
+
#
|
63
|
+
__bootstrapDefault: (applicationContainer) ->
|
64
|
+
@__bootstrap @__nestingMap(), @layout?.content() || applicationContainer
|
65
|
+
|
66
|
+
# AMD wrapper
|
67
|
+
if define?.amd?
|
68
|
+
define 'joosy/page', -> Joosy.Page
|
@@ -0,0 +1,305 @@
|
|
1
|
+
#= require joosy/joosy
|
2
|
+
#= require joosy/modules/events
|
3
|
+
#= require joosy/page
|
4
|
+
#= require joosy/helpers/routes
|
5
|
+
|
6
|
+
#
|
7
|
+
# Router. Reacts on URI change event and loads proper pages
|
8
|
+
#
|
9
|
+
# Internal storage rules:
|
10
|
+
# * HTML5 Prefix option is stored with both leading and trailing slashes
|
11
|
+
# * Helpers pathes are stored without leading trailing slash
|
12
|
+
# * Route matchers declare leading and trailing slashes as optional
|
13
|
+
#
|
14
|
+
# Example:
|
15
|
+
# Joosy.Router.map
|
16
|
+
# 404 : (path) -> alert "Page '#{path}' was not found :("
|
17
|
+
# '/' : Welcome.IndexPage
|
18
|
+
# '/resources' :
|
19
|
+
# '/' : Resource.IndexPage
|
20
|
+
# '/:id' : Resource.ShowPage
|
21
|
+
# '/:id/edit' : Resource.EditPage
|
22
|
+
# '/new' : Resource.EditPage
|
23
|
+
#
|
24
|
+
# @mixin
|
25
|
+
#
|
26
|
+
class Joosy.Router extends Joosy.Module
|
27
|
+
@extend Joosy.Modules.Events
|
28
|
+
|
29
|
+
# We need to be constantly subscribed to popstate event to filter
|
30
|
+
# the first event that always happens on the initial load
|
31
|
+
$(window).bind 'popstate', (event) =>
|
32
|
+
if window.history.loaded?
|
33
|
+
@trigger 'popstate', event
|
34
|
+
else
|
35
|
+
window.history.loaded = true
|
36
|
+
|
37
|
+
$(document).on 'click', 'a[data-joosy]', (event) =>
|
38
|
+
@navigate event.target.getAttribute('href')
|
39
|
+
false
|
40
|
+
|
41
|
+
#
|
42
|
+
# Rails-like wrapper around internal raw routes representation
|
43
|
+
#
|
44
|
+
class Drawer
|
45
|
+
@run: (block, namespace='', alias='') ->
|
46
|
+
context = new Drawer namespace, alias
|
47
|
+
block.call(context)
|
48
|
+
|
49
|
+
constructor: (@__namespace, @__alias) ->
|
50
|
+
|
51
|
+
#
|
52
|
+
# Match route (ads it to @rawRoutes)
|
53
|
+
#
|
54
|
+
# @param [String] route similar to ones sent in map hash
|
55
|
+
#
|
56
|
+
# @param options [String] to function to which the route routes
|
57
|
+
# @option options [String] as name of the route, used for reverse routing
|
58
|
+
#
|
59
|
+
match: (route, options={}) ->
|
60
|
+
if options.as?
|
61
|
+
if @__alias
|
62
|
+
as = @__alias + options.as.charAt(0).toUpperCase() + options.as.slice(1)
|
63
|
+
else
|
64
|
+
as = options.as
|
65
|
+
|
66
|
+
route = @__namespace + route
|
67
|
+
|
68
|
+
Joosy.Router.compileRoute route, options.to, as
|
69
|
+
|
70
|
+
#
|
71
|
+
# Shortcut to match "/"
|
72
|
+
#
|
73
|
+
# @param options [String] to function to which the route routes
|
74
|
+
# @option options [String] as name of the route, used for reverse routing
|
75
|
+
# default it is "root"
|
76
|
+
#
|
77
|
+
root: (options={}) ->
|
78
|
+
@match "/", to: options.to, as: options.as || 'root'
|
79
|
+
|
80
|
+
#
|
81
|
+
# Routes the 404
|
82
|
+
#
|
83
|
+
# @param options [String] to function to which the route routes
|
84
|
+
#
|
85
|
+
notFound: (options={}) ->
|
86
|
+
@match 404, to: options.to
|
87
|
+
|
88
|
+
#
|
89
|
+
# Namespaces a match route
|
90
|
+
#
|
91
|
+
# @param [String] name name of the namespace, prefixes other commands
|
92
|
+
#
|
93
|
+
# @option [Hash] options "as", prefixes all other "as" commands
|
94
|
+
# @param [Function] block callback for child commands
|
95
|
+
namespace: (name, options={}, block) ->
|
96
|
+
if Object.isFunction(options)
|
97
|
+
block = options
|
98
|
+
options = {}
|
99
|
+
|
100
|
+
Drawer.run block, @__namespace+name, options.as?.toString()
|
101
|
+
|
102
|
+
#
|
103
|
+
# Registers a set of raw routes
|
104
|
+
# The method saves hash of routes for further activation
|
105
|
+
#
|
106
|
+
# @param [Object] routes Set of routes in inner format (see class description)
|
107
|
+
#
|
108
|
+
@map: (routes, namespace) ->
|
109
|
+
Object.each routes, (path, to) =>
|
110
|
+
path = namespace + '/' + path if namespace?
|
111
|
+
if Object.isFunction(to) || to.prototype
|
112
|
+
@compileRoute path, to
|
113
|
+
else
|
114
|
+
@map to, path
|
115
|
+
|
116
|
+
#
|
117
|
+
# Draws the routes similar to Ruby on Rails
|
118
|
+
#
|
119
|
+
# @param [Function] block callback for child commands
|
120
|
+
#
|
121
|
+
@draw: (block)->
|
122
|
+
Drawer.run block
|
123
|
+
|
124
|
+
#
|
125
|
+
# Inits the routing system and loads the current route
|
126
|
+
#
|
127
|
+
@setup: (@config, @responder, respond=true) ->
|
128
|
+
@config.html5 = false unless history.pushState
|
129
|
+
@config.prefix ||= ''
|
130
|
+
@config.prefix = ('/'+@config.prefix+'/').replace(/\/{2,}/g, '/') if @config.html5
|
131
|
+
|
132
|
+
@respond @canonizeLocation() if respond
|
133
|
+
|
134
|
+
if @config.html5
|
135
|
+
@listener = @bind 'popstate pushstate', =>
|
136
|
+
@respond @canonizeLocation()
|
137
|
+
|
138
|
+
else
|
139
|
+
$(window).bind 'hashchange.JoosyRouter', =>
|
140
|
+
@respond @canonizeLocation()
|
141
|
+
|
142
|
+
#
|
143
|
+
# Clears current map of routes and deactivates bindings
|
144
|
+
#
|
145
|
+
@reset: ->
|
146
|
+
@unbind @listener
|
147
|
+
$(window).unbind '.JoosyRouter'
|
148
|
+
@restriction = false
|
149
|
+
@routes = {}
|
150
|
+
|
151
|
+
#
|
152
|
+
# Sets the restriction pattern.
|
153
|
+
# Makes Router ignore URI modification if it matches given regexp.
|
154
|
+
# Set `false` to make router react on all modifications.
|
155
|
+
#
|
156
|
+
# @param [Regexp] restriction
|
157
|
+
#
|
158
|
+
@restrict: (@restriction) ->
|
159
|
+
|
160
|
+
#
|
161
|
+
# Changes current URI and therefore triggers route loading
|
162
|
+
#
|
163
|
+
# @param [String] to Route to navigate to
|
164
|
+
#
|
165
|
+
# @option options [Boolean] respond If false just changes route without responding
|
166
|
+
# @option options [Boolean] replaceState If true replaces history entry instead of adding. Works only in browsers supporting history.pushState
|
167
|
+
#
|
168
|
+
@navigate: (to, options={}) ->
|
169
|
+
path = to
|
170
|
+
|
171
|
+
if @config.html5
|
172
|
+
path = path.substr(1) if path[0] == '/'
|
173
|
+
path = @config.prefix+path
|
174
|
+
else
|
175
|
+
path = path.substr(1) if path[0] == '#'
|
176
|
+
|
177
|
+
if @config.prefix && !path.startsWith(@config.prefix)
|
178
|
+
path = @config.prefix + path
|
179
|
+
|
180
|
+
if @config.html5
|
181
|
+
history.pushState {}, '', path
|
182
|
+
@trigger 'pushstate'
|
183
|
+
else
|
184
|
+
location.hash = path
|
185
|
+
return
|
186
|
+
|
187
|
+
#
|
188
|
+
# Gets current route out of the window location
|
189
|
+
#
|
190
|
+
# @note canonized location always starts with leading /
|
191
|
+
#
|
192
|
+
@canonizeLocation: ->
|
193
|
+
if @config.html5
|
194
|
+
location.pathname.replace(///^#{RegExp.escape @config.prefix}?///, '/')+location.search
|
195
|
+
else
|
196
|
+
location.hash.replace ///^\#(#{@config.prefix})?\/?///, '/'
|
197
|
+
|
198
|
+
#
|
199
|
+
# Compiles one single route
|
200
|
+
#
|
201
|
+
# @param [String] path Full path from raw route
|
202
|
+
# @param [Class] response Class that should be instantiated at this route
|
203
|
+
# @param [Function] response Lambda to call at this route
|
204
|
+
#
|
205
|
+
@compileRoute: (path, to, as) ->
|
206
|
+
if path.toString() == '404'
|
207
|
+
@wildcardAction = to
|
208
|
+
return
|
209
|
+
|
210
|
+
path = path.substr(1) if path[0] == '/'
|
211
|
+
|
212
|
+
matcher = path.replace /\/{2,}/g, '/'
|
213
|
+
result = {}
|
214
|
+
|
215
|
+
# Full RegExp matcher for the route
|
216
|
+
matcher = matcher.replace(/\/:([^\/]+)/g, '/([^/]+)') # Turning :params into regexp section
|
217
|
+
matcher = matcher.replace(/^\/?/, '^/?') # Making leading slash optional
|
218
|
+
matcher = matcher.replace(/\/?$/, '/?$') # Making trailing slash optional
|
219
|
+
|
220
|
+
# Array of parameter names
|
221
|
+
params = (path.match(/\/:[^\/]+/g) || []).map (str) ->
|
222
|
+
str.substr 2
|
223
|
+
|
224
|
+
@routes ||= {}
|
225
|
+
@routes[matcher] =
|
226
|
+
to: to,
|
227
|
+
capture: params
|
228
|
+
as: as
|
229
|
+
|
230
|
+
@defineHelpers path, as if as?
|
231
|
+
|
232
|
+
#
|
233
|
+
# Searches given route at compiled routes and reacts
|
234
|
+
#
|
235
|
+
# @param [String] hash Hash value to search route for
|
236
|
+
#
|
237
|
+
@respond: (path) ->
|
238
|
+
Joosy.Modules.Log.debug "Router> Answering '#{path}'"
|
239
|
+
|
240
|
+
if (@restriction && path.match(@restriction) == null)
|
241
|
+
@trigger 'restricted', path
|
242
|
+
return
|
243
|
+
|
244
|
+
[path, query] = path.split '?'
|
245
|
+
query = query?.split?('&') || []
|
246
|
+
|
247
|
+
for regex, route of @routes when @routes.hasOwnProperty regex
|
248
|
+
if match = path.match new RegExp(regex)
|
249
|
+
@responder route.to, @__grabParams(query, route, match)
|
250
|
+
@trigger 'responded', path
|
251
|
+
return
|
252
|
+
|
253
|
+
if @wildcardAction?
|
254
|
+
@responder @wildcardAction, path
|
255
|
+
@trigger 'responded'
|
256
|
+
else
|
257
|
+
@trigger 'missed'
|
258
|
+
|
259
|
+
#
|
260
|
+
# Registers Rails-like route helpers (`fooPath()`, `fooUrl()`)
|
261
|
+
#
|
262
|
+
# @param [String] path String route representation to wrap into helper
|
263
|
+
# @param [String] as Helpers base name
|
264
|
+
#
|
265
|
+
@defineHelpers: (path, as) ->
|
266
|
+
helper = (options) ->
|
267
|
+
result = path
|
268
|
+
|
269
|
+
path.match(/\/:[^\/]+/g)?.each? (param) ->
|
270
|
+
result = result.replace(param.substr(1), options[param.substr(2)])
|
271
|
+
|
272
|
+
if Joosy.Router.config.html5
|
273
|
+
"#{Joosy.Router.config.prefix}#{result}"
|
274
|
+
else
|
275
|
+
"##{Joosy.Router.config.prefix}#{result}"
|
276
|
+
|
277
|
+
Joosy.helpers 'Routes', ->
|
278
|
+
@["#{as}Path"] = helper
|
279
|
+
|
280
|
+
@["#{as}Url"] = (options) ->
|
281
|
+
if Joosy.Router.config.html5
|
282
|
+
"#{location.origin}#{helper(options)}"
|
283
|
+
else
|
284
|
+
"#{location.origin}#{location.pathname}#{helper(options)}"
|
285
|
+
|
286
|
+
@__grabParams: (query, route=null, match=[]) ->
|
287
|
+
params = {}
|
288
|
+
|
289
|
+
# Collect parameters from route placeholers
|
290
|
+
match.shift() # First entry is full route regexp match that should be just skipped
|
291
|
+
|
292
|
+
route?.capture?.each (key) ->
|
293
|
+
params[key] = decodeURIComponent match.shift()
|
294
|
+
|
295
|
+
# Collect parameters from URL query section
|
296
|
+
query.each (entry) ->
|
297
|
+
unless entry.isBlank()
|
298
|
+
[key, value] = entry.split '='
|
299
|
+
params[key] = value
|
300
|
+
|
301
|
+
params
|
302
|
+
|
303
|
+
# AMD wrapper
|
304
|
+
if define?.amd?
|
305
|
+
define 'joosy/router', -> Joosy.Router
|
@@ -1,12 +1,11 @@
|
|
1
|
-
#= require joosy/
|
1
|
+
#= require joosy/joosy
|
2
2
|
|
3
3
|
#
|
4
4
|
# JST template precompilation binding
|
5
5
|
#
|
6
6
|
class Joosy.Templaters.JST
|
7
|
-
constructor: (
|
8
|
-
if
|
9
|
-
@applicationName = applicationName
|
7
|
+
constructor: (@config={}) ->
|
8
|
+
@prefix = @config.prefix if @config.prefix? && @config.prefix.length > 0
|
10
9
|
|
11
10
|
#
|
12
11
|
# Gets template lambda by its full name
|
@@ -16,10 +15,10 @@ class Joosy.Templaters.JST
|
|
16
15
|
buildView: (name) ->
|
17
16
|
template = false
|
18
17
|
|
19
|
-
if @
|
18
|
+
if @prefix
|
20
19
|
haystack = [
|
21
|
-
"#{@
|
22
|
-
"#{@
|
20
|
+
"#{@prefix}/templates/#{name}-#{I18n?.locale}",
|
21
|
+
"#{@prefix}/templates/#{name}"
|
23
22
|
]
|
24
23
|
else
|
25
24
|
haystack = [
|
@@ -47,3 +46,7 @@ class Joosy.Templaters.JST
|
|
47
46
|
path.unshift section
|
48
47
|
|
49
48
|
"#{path.join '/'}/#{template}"
|
49
|
+
|
50
|
+
# AMD wrapper
|
51
|
+
if define?.amd?
|
52
|
+
define 'joosy/templaters/jst', -> Joosy.Templaters.JST
|