joosy 1.2.0.alpha.73 → 1.2.0.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gruntfile.coffee +56 -18
- data/bower.json +1 -1
- data/build/joosy/form.js +1 -0
- data/build/joosy/resources.js +1 -0
- data/build/joosy.js +2 -2774
- data/package.json +5 -4
- data/source/joosy/application.coffee +9 -7
- data/source/joosy/{extensions/resources-form/form.coffee → form.coffee} +58 -51
- data/source/joosy/helpers/form.coffee +241 -0
- data/source/joosy/helpers/index.coffee +3 -0
- data/source/joosy/helpers/routes.coffee +3 -1
- data/source/joosy/helpers/view.coffee +9 -9
- data/source/joosy/joosy.coffee +3 -5
- data/source/joosy/module.coffee +9 -4
- data/source/joosy/modules/dom.coffee +33 -31
- data/source/joosy/modules/events.coffee +24 -20
- data/source/joosy/modules/filters.coffee +38 -35
- data/source/joosy/modules/page/title.coffee +3 -3
- data/source/joosy/modules/renderer.coffee +23 -18
- data/source/joosy/modules/resources/identity_map.coffee +45 -0
- data/source/joosy/modules/resources/model.coffee +146 -0
- data/source/joosy/modules/widgets_manager.coffee +8 -8
- data/source/joosy/resources/array.coffee +0 -5
- data/source/joosy/resources/hash.coffee +8 -13
- data/source/joosy/resources/index.coffee +2 -0
- data/source/joosy/{extensions/resources → resources}/rest.coffee +48 -19
- data/source/joosy/resources/scalar.coffee +8 -10
- data/source/joosy/router.coffee +13 -12
- data/source/joosy/templaters/jst.coffee +3 -2
- data/source/joosy/widget.coffee +17 -15
- data/source/joosy.coffee +2 -0
- data/source/vendor/es5-shim.js +1316 -0
- data/source/vendor/inflections.js +598 -0
- data/source/vendor/metamorph.js +457 -0
- data/spec/helpers/matchers.coffee +4 -4
- data/spec/joosy/core/application_spec.coffee +1 -1
- data/spec/joosy/core/helpers/view_spec.coffee +2 -2
- data/spec/joosy/core/joosy_spec.coffee +8 -4
- data/spec/joosy/core/modules/dom_spec.coffee +7 -7
- data/spec/joosy/core/modules/events_spec.coffee +2 -2
- data/spec/joosy/core/modules/filters_spec.coffee +7 -8
- data/spec/joosy/core/modules/module_spec.coffee +5 -5
- data/spec/joosy/core/router_spec.coffee +3 -3
- data/spec/joosy/core/widget_spec.coffee +6 -6
- data/spec/joosy/environments/amd_spec.coffee +4 -2
- data/spec/joosy/environments/global_spec.coffee +1 -1
- data/spec/joosy/{extensions/form → form}/form_spec.coffee +9 -16
- data/spec/joosy/{extensions/form → form}/helpers/forms_spec.coffee +5 -5
- data/spec/joosy/{core/resources → resources}/array_spec.coffee +2 -2
- data/spec/joosy/{core/resources → resources}/hash_spec.coffee +0 -8
- data/spec/joosy/{core/modules/resources → resources/modules}/cacher_spec.coffee +0 -0
- data/spec/joosy/resources/modules/identity_map_spec.coffee +47 -0
- data/spec/joosy/{extensions/resources/base_spec.coffee → resources/modules/model_spec.coffee} +28 -48
- data/spec/joosy/{extensions/resources → resources}/rest_spec.coffee +29 -22
- data/spec/joosy/{core/resources → resources}/scalar_spec.coffee +8 -8
- data/templates/application/application.coffee.tt +0 -2
- data/templates/environment/app/haml/index.haml +2 -2
- data/templates/environment/package.json +1 -1
- metadata +23 -19
- data/build/joosy/extensions/resources-form.js +0 -590
- data/build/joosy/extensions/resources.js +0 -561
- data/source/joosy/extensions/resources/base.coffee +0 -282
- data/source/joosy/extensions/resources/index.coffee +0 -1
- data/source/joosy/extensions/resources-form/helpers/form.coffee +0 -104
- data/source/joosy/extensions/resources-form/index.coffee +0 -1
- data/source/metamorph.coffee +0 -410
@@ -1,282 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Basic data wrapper with triggering and entity name binding
|
3
|
-
#
|
4
|
-
# @example Basic usage
|
5
|
-
# class R extends Joosy.Resources.Base
|
6
|
-
# @entity 'r'
|
7
|
-
#
|
8
|
-
# @beforeLoad (data) ->
|
9
|
-
# data.real = true
|
10
|
-
#
|
11
|
-
# r = R.build {r: {foo: {bar: 'baz'}}}
|
12
|
-
#
|
13
|
-
# r('foo') # {baz: 'baz'}
|
14
|
-
# r('real') # true
|
15
|
-
# r('foo.bar') # baz
|
16
|
-
# r('foo.bar', 'fluffy') # triggers 'changed'
|
17
|
-
#
|
18
|
-
# @include Joosy.Modules.Log
|
19
|
-
# @include Joosy.Modules.Events
|
20
|
-
# @include Joosy.Modules.Filters
|
21
|
-
#
|
22
|
-
# @method .beforeLoad(callback)
|
23
|
-
# Allows to modify data before it gets stored.
|
24
|
-
# You can define several beforeLoad filters that will be chained.
|
25
|
-
# @param [Function] action `(Object) -> Object` to call
|
26
|
-
#
|
27
|
-
#
|
28
|
-
class Joosy.Resources.Base extends Joosy.Function
|
29
|
-
@include Joosy.Modules.Log
|
30
|
-
@include Joosy.Modules.Events
|
31
|
-
@include Joosy.Modules.Filters
|
32
|
-
|
33
|
-
#
|
34
|
-
# Default primary key field 'id'
|
35
|
-
#
|
36
|
-
__primaryKey: 'id'
|
37
|
-
|
38
|
-
#
|
39
|
-
# Clears the identity map cache. Recomended to be called during layout switch to
|
40
|
-
# ensure correct garbage collection.
|
41
|
-
#
|
42
|
-
@resetIdentity: ->
|
43
|
-
Joosy.Resources.Base.identity = {}
|
44
|
-
|
45
|
-
@registerPlainFilters 'beforeLoad'
|
46
|
-
|
47
|
-
#
|
48
|
-
# Sets the field containing primary key.
|
49
|
-
#
|
50
|
-
# @note It has no direct use inside the REST resource itself and can be omited.
|
51
|
-
# But it usually should not since we have plans on adding some kind of Identity Map to Joosy.
|
52
|
-
#
|
53
|
-
# @param [String] primary Name of the field
|
54
|
-
#
|
55
|
-
@primaryKey: (primaryKey) ->
|
56
|
-
@::__primaryKey = primaryKey
|
57
|
-
|
58
|
-
#
|
59
|
-
# Sets the entity text name:
|
60
|
-
# required to do some magic like skipping the root node.
|
61
|
-
#
|
62
|
-
# @param [String] name Singular name of resource
|
63
|
-
#
|
64
|
-
@entity: (name) ->
|
65
|
-
@::__entityName = name
|
66
|
-
|
67
|
-
#
|
68
|
-
# Dynamically creates collection of inline resources.
|
69
|
-
#
|
70
|
-
# Inline resources share the instance with direct data and therefore can be used
|
71
|
-
# to handle inline changes with triggers and all that resources stuff
|
72
|
-
#
|
73
|
-
# @example Basic usage
|
74
|
-
# class Zombie extends Joosy.Resources.Base
|
75
|
-
# @entity 'zombie'
|
76
|
-
# class Puppy extends Joosy.Resources.Base
|
77
|
-
# @entity 'puppy'
|
78
|
-
# @map 'zombies'
|
79
|
-
#
|
80
|
-
# p = Puppy.build {zombies: [{foo: 'bar'}]}
|
81
|
-
#
|
82
|
-
# p('zombies') # Direct access: [{foo: 'bar'}]
|
83
|
-
# p.zombies # Wrapped Collection of Zombie instances
|
84
|
-
# p.zombies.at(0)('foo') # bar
|
85
|
-
#
|
86
|
-
# @param [String] name Pluralized name of property to define
|
87
|
-
# @param [Class] klass Resource class to instantiate
|
88
|
-
#
|
89
|
-
@map: (name, klass=false) ->
|
90
|
-
unless klass
|
91
|
-
klass = window[name.singularize().camelize()]
|
92
|
-
|
93
|
-
if !klass
|
94
|
-
throw new Error "#{Joosy.Module.__className @}> class can not be detected for '#{name}' mapping"
|
95
|
-
|
96
|
-
@beforeLoad (data) ->
|
97
|
-
klass = klass() unless Joosy.Module.hasAncestor(klass, Joosy.Resources.Base)
|
98
|
-
|
99
|
-
@__map(data, name, klass)
|
100
|
-
|
101
|
-
#
|
102
|
-
# Wraps instance of resource inside shim-function allowing to track
|
103
|
-
# data changes. See class example
|
104
|
-
#
|
105
|
-
# @return [Joosy.Resources.Base]
|
106
|
-
#
|
107
|
-
@build: (data={}) ->
|
108
|
-
if Object.isNumber(data) || Object.isString(data)
|
109
|
-
id = data
|
110
|
-
data = {}
|
111
|
-
data[@::__primaryKey] = id
|
112
|
-
|
113
|
-
klass = @::__entityName
|
114
|
-
id = data[@::__primaryKey]
|
115
|
-
|
116
|
-
if klass? && id?
|
117
|
-
Joosy.Resources.Base.identity ?= {}
|
118
|
-
Joosy.Resources.Base.identity[klass] ?= {}
|
119
|
-
Joosy.Resources.Base.identity[klass][id] ?= new @ id: id
|
120
|
-
|
121
|
-
Joosy.Resources.Base.identity[klass][id].load data
|
122
|
-
else
|
123
|
-
new @ data
|
124
|
-
|
125
|
-
#
|
126
|
-
# Creates new instance of Resource using values from form
|
127
|
-
#
|
128
|
-
# @param [DOMElement] form Form to grab
|
129
|
-
#
|
130
|
-
@grab: (form) ->
|
131
|
-
@build({}).grab form
|
132
|
-
|
133
|
-
#
|
134
|
-
# Should NOT be called directly, use {::build} instead
|
135
|
-
#
|
136
|
-
# @private
|
137
|
-
# @param [Object] data Data to store
|
138
|
-
#
|
139
|
-
constructor: (data={}) ->
|
140
|
-
return super ->
|
141
|
-
@__fillData data, false
|
142
|
-
|
143
|
-
id: ->
|
144
|
-
@data?[@__primaryKey]
|
145
|
-
|
146
|
-
knownAttributes: ->
|
147
|
-
Object.keys @data
|
148
|
-
|
149
|
-
#
|
150
|
-
# Set the resource data manually
|
151
|
-
#
|
152
|
-
# @param [Object] data Data to store
|
153
|
-
#
|
154
|
-
# @return [Joosy.Resources.Base] Returns self
|
155
|
-
#
|
156
|
-
load: (data, clear=false) ->
|
157
|
-
@data = {} if clear
|
158
|
-
@__fillData data
|
159
|
-
return @
|
160
|
-
|
161
|
-
#
|
162
|
-
# Updates the Resource with a data from given form
|
163
|
-
#
|
164
|
-
# @param [DOMElement] form Form to grab
|
165
|
-
#
|
166
|
-
grab: (form) ->
|
167
|
-
data = {}
|
168
|
-
for field in $(form).serializeArray()
|
169
|
-
unless data[field.name]
|
170
|
-
data[field.name] = field.value
|
171
|
-
else
|
172
|
-
data[field.name] = [data[field.name]] unless data[field.name] instanceof Array
|
173
|
-
data[field.name].push field.value
|
174
|
-
|
175
|
-
@load data
|
176
|
-
|
177
|
-
#
|
178
|
-
# Getter for wrapped data
|
179
|
-
#
|
180
|
-
# @param [String] path Attribute name to get. Can contain dots to get inline Objects values
|
181
|
-
# @return [mixed]
|
182
|
-
#
|
183
|
-
__get: (path) ->
|
184
|
-
target = @__callTarget path, true
|
185
|
-
|
186
|
-
if !target
|
187
|
-
return undefined
|
188
|
-
else if target[0] instanceof Joosy.Resources.Base
|
189
|
-
return target[0](target[1])
|
190
|
-
else
|
191
|
-
return target[0][target[1]]
|
192
|
-
|
193
|
-
#
|
194
|
-
# Setter for wrapped data, triggers `changed` event.
|
195
|
-
#
|
196
|
-
# @param [String] path Attribute name to set. Can contain dots to get inline Objects values
|
197
|
-
# @param [mixed] value Value to set
|
198
|
-
#
|
199
|
-
__set: (path, value) ->
|
200
|
-
target = @__callTarget path
|
201
|
-
|
202
|
-
if target[0] instanceof Joosy.Resources.Base
|
203
|
-
target[0](target[1], value)
|
204
|
-
else
|
205
|
-
target[0][target[1]] = value
|
206
|
-
|
207
|
-
@trigger 'changed'
|
208
|
-
null
|
209
|
-
|
210
|
-
#
|
211
|
-
# Locates the actual instance of attribute path `foo.bar` from get/set
|
212
|
-
#
|
213
|
-
# @param [String] path Path to the attribute (`foo.bar`)
|
214
|
-
# @param [Boolean] safe Indicates whether nested hashes should not be automatically created when they don't exist
|
215
|
-
# @return [Array] Instance of object containing last step of path and keyword for required field
|
216
|
-
#
|
217
|
-
__callTarget: (path, safe=false) ->
|
218
|
-
if path.has(/\./) && !@data[path]?
|
219
|
-
path = path.split '.'
|
220
|
-
keyword = path.pop()
|
221
|
-
target = @data
|
222
|
-
|
223
|
-
for part in path
|
224
|
-
return false if safe && !target[part]?
|
225
|
-
|
226
|
-
target[part] ||= {}
|
227
|
-
if target instanceof Joosy.Resources.Base
|
228
|
-
target = target(part)
|
229
|
-
else
|
230
|
-
target = target[part]
|
231
|
-
|
232
|
-
[target, keyword]
|
233
|
-
else
|
234
|
-
[@data, path]
|
235
|
-
|
236
|
-
#
|
237
|
-
# Wrapper for {Joosy.Resources.Base.build} magic
|
238
|
-
#
|
239
|
-
__call: (path, value) ->
|
240
|
-
if arguments.length > 1
|
241
|
-
@__set path, value
|
242
|
-
else
|
243
|
-
@__get path
|
244
|
-
|
245
|
-
#
|
246
|
-
# Defines how exactly prepared data should be saved
|
247
|
-
#
|
248
|
-
# @param [Object] data Raw data to store
|
249
|
-
#
|
250
|
-
__fillData: (data, notify=true) ->
|
251
|
-
@raw = data
|
252
|
-
@data = {} unless @hasOwnProperty 'data'
|
253
|
-
|
254
|
-
Joosy.Module.merge @data, @__prepareData(data)
|
255
|
-
|
256
|
-
@trigger 'changed' if notify
|
257
|
-
|
258
|
-
null
|
259
|
-
|
260
|
-
#
|
261
|
-
# Prepares raw data: cuts the root node if it exists, runs before filters
|
262
|
-
#
|
263
|
-
# @param [Hash] data Raw data to prepare
|
264
|
-
# @return [Hash]
|
265
|
-
#
|
266
|
-
__prepareData: (data) ->
|
267
|
-
if Object.isObject(data) && Object.keys(data).length == 1 && @__entityName
|
268
|
-
name = @__entityName.camelize(false)
|
269
|
-
data = data[name] if data[name]
|
270
|
-
|
271
|
-
@__applyBeforeLoads data
|
272
|
-
|
273
|
-
__map: (data, name, klass) ->
|
274
|
-
if Object.isArray data[name]
|
275
|
-
entries = data[name].map (x) -> klass.build x
|
276
|
-
data[name] = new Joosy.Resources.Array entries...
|
277
|
-
else if Object.isObject data[name]
|
278
|
-
data[name] = klass.build data[name]
|
279
|
-
data
|
280
|
-
|
281
|
-
toString: ->
|
282
|
-
"<Resource #{@__entityName}> #{JSON.stringify(@data)}"
|
@@ -1 +0,0 @@
|
|
1
|
-
#= require_tree ./
|
@@ -1,104 +0,0 @@
|
|
1
|
-
#= require ../form
|
2
|
-
|
3
|
-
#
|
4
|
-
# Form helper
|
5
|
-
#
|
6
|
-
Joosy.helpers 'Application', ->
|
7
|
-
|
8
|
-
description = (resource, method, extendIds, idSuffix) ->
|
9
|
-
if Joosy.Module.hasAncestor resource.constructor, Joosy.Resources.Base
|
10
|
-
id = resource.id()
|
11
|
-
resource = resource.__entityName
|
12
|
-
|
13
|
-
name: resource + "#{if method.match(/^\[.*\]$/) then method else "[#{method}]"}"
|
14
|
-
id: resource + (if id && extendIds then '_'+id else '') + "_#{method.parameterize().underscore()}" + (if idSuffix then '_'+idSuffix else '')
|
15
|
-
|
16
|
-
input = (type, resource, method, options={}) =>
|
17
|
-
d = description(resource, method, options.extendIds, options.idSuffix)
|
18
|
-
delete options.extendIds
|
19
|
-
delete options.idSuffix
|
20
|
-
@tag 'input', Joosy.Module.merge {type: type, name: d.name, id: d.id}, options
|
21
|
-
|
22
|
-
#
|
23
|
-
# @private
|
24
|
-
#
|
25
|
-
class Form
|
26
|
-
constructor: (@context, @resource, @options) ->
|
27
|
-
|
28
|
-
label: (method, options={}, content='') ->
|
29
|
-
if !Object.isObject(options)
|
30
|
-
content = options
|
31
|
-
options = {}
|
32
|
-
|
33
|
-
@context.label(@resource, method, Joosy.Module.merge(extendIds: @options.extendIds, options), content)
|
34
|
-
|
35
|
-
radioButton: (method, tagValue, options={}) -> @context.radioButton(@resource, method, tagValue, Joosy.Module.merge(extendIds: @options.extendIds, options))
|
36
|
-
textArea: (method, options={}) -> @context.textArea(@resource, method, Joosy.Module.merge(extendIds: @options.extendIds, options))
|
37
|
-
checkBox: (method, options={}, checkedValue=1, uncheckedValue=0) -> @context.checkBox(@resource, method, Joosy.Module.merge(extendIds: @options.extendIds, options), checkedValue, uncheckedValue)
|
38
|
-
select: (method, options={}, htmlOptions={}) -> @context.select @resource, method, options, Joosy.Module.merge(extendIds: @options.extendIds, htmlOptions)
|
39
|
-
|
40
|
-
['text', 'file', 'hidden', 'password'].each (type) =>
|
41
|
-
Form.prototype[type+'Field'] = (method, options={}) ->
|
42
|
-
@context[type+'Field'] @resource, method, Joosy.Module.merge(extendIds: @options.extendIds, options)
|
43
|
-
|
44
|
-
@formFor = (resource, options={}, block) ->
|
45
|
-
if Object.isFunction(options)
|
46
|
-
block = options
|
47
|
-
options = {}
|
48
|
-
|
49
|
-
uuid = Joosy.uuid()
|
50
|
-
form = @tag 'form', Joosy.Module.merge(options.html || {}, id: uuid), block?.call(this, new Form(this, resource, options))
|
51
|
-
|
52
|
-
@onRefresh? -> Joosy.Form.attach '#'+uuid, Joosy.Module.merge(options, resource: resource)
|
53
|
-
|
54
|
-
form
|
55
|
-
|
56
|
-
@label = (resource, method, options={}, content='') ->
|
57
|
-
if !Object.isObject(options)
|
58
|
-
content = options
|
59
|
-
options = {}
|
60
|
-
|
61
|
-
d = description(resource, method, options.extendIds)
|
62
|
-
delete options.extendIds
|
63
|
-
|
64
|
-
@contentTag 'label', content, Joosy.Module.merge(options, for: d.id)
|
65
|
-
|
66
|
-
['text', 'file', 'hidden', 'password'].each (type) =>
|
67
|
-
@[type+'Field'] = (resource, method, options={}) -> input type, resource, method, options
|
68
|
-
|
69
|
-
@radioButton = (resource, method, tagValue, options={}) -> input 'radio', resource, method, Joosy.Module.merge(value: tagValue, idSuffix: tagValue, options)
|
70
|
-
|
71
|
-
@checkBox = (resource, method, options={}, checkedValue=1, uncheckedValue=0) ->
|
72
|
-
spy = @tag 'input', Joosy.Module.merge(name: description(resource, method).name, value: uncheckedValue, type: 'hidden')
|
73
|
-
box = input 'checkbox', resource, method, Joosy.Module.merge(value: checkedValue, options)
|
74
|
-
|
75
|
-
spy+box
|
76
|
-
|
77
|
-
@select = (resource, method, options, htmlOptions) ->
|
78
|
-
if Object.isObject options
|
79
|
-
opts = []
|
80
|
-
for key, val of options
|
81
|
-
opts.push [val, key]
|
82
|
-
else
|
83
|
-
opts = options
|
84
|
-
if htmlOptions.includeBlank
|
85
|
-
delete htmlOptions.includeBlank
|
86
|
-
opts.unshift ['', '']
|
87
|
-
opts = opts.reduce (str, vals) =>
|
88
|
-
params = if Object.isArray vals then ['option', vals[0], { value: vals[1] }] else ['option', vals, {}]
|
89
|
-
if htmlOptions.value == (if Object.isArray(vals) then vals[1] else vals)
|
90
|
-
params[2].selected = 'selected'
|
91
|
-
str += @contentTag.apply @, params
|
92
|
-
, ''
|
93
|
-
extendIds = htmlOptions.extendIds
|
94
|
-
delete htmlOptions.value
|
95
|
-
delete htmlOptions.extendIds
|
96
|
-
@contentTag 'select', opts, Joosy.Module.merge(description(resource, method, extendIds), htmlOptions)
|
97
|
-
|
98
|
-
@textArea = (resource, method, options={}) ->
|
99
|
-
value = options.value
|
100
|
-
extendIds = options.extendIds
|
101
|
-
delete options.value
|
102
|
-
delete options.extendIds
|
103
|
-
|
104
|
-
@contentTag 'textarea', value, Joosy.Module.merge(description(resource, method, extendIds), options)
|
@@ -1 +0,0 @@
|
|
1
|
-
#= require_tree ./
|