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/src/joosy/core/joosy.coffee
CHANGED
@@ -91,29 +91,6 @@
|
|
91
91
|
v.toString 16
|
92
92
|
.toUpperCase()
|
93
93
|
|
94
|
-
#
|
95
|
-
# Preloads sets of images then runs callback
|
96
|
-
#
|
97
|
-
# @param [Array<String>] images Images paths
|
98
|
-
# @param [Function] callback Action to run when every picture was loaded (or triggered an error)
|
99
|
-
#
|
100
|
-
preloadImages: (images, callback) ->
|
101
|
-
unless Object.isArray(images)
|
102
|
-
images = [images]
|
103
|
-
if images.length == 0
|
104
|
-
callback()
|
105
|
-
|
106
|
-
ticks = images.length
|
107
|
-
result = []
|
108
|
-
checker = ->
|
109
|
-
if (ticks -= 1) == 0
|
110
|
-
callback?()
|
111
|
-
|
112
|
-
for p in images
|
113
|
-
result.push $('<img/>').load(checker).error(checker).attr('src', p)
|
114
|
-
|
115
|
-
result
|
116
|
-
|
117
94
|
#
|
118
95
|
# Basic URI builder. Joins base path with params hash
|
119
96
|
#
|
@@ -33,6 +33,7 @@ class Joosy.Layout extends Joosy.Module
|
|
33
33
|
@include Joosy.Modules.Filters
|
34
34
|
|
35
35
|
@view 'default'
|
36
|
+
@helper 'page'
|
36
37
|
|
37
38
|
#
|
38
39
|
# Sets the method which will controll the painting preparation proccess.
|
@@ -116,6 +117,7 @@ class Joosy.Layout extends Joosy.Module
|
|
116
117
|
# @param [Hash] params List of route params
|
117
118
|
#
|
118
119
|
constructor: (@params) ->
|
120
|
+
@uid = Joosy.uid()
|
119
121
|
|
120
122
|
#
|
121
123
|
# @see Joosy.Router.navigate
|
@@ -157,11 +159,11 @@ class Joosy.Layout extends Joosy.Module
|
|
157
159
|
@__runAfterUnloads()
|
158
160
|
|
159
161
|
#
|
160
|
-
#
|
161
|
-
# element with UUID called `yield`.
|
162
|
+
# Helpers that outputs container for the page
|
162
163
|
#
|
163
|
-
|
164
|
-
|
164
|
+
page: (tag, options={}) ->
|
165
|
+
options.id = @uid
|
166
|
+
Joosy.Helpers.Application.tag tag, options
|
165
167
|
|
166
168
|
#
|
167
169
|
# Gets layout element.
|
@@ -169,4 +171,4 @@ class Joosy.Layout extends Joosy.Module
|
|
169
171
|
# @return [jQuery]
|
170
172
|
#
|
171
173
|
content: ->
|
172
|
-
$("##{@
|
174
|
+
$("##{@uid}")
|
@@ -52,14 +52,34 @@ class @Joosy.Module
|
|
52
52
|
|
53
53
|
false
|
54
54
|
|
55
|
-
|
56
|
-
|
55
|
+
#
|
56
|
+
# Allows to override method keeping the previous implementation accessible
|
57
|
+
#
|
58
|
+
# @param [String] method Name of the method to override
|
59
|
+
# @param [String] feature Shortcut to use as previous implementation suffix
|
60
|
+
# @param [String] action Name of new method to use
|
61
|
+
# @param [Function] action New implementation
|
62
|
+
#
|
63
|
+
@aliasMethodChain: (method, feature, action) ->
|
64
|
+
camelized = feature.charAt(0).toUpperCase() + feature.slice(1)
|
65
|
+
chained = "#{method}Without#{camelized}"
|
66
|
+
|
67
|
+
action = @::[action] unless Object.isFunction(action)
|
57
68
|
|
58
69
|
@::[chained] = @::[method]
|
59
70
|
@::[method] = action
|
60
71
|
|
61
|
-
|
62
|
-
|
72
|
+
#
|
73
|
+
# Allows to override class-level method keeping the previous implementation accessible
|
74
|
+
#
|
75
|
+
# @param [String] method Name of the method to override
|
76
|
+
# @param [String] feature Shortcut to use as previous implementation suffix
|
77
|
+
# @param [String] action Name of new method to use
|
78
|
+
# @param [Function] action New implementation
|
79
|
+
#
|
80
|
+
@aliasStaticMethodChain: (method, feature, action) ->
|
81
|
+
camelized = feature.charAt(0).toUpperCase() + feature.slice(1)
|
82
|
+
chained = "#{method}Without#{camelized}"
|
63
83
|
|
64
84
|
@[chained] = @[method]
|
65
85
|
@[method] = action
|
@@ -11,41 +11,38 @@ Joosy.Modules.Container =
|
|
11
11
|
eventSplitter: /^(\S+)\s*(.*)$/
|
12
12
|
|
13
13
|
included: ->
|
14
|
+
#
|
15
|
+
# Extends elements mapping scheme
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# @mapElements
|
19
|
+
# 'name': '.selector'
|
20
|
+
# 'name2': '$name .selector'
|
21
|
+
# 'category':
|
22
|
+
# 'name3': '.selector'
|
23
|
+
#
|
14
24
|
@mapElements = (map) ->
|
15
25
|
unless @::hasOwnProperty "__elements"
|
16
26
|
@::__elements = Object.clone(@.__super__.__elements) || {}
|
17
27
|
Object.merge @::__elements, map
|
18
28
|
|
29
|
+
#
|
30
|
+
# Extends events mapping scheme
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
# @mapEvents
|
34
|
+
# 'click': ($container, event) -> #fires on container
|
35
|
+
# 'click .selector': ($element, event) -> #fires on .selector
|
36
|
+
# 'click $name': ($element, event) -> #fires on selector assigned to 'name' element
|
37
|
+
#
|
19
38
|
@mapEvents = (map) ->
|
20
39
|
unless @::hasOwnProperty "__events"
|
21
40
|
@::__events = Object.clone(@.__super__.__events) || {}
|
22
41
|
Object.merge @::__events, map
|
23
42
|
|
24
|
-
onRefresh: (callback) ->
|
25
|
-
@__onRefreshes = [] unless @hasOwnProperty "__onRefreshes"
|
26
|
-
@__onRefreshes.push callback
|
27
|
-
|
28
43
|
$: (selector) ->
|
29
44
|
$(selector, @container)
|
30
45
|
|
31
|
-
#
|
32
|
-
# Rebinds selectors defined in 'elements' hash to object properties
|
33
|
-
#
|
34
|
-
refreshElements: ->
|
35
|
-
if @hasOwnProperty "__onRefreshes"
|
36
|
-
@__onRefreshes.each (callback) => callback.apply @
|
37
|
-
@__onRefreshes = []
|
38
|
-
|
39
|
-
#
|
40
|
-
# Clears old HTML links, set the new HTML from the callback and refreshes elements
|
41
|
-
#
|
42
|
-
# @param [Function] htmlCallback `() -> String` callback that will generate new HTML
|
43
|
-
#
|
44
|
-
reloadContainer: (htmlCallback) ->
|
45
|
-
@__removeMetamorphs?()
|
46
|
-
@container.html htmlCallback()
|
47
|
-
@refreshElements()
|
48
|
-
|
49
46
|
#
|
50
47
|
# Fills container with given data removing all events
|
51
48
|
#
|
@@ -88,18 +85,22 @@ Joosy.Modules.Container =
|
|
88
85
|
|
89
86
|
return unless entries
|
90
87
|
|
91
|
-
|
88
|
+
for key,value of entries
|
92
89
|
if Object.isObject(value)
|
93
90
|
@__assignElements root['$'+key]={}, value
|
94
91
|
else
|
95
92
|
value = @__extractSelector value
|
96
|
-
|
97
|
-
root['$'+key] = (filter) =>
|
98
|
-
return @$(value) unless filter
|
99
|
-
return @$(value).filter(filter)
|
100
|
-
|
93
|
+
root['$'+key] = @__wrapElement(value)
|
101
94
|
root['$'+key].selector = value
|
102
95
|
|
96
|
+
#
|
97
|
+
# Wraps actual element closures. Required to clear context to avoid circular reference
|
98
|
+
#
|
99
|
+
__wrapElement: (value) ->
|
100
|
+
(filter) =>
|
101
|
+
return @$(value) unless filter
|
102
|
+
return @$(value).filter(filter)
|
103
|
+
|
103
104
|
#
|
104
105
|
# Binds events defined in 'events' to container
|
105
106
|
#
|
@@ -23,12 +23,17 @@ Joosy.Modules.Events =
|
|
23
23
|
events = name
|
24
24
|
name = Object.keys(@__oneShotEvents).length.toString()
|
25
25
|
|
26
|
-
|
27
|
-
@__validateEvents events
|
28
|
-
|
29
|
-
@__oneShotEvents[name] = [events, callback]
|
26
|
+
@__oneShotEvents[name] = [@__splitEvents(events), callback]
|
30
27
|
name
|
31
28
|
|
29
|
+
#
|
30
|
+
# Removes waiter action
|
31
|
+
#
|
32
|
+
# @param [Function] target Name of waiter to unbind
|
33
|
+
#
|
34
|
+
unwait: (target) ->
|
35
|
+
delete @__oneShotEvents[target]
|
36
|
+
|
32
37
|
#
|
33
38
|
# Binds action to run each time any of given event was triggered
|
34
39
|
#
|
@@ -45,26 +50,16 @@ Joosy.Modules.Events =
|
|
45
50
|
events = name
|
46
51
|
name = Object.keys(@__boundEvents).length.toString()
|
47
52
|
|
48
|
-
|
49
|
-
@__validateEvents events
|
50
|
-
|
51
|
-
@__boundEvents[name] = [events, callback]
|
53
|
+
@__boundEvents[name] = [@__splitEvents(events), callback]
|
52
54
|
name
|
53
55
|
|
54
56
|
#
|
55
57
|
# Unbinds action from runing on trigger
|
56
58
|
#
|
57
|
-
# @param [Function] target
|
59
|
+
# @param [Function] target Name of bind to unbind
|
58
60
|
#
|
59
61
|
unbind: (target) ->
|
60
|
-
|
61
|
-
|
62
|
-
for name, [events, callback] of @__boundEvents
|
63
|
-
if (Object.isFunction(target) && callback == target) || name == target
|
64
|
-
needle = name
|
65
|
-
break
|
66
|
-
|
67
|
-
delete @__boundEvents[needle] if needle?
|
62
|
+
delete @__boundEvents[target]
|
68
63
|
|
69
64
|
#
|
70
65
|
# Triggers event for {bind} and {wait}
|
@@ -73,6 +68,7 @@ Joosy.Modules.Events =
|
|
73
68
|
#
|
74
69
|
trigger: (event, data...) ->
|
75
70
|
Joosy.Modules.Log.debugAs @, "Event #{event} triggered"
|
71
|
+
|
76
72
|
if @__oneShotEvents
|
77
73
|
fire = []
|
78
74
|
for name, [events, callback] of @__oneShotEvents
|
@@ -83,6 +79,7 @@ Joosy.Modules.Events =
|
|
83
79
|
callback = @__oneShotEvents[name][1]
|
84
80
|
delete @__oneShotEvents[name]
|
85
81
|
callback data...
|
82
|
+
|
86
83
|
if @__boundEvents
|
87
84
|
for name, [events, callback] of @__boundEvents
|
88
85
|
if events.any event
|
@@ -101,75 +98,91 @@ Joosy.Modules.Events =
|
|
101
98
|
# @param [Function] block Configuration block (see example)
|
102
99
|
#
|
103
100
|
synchronize: (block) ->
|
104
|
-
context = new Joosy.Events.SynchronizationContext(
|
105
|
-
block.call(
|
101
|
+
context = new Joosy.Events.SynchronizationContext(@)
|
102
|
+
block.call(@, context)
|
106
103
|
|
107
104
|
if context.expectations.length == 0
|
108
|
-
context.after.call(
|
105
|
+
context.after.call(@)
|
109
106
|
else
|
110
|
-
@wait context.expectations, => context.after.call(
|
107
|
+
@wait context.expectations, => context.after.call(@)
|
111
108
|
context.actions.each (data) =>
|
112
|
-
data[0].call
|
109
|
+
data[0].call @, =>
|
113
110
|
@trigger data[1]
|
114
111
|
|
115
112
|
__splitEvents: (events) ->
|
116
113
|
if Object.isString events
|
117
114
|
if events.isBlank()
|
118
|
-
[]
|
115
|
+
events = []
|
119
116
|
else
|
120
|
-
events.trim().split /\s+/
|
121
|
-
else
|
122
|
-
events
|
117
|
+
events = events.trim().split /\s+/
|
123
118
|
|
124
|
-
__validateEvents: (events) ->
|
125
119
|
unless Object.isArray(events) && events.length > 0
|
126
120
|
throw new Error "#{Joosy.Module.__className @}> bind invalid events: #{events}"
|
127
121
|
|
128
|
-
|
129
|
-
Joosy.Events = {}
|
130
|
-
|
131
|
-
class Joosy.Events.Namespace
|
132
|
-
constructor: (@parent) ->
|
133
|
-
@bindings = []
|
134
|
-
|
135
|
-
bind: (args...) -> @bindings.push @parent.bind(args...)
|
136
|
-
unbind: ->
|
137
|
-
@parent.unbind b for b in @bindings
|
138
|
-
@bindings = []
|
122
|
+
events
|
139
123
|
|
140
124
|
#
|
141
|
-
#
|
125
|
+
# Additional events helpers and tools
|
142
126
|
#
|
143
|
-
|
144
|
-
#
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
#
|
153
|
-
#
|
154
|
-
#
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
#
|
170
|
-
#
|
171
|
-
#
|
172
|
-
#
|
173
|
-
#
|
174
|
-
|
175
|
-
|
127
|
+
Joosy.namespace 'Joosy.Events', ->
|
128
|
+
#
|
129
|
+
# Events namespace
|
130
|
+
#
|
131
|
+
# Creates unified collection of bindings to a particular instance
|
132
|
+
# that can be unbinded alltogether
|
133
|
+
#
|
134
|
+
# @example
|
135
|
+
# namespace = Joosy.Events.Namespace(something)
|
136
|
+
#
|
137
|
+
# namespace.bind 'event1', ->
|
138
|
+
# namespace.bind 'event2', ->
|
139
|
+
# namespace.unbind() # unbinds both bindings
|
140
|
+
#
|
141
|
+
class @Namespace
|
142
|
+
#
|
143
|
+
# @param [Object] @parent Any instance that can trigger events
|
144
|
+
#
|
145
|
+
constructor: (@parent) ->
|
146
|
+
@bindings = []
|
147
|
+
|
148
|
+
bind: (args...) -> @bindings.push @parent.bind(args...)
|
149
|
+
unbind: ->
|
150
|
+
@parent.unbind b for b in @bindings
|
151
|
+
@bindings = []
|
152
|
+
|
153
|
+
#
|
154
|
+
# Internal representation of {Joosy.Modules.Events.synchronize} context
|
155
|
+
#
|
156
|
+
# @see Joosy.Modules.Events.synchronize
|
157
|
+
#
|
158
|
+
class @SynchronizationContext
|
159
|
+
@uid = 0
|
160
|
+
|
161
|
+
constructor: (@parent) ->
|
162
|
+
@expectations = []
|
163
|
+
@actions = []
|
164
|
+
|
165
|
+
#
|
166
|
+
# Internal simple counter to separate given synchronization actions
|
167
|
+
#
|
168
|
+
uid: ->
|
169
|
+
@constructor.uid += 1
|
170
|
+
|
171
|
+
#
|
172
|
+
# Registeres another async function that should be synchronized
|
173
|
+
#
|
174
|
+
# @param [Function] action `(Function) -> null` to call.
|
175
|
+
# Should call given function to mark itself complete.
|
176
|
+
#
|
177
|
+
do: (action) ->
|
178
|
+
event = "synchro-#{@uid()}"
|
179
|
+
@expectations.push event
|
180
|
+
@actions.push [action, event]
|
181
|
+
|
182
|
+
#
|
183
|
+
# Registers finalizer: the action that will be called when all do-functions
|
184
|
+
# marked themselves as complete.
|
185
|
+
#
|
186
|
+
# @param [Function] after Function to call.
|
187
|
+
#
|
188
|
+
after: (@after) ->
|
@@ -31,7 +31,9 @@ Joosy.Modules.Filters =
|
|
31
31
|
|
32
32
|
|
33
33
|
['beforeLoad', 'afterLoad', 'afterUnload'].each (filter) =>
|
34
|
-
|
34
|
+
camelized = filter.charAt(0).toUpperCase() + filter.slice(1);
|
35
|
+
|
36
|
+
Joosy.Modules.Filters["__run#{camelized}s"] = (opts...) ->
|
35
37
|
return true unless @["__#{filter}s"]
|
36
38
|
|
37
39
|
@["__#{filter}s"].reduce (flag, func) =>
|
@@ -6,18 +6,15 @@
|
|
6
6
|
# Core DOM rendering mechanics
|
7
7
|
#
|
8
8
|
# @mixin
|
9
|
-
# @todo Describe this scary thing o_O
|
10
9
|
#
|
11
10
|
Joosy.Modules.Renderer =
|
12
11
|
|
13
12
|
#
|
14
|
-
# Default behavior for non-set
|
13
|
+
# Default behavior for non-set view (empty template?)
|
15
14
|
#
|
16
|
-
|
15
|
+
__renderDefault: ->
|
17
16
|
throw new Error "#{Joosy.Module.__className @constructor} does not have an attached template"
|
18
17
|
|
19
|
-
__helpers: null
|
20
|
-
|
21
18
|
#
|
22
19
|
# Defines class-level helpers: @view and @helpers
|
23
20
|
#
|
@@ -26,33 +23,69 @@ Joosy.Modules.Renderer =
|
|
26
23
|
#
|
27
24
|
included: ->
|
28
25
|
@view = (template, options={}) ->
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
@renderDynamic template, locals
|
35
|
-
else
|
36
|
-
@render template, locals
|
37
|
-
|
38
|
-
@helpers = (helpers...) ->
|
39
|
-
@::__helpers ||= []
|
40
|
-
helpers.map (helper) =>
|
41
|
-
module = Joosy.Helpers[helper]
|
42
|
-
unless module
|
43
|
-
throw new Error "Cannot find helper module #{helper}"
|
44
|
-
|
45
|
-
@::__helpers.push module
|
26
|
+
@::__renderDefault = (locals={}) ->
|
27
|
+
if options.dynamic
|
28
|
+
@renderDynamic template, locals
|
29
|
+
else
|
30
|
+
@render template, locals
|
46
31
|
|
32
|
+
@helper = (helpers...) ->
|
33
|
+
unless @::hasOwnProperty "__helpers"
|
34
|
+
@::__helpers = @.__super__.__helpers?.clone() || []
|
35
|
+
|
36
|
+
@::__helpers = @::__helpers.add(helpers).unique()
|
47
37
|
@::__helpers = @::__helpers.unique()
|
48
38
|
|
39
|
+
#
|
40
|
+
# Renders given template with given locals
|
41
|
+
#
|
42
|
+
# @param [String] template Name of the template to render using templater
|
43
|
+
# @param [Function] template `(locals) ->` lambda to use as template
|
44
|
+
# @param [Object] locals Locals to assign
|
45
|
+
# @param [Object] parentStackPointer Internal rendering stack pointer
|
46
|
+
#
|
47
|
+
render: (template, locals={}, parentStackPointer=false) ->
|
48
|
+
@__render false, template, locals, parentStackPointer
|
49
|
+
|
50
|
+
#
|
51
|
+
# Dynamically renders given template with given locals
|
52
|
+
#
|
53
|
+
# Whenever any of assigned locals triggers `changed` event, DOM will automatically be refreshed
|
54
|
+
#
|
55
|
+
# @param [String] template Name of the template to render using templater
|
56
|
+
# @param [Function] template `(locals) ->` lambda to use as template
|
57
|
+
# @param [Object] locals Locals to assign
|
58
|
+
# @param [Object] parentStackPointer Internal rendering stack pointer
|
59
|
+
#
|
60
|
+
renderDynamic: (template, locals={}, parentStackPointer=false) ->
|
61
|
+
@__render true, template, locals, parentStackPointer
|
62
|
+
|
63
|
+
#
|
64
|
+
# Converts all possible `@helper` arguments to the objects available for merge
|
65
|
+
#
|
66
|
+
__assignHelpers: ->
|
67
|
+
return unless @__helpers?
|
68
|
+
|
69
|
+
unless @hasOwnProperty "__helpers"
|
70
|
+
@__helpers = @__helpers.clone()
|
71
|
+
|
72
|
+
@__helpers.each (helper, i) =>
|
73
|
+
unless Object.isObject(helper)
|
74
|
+
unless @[helper]?
|
75
|
+
throw new Error "Cannot find method '#{helper}' to use as helper"
|
76
|
+
|
77
|
+
@__helpers[i] = {}
|
78
|
+
@__helpers[i][helper] = => @[helper] arguments...
|
79
|
+
|
80
|
+
#
|
81
|
+
# Collects and merges all requested helpers including global scope to one cached object
|
82
|
+
#
|
49
83
|
__instantiateHelpers: ->
|
50
84
|
unless @__helpersInstance
|
51
|
-
@
|
85
|
+
@__assignHelpers()
|
52
86
|
|
53
|
-
|
54
|
-
|
55
|
-
@onRefresh callback
|
87
|
+
@__helpersInstance = Object.extended Joosy.Helpers.Application
|
88
|
+
@__helpersInstance.__renderer = @
|
56
89
|
|
57
90
|
if @__helpers
|
58
91
|
for helper in @__helpers
|
@@ -60,102 +93,80 @@ Joosy.Modules.Renderer =
|
|
60
93
|
|
61
94
|
@__helpersInstance
|
62
95
|
|
63
|
-
#
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
new @__helpersProxyInstance locals
|
76
|
-
|
77
|
-
render: (template, locals={}, parentStackPointer=false) ->
|
78
|
-
@__render false, template, locals, parentStackPointer
|
79
|
-
|
80
|
-
renderDynamic: (template, locals={}, parentStackPointer=false) ->
|
81
|
-
@__render true, template, locals, parentStackPointer
|
96
|
+
#
|
97
|
+
# Defines local `@render*` methods with proper stack pointer set
|
98
|
+
#
|
99
|
+
# @param [Object] parentStackPointer Internal rendering stack pointer
|
100
|
+
#
|
101
|
+
__instantiateRenderers: (parentStackPointer) ->
|
102
|
+
render: (template, locals={}) =>
|
103
|
+
@render template, locals, parentStackPointer
|
104
|
+
renderDynamic: (template, locals={}) =>
|
105
|
+
@renderDynamic template, locals, parentStackPointer
|
106
|
+
renderInline: (locals={}, template) =>
|
107
|
+
@renderDynamic template, locals, parentStackPointer
|
82
108
|
|
109
|
+
#
|
110
|
+
# Actual rendering implementation
|
111
|
+
#
|
83
112
|
__render: (dynamic, template, locals={}, parentStackPointer=false) ->
|
84
113
|
stack = @__renderingStackChildFor parentStackPointer
|
85
114
|
|
86
115
|
stack.template = template
|
87
116
|
stack.locals = locals
|
88
117
|
|
89
|
-
# If template was given as a lambda, parameters should
|
90
|
-
# be passed as a context, not as a argument
|
91
|
-
assignContext = false
|
92
|
-
|
93
118
|
if Object.isString template
|
94
119
|
if @__renderSection?
|
95
120
|
template = Joosy.Application.templater.resolveTemplate @__renderSection(), template, this
|
96
|
-
|
97
121
|
template = Joosy.Application.templater.buildView template
|
98
|
-
else if Object.isFunction template
|
99
|
-
assignContext = true
|
100
122
|
else if !Object.isFunction template
|
101
123
|
throw new Error "#{Joosy.Module.__className @}> template (maybe @view) does not look like a string or lambda"
|
102
124
|
|
103
125
|
if !Object.isObject(locals) && Object.extended().constructor != locals.constructor
|
104
126
|
throw new Error "#{Joosy.Module.__className @}> locals (maybe @data?) is not a hash"
|
105
127
|
|
106
|
-
renderers =
|
107
|
-
render: (template, locals={}) =>
|
108
|
-
@render template, locals, stack
|
109
|
-
renderDynamic: (template, locals={}) =>
|
110
|
-
@renderDynamic template, locals, stack
|
111
|
-
renderInline: (locals={}, template) =>
|
112
|
-
@renderDynamic template, locals, stack
|
113
|
-
|
114
128
|
context = =>
|
115
129
|
data = {}
|
116
130
|
|
117
131
|
Joosy.Module.merge data, stack.locals
|
118
132
|
Joosy.Module.merge data, @__instantiateHelpers(), false
|
119
|
-
Joosy.Module.merge data,
|
133
|
+
Joosy.Module.merge data, @__instantiateRenderers(stack)
|
120
134
|
data
|
121
135
|
|
122
136
|
result = ->
|
123
|
-
|
124
|
-
template.call(context())
|
125
|
-
else
|
126
|
-
template(context())
|
137
|
+
template(context())
|
127
138
|
|
128
139
|
if dynamic
|
129
140
|
morph = Metamorph result()
|
130
141
|
update = =>
|
131
142
|
if morph.isRemoved()
|
132
|
-
for [object,
|
133
|
-
object.unbind
|
143
|
+
for [object, binding] in morph.__bindings
|
144
|
+
object.unbind binding
|
134
145
|
else
|
135
146
|
for child in stack.children
|
136
147
|
@__removeMetamorphs child
|
137
148
|
stack.children = []
|
138
149
|
morph.html result()
|
139
|
-
@refreshElements?()
|
140
150
|
|
141
151
|
# This is here to break stack tree and save from
|
142
|
-
# repeating DOM
|
152
|
+
# repeating DOM modification
|
143
153
|
update = update.debounce 0
|
144
154
|
|
145
|
-
morph.__bindings = []
|
146
|
-
|
147
155
|
for key, object of locals
|
148
156
|
if locals.hasOwnProperty key
|
149
157
|
if object?.bind? && object?.unbind?
|
150
|
-
binding = [object, update]
|
151
|
-
object.bind 'changed', update
|
158
|
+
binding = [object, object.bind('changed', update)]
|
152
159
|
stack.metamorphBindings.push binding
|
153
|
-
|
160
|
+
|
161
|
+
morph.__bindings = stack.metamorphBindings
|
154
162
|
|
155
163
|
morph.outerHTML()
|
156
164
|
else
|
157
165
|
result()
|
158
166
|
|
167
|
+
#
|
168
|
+
# Template for the rendering stack node
|
169
|
+
#
|
159
170
|
__renderingStackElement: (parent=null) ->
|
160
171
|
metamorphBindings: []
|
161
172
|
locals: null
|
@@ -163,6 +174,9 @@ Joosy.Modules.Renderer =
|
|
163
174
|
children: []
|
164
175
|
parent: parent
|
165
176
|
|
177
|
+
#
|
178
|
+
# Creates new rendering stack node using given pointer as the parent
|
179
|
+
#
|
166
180
|
__renderingStackChildFor: (parentPointer) ->
|
167
181
|
if !@__renderingStack
|
168
182
|
@__renderingStack = []
|
@@ -176,6 +190,9 @@ Joosy.Modules.Renderer =
|
|
176
190
|
parentPointer.children.push element
|
177
191
|
element
|
178
192
|
|
193
|
+
#
|
194
|
+
# Disables and unbinds all dynamic bindings for the whole rendering stack
|
195
|
+
#
|
179
196
|
__removeMetamorphs: (stackPointer=false) ->
|
180
197
|
remove = (stackPointer) =>
|
181
198
|
if stackPointer?.children
|