joosy 1.2.0.alpha.73 → 1.2.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/Gruntfile.coffee +56 -18
  3. data/bower.json +1 -1
  4. data/build/joosy/form.js +1 -0
  5. data/build/joosy/resources.js +1 -0
  6. data/build/joosy.js +2 -2774
  7. data/package.json +5 -4
  8. data/source/joosy/application.coffee +9 -7
  9. data/source/joosy/{extensions/resources-form/form.coffee → form.coffee} +58 -51
  10. data/source/joosy/helpers/form.coffee +241 -0
  11. data/source/joosy/helpers/index.coffee +3 -0
  12. data/source/joosy/helpers/routes.coffee +3 -1
  13. data/source/joosy/helpers/view.coffee +9 -9
  14. data/source/joosy/joosy.coffee +3 -5
  15. data/source/joosy/module.coffee +9 -4
  16. data/source/joosy/modules/dom.coffee +33 -31
  17. data/source/joosy/modules/events.coffee +24 -20
  18. data/source/joosy/modules/filters.coffee +38 -35
  19. data/source/joosy/modules/page/title.coffee +3 -3
  20. data/source/joosy/modules/renderer.coffee +23 -18
  21. data/source/joosy/modules/resources/identity_map.coffee +45 -0
  22. data/source/joosy/modules/resources/model.coffee +146 -0
  23. data/source/joosy/modules/widgets_manager.coffee +8 -8
  24. data/source/joosy/resources/array.coffee +0 -5
  25. data/source/joosy/resources/hash.coffee +8 -13
  26. data/source/joosy/resources/index.coffee +2 -0
  27. data/source/joosy/{extensions/resources → resources}/rest.coffee +48 -19
  28. data/source/joosy/resources/scalar.coffee +8 -10
  29. data/source/joosy/router.coffee +13 -12
  30. data/source/joosy/templaters/jst.coffee +3 -2
  31. data/source/joosy/widget.coffee +17 -15
  32. data/source/joosy.coffee +2 -0
  33. data/source/vendor/es5-shim.js +1316 -0
  34. data/source/vendor/inflections.js +598 -0
  35. data/source/vendor/metamorph.js +457 -0
  36. data/spec/helpers/matchers.coffee +4 -4
  37. data/spec/joosy/core/application_spec.coffee +1 -1
  38. data/spec/joosy/core/helpers/view_spec.coffee +2 -2
  39. data/spec/joosy/core/joosy_spec.coffee +8 -4
  40. data/spec/joosy/core/modules/dom_spec.coffee +7 -7
  41. data/spec/joosy/core/modules/events_spec.coffee +2 -2
  42. data/spec/joosy/core/modules/filters_spec.coffee +7 -8
  43. data/spec/joosy/core/modules/module_spec.coffee +5 -5
  44. data/spec/joosy/core/router_spec.coffee +3 -3
  45. data/spec/joosy/core/widget_spec.coffee +6 -6
  46. data/spec/joosy/environments/amd_spec.coffee +4 -2
  47. data/spec/joosy/environments/global_spec.coffee +1 -1
  48. data/spec/joosy/{extensions/form → form}/form_spec.coffee +9 -16
  49. data/spec/joosy/{extensions/form → form}/helpers/forms_spec.coffee +5 -5
  50. data/spec/joosy/{core/resources → resources}/array_spec.coffee +2 -2
  51. data/spec/joosy/{core/resources → resources}/hash_spec.coffee +0 -8
  52. data/spec/joosy/{core/modules/resources → resources/modules}/cacher_spec.coffee +0 -0
  53. data/spec/joosy/resources/modules/identity_map_spec.coffee +47 -0
  54. data/spec/joosy/{extensions/resources/base_spec.coffee → resources/modules/model_spec.coffee} +28 -48
  55. data/spec/joosy/{extensions/resources → resources}/rest_spec.coffee +29 -22
  56. data/spec/joosy/{core/resources → resources}/scalar_spec.coffee +8 -8
  57. data/templates/application/application.coffee.tt +0 -2
  58. data/templates/environment/app/haml/index.haml +2 -2
  59. data/templates/environment/package.json +1 -1
  60. metadata +23 -19
  61. data/build/joosy/extensions/resources-form.js +0 -590
  62. data/build/joosy/extensions/resources.js +0 -561
  63. data/source/joosy/extensions/resources/base.coffee +0 -282
  64. data/source/joosy/extensions/resources/index.coffee +0 -1
  65. data/source/joosy/extensions/resources-form/helpers/form.coffee +0 -104
  66. data/source/joosy/extensions/resources-form/index.coffee +0 -1
  67. data/source/metamorph.coffee +0 -410
data/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "keywords": [
5
5
  "joosy"
6
6
  ],
7
- "version": "1.2.0-alpha.73",
7
+ "version": "1.2.0-beta.1",
8
8
  "author": "Boris Staal <boris@staal.io>",
9
9
  "homepage": "http://joosy.ws/",
10
10
  "repository": {
@@ -15,15 +15,16 @@
15
15
  "node": ">=0.4.0"
16
16
  },
17
17
  "dependencies": {
18
- "grill": ">=1.0.0-alpha.19"
18
+ "grill": ">=1.0.0-alpha.22"
19
19
  },
20
20
  "devDependencies": {
21
21
  "bower": "~1.2.1",
22
22
  "semver": "~2.1.0",
23
23
  "grunt-coffeelint": "0.0.6",
24
24
  "grunt-release": "~0.3.5",
25
- "grunt-contrib-testem": ">=0.5.2",
25
+ "grunt-contrib-testem": ">=0.5.3",
26
26
  "grunt-gh-pages": "git+https://github.com/inossidabile/grunt-gh-pages.git",
27
- "moment": "~2.1.0"
27
+ "moment": "~2.1.0",
28
+ "grunt-contrib-uglify": "~0.2.4"
28
29
  }
29
30
  }
@@ -1,8 +1,7 @@
1
1
  #= require joosy/joosy
2
2
  #= require joosy/router
3
- #= require_tree ./templaters
4
- #= require_tree ./resources
5
- #= require_tree ./helpers
3
+ #= require joosy/templaters/jst
4
+ #= require joosy/helpers
6
5
 
7
6
  #
8
7
  # Joosy Application container
@@ -15,7 +14,7 @@ class Joosy.Application
15
14
  @initialized: false
16
15
  @loading: true
17
16
 
18
- @config:
17
+ @defaultConfig:
19
18
  test: false
20
19
  debug: false
21
20
  templater:
@@ -36,8 +35,11 @@ class Joosy.Application
36
35
  if @initialized
37
36
  throw new Error 'Attempted to initialize Application twice'
38
37
 
39
- Object.merge @config, window.JoosyEnvironment, true if window.JoosyEnvironment?
40
- Object.merge @config, options, true
38
+ @config = {}
39
+
40
+ Joosy.Module.merge @config, @defaultConfig, true, true
41
+ Joosy.Module.merge @config, window.JoosyEnvironment, true, true if window.JoosyEnvironment?
42
+ Joosy.Module.merge @config, options, true, true
41
43
 
42
44
  @forceSandbox() if @config.test
43
45
 
@@ -47,7 +49,7 @@ class Joosy.Application
47
49
  Joosy.Router.setup @config.router, (action, params) =>
48
50
  if Joosy.Module.hasAncestor action, Joosy.Page
49
51
  @changePage action, params
50
- else if Object.isFunction(action)
52
+ else if typeof(action) == 'function'
51
53
  action(params)
52
54
  else
53
55
  throw new Error "Unknown kind of route action: #{action}"
@@ -95,11 +95,10 @@ class Joosy.Form extends Joosy.Module
95
95
  # @option options [Boolean] debounce Drop submit events while there is a pending submit request
96
96
  #
97
97
  constructor: (form, options={}) ->
98
- if Object.isFunction options
98
+ if typeof(options) == 'function'
99
99
  @success = options
100
100
  else
101
- Object.each options, (key, value) =>
102
- @[key] = value
101
+ @[key] = value for key, value of options
103
102
 
104
103
  @$container = $(form)
105
104
  return if @$container.length == 0
@@ -108,7 +107,7 @@ class Joosy.Form extends Joosy.Module
108
107
  @__delegateEvents()
109
108
 
110
109
  method = @$container.get(0).getAttribute('method')?.toLowerCase()
111
- if method && !['get', 'post'].any method
110
+ if method && !['get', 'post'].indexOf(method) != -1
112
111
  @__markMethod method
113
112
  @$container.attr 'method', 'POST'
114
113
 
@@ -155,7 +154,7 @@ class Joosy.Form extends Joosy.Module
155
154
 
156
155
  #
157
156
  # Links current form with given resource and sets values of form inputs from with it.
158
- # Form will use give resource while doing invalidation routine.
157
+ # Form will use given resource while doing invalidation routine.
159
158
  #
160
159
  # @param [Resource] resource Resource to fill fields with
161
160
  # @param [Hash] options Options
@@ -166,7 +165,7 @@ class Joosy.Form extends Joosy.Module
166
165
  # @option options [String] action Action URL for the form
167
166
  #
168
167
  fill: (resource, options) ->
169
- resource = resource.build() if Object.isFunction(resource.build)
168
+ resource = resource.build() if typeof(resource.build) == 'function'
170
169
  @__resource = resource
171
170
 
172
171
  if options?.decorator?
@@ -177,27 +176,29 @@ class Joosy.Form extends Joosy.Module
177
176
  filler = (data, scope) =>
178
177
  return if data.__joosy_form_filler_lock
179
178
  data.__joosy_form_filler_lock = true
180
- Object.each data, (property, val) =>
181
- key = @concatFieldName scope, property
182
- input = @$fields().filter("[name='#{key}']:not(:file),[name='#{key.underscore()}']:not(:file),[name='#{key.camelize(false)}']:not(:file)")
183
- if input.length > 0
184
- if input.is ':checkbox'
185
- if val
186
- input.attr 'checked', 'checked'
179
+
180
+ for property, val of data
181
+ do (property, val) =>
182
+ key = @concatFieldName scope, property
183
+ input = @$fields().filter("[name='#{key}']:not(:file),[name='#{inflection.underscore(key)}']:not(:file),[name='#{inflection.camelize(key, true)}']:not(:file)")
184
+ if input.length > 0
185
+ if input.is ':checkbox'
186
+ if val
187
+ input.attr 'checked', 'checked'
188
+ else
189
+ input.removeAttr 'checked'
190
+ else if input.is ':radio'
191
+ input.filter("[value='#{val}']").attr 'checked', 'checked'
187
192
  else
188
- input.removeAttr 'checked'
189
- else if input.is ':radio'
190
- input.filter("[value='#{val}']").attr 'checked', 'checked'
193
+ input.val val
194
+ if val instanceof Joosy.Resources.Array
195
+ for entity, i in val
196
+ filler entity.data, @concatFieldName(scope, "[#{property}_attributes][#{i}]")
197
+ else if val instanceof Joosy.Resources.REST
198
+ filler val.data, @concatFieldName(scope, "[#{property}_attributes]")
199
+ else if val?.constructor == Object || val instanceof Array
200
+ filler val, key
191
201
  else
192
- input.val val
193
- if val instanceof Joosy.Resources.Array
194
- for entity, i in val
195
- filler entity.data, @concatFieldName(scope, "[#{property}_attributes][#{i}]")
196
- else if val instanceof Joosy.Resources.REST
197
- filler val.data, @concatFieldName(scope, "[#{property}_attributes]")
198
- else if Object.isObject(val) || Object.isArray(val)
199
- filler val, key
200
- else
201
202
  delete data.__joosy_form_filler_lock
202
203
 
203
204
  filler data, resource.__entityName || options.resourceName
@@ -264,9 +265,10 @@ class Joosy.Form extends Joosy.Module
264
265
  if !@error? || @error(errors) is true
265
266
  errors = @__stringifyErrors(errors)
266
267
 
267
- Object.each errors, (field, notifications) =>
268
- input = @findField(field).addClass @invalidationClass
269
- @notification? input, notifications
268
+ for field, notifications of errors
269
+ do (field, notifications) =>
270
+ input = @findField(field).addClass @invalidationClass
271
+ @notification? input, notifications
270
272
 
271
273
  return errors
272
274
 
@@ -330,29 +332,30 @@ class Joosy.Form extends Joosy.Module
330
332
  __stringifyErrors: (errors) ->
331
333
  result = {}
332
334
 
333
- errors = errors.errors if Object.isObject(errors?.errors)
335
+ errors = errors.errors if errors?.errors?.constructor == Object
334
336
 
335
- Object.each errors, (field, notifications) =>
336
- if @substitutions[field]?
337
- field = @substitutions[field]
337
+ for field, notifications of errors
338
+ do (field, notifications) =>
339
+ if @substitutions[field]?
340
+ field = @substitutions[field]
338
341
 
339
- if Object.isObject(notifications) || @isArrayOfObjects(notifications)
340
- Object.each @__foldInlineEntities(notifications), (key, value) ->
341
- result[field+key] = value
342
- else
343
- if field.indexOf(".") != -1
344
- splited = field.split '.'
345
- field = splited.shift()
346
- if @resourceName || @__resource
347
- name = @resourceName || @__resource.__entityName
348
- field = name + "[#{field}]"
349
- field += "[#{f}]" for f in splited
342
+ if notifications.constructor == Object || @isArrayOfObjects(notifications)
343
+ result[field+key] = value for key, value of @__foldInlineEntities(notifications)
344
+
345
+ else
346
+ if field.indexOf(".") != -1
347
+ splited = field.split '.'
348
+ field = splited.shift()
349
+ if @resourceName || @__resource
350
+ name = @resourceName || @__resource.__entityName
351
+ field = name + "[#{field}]"
352
+ field += "[#{f}]" for f in splited
350
353
 
351
- else if @resourceName || @__resource
352
- name = @resourceName || @__resource.__entityName
353
- field = name + "[#{field}]"
354
+ else if @resourceName || @__resource
355
+ name = @resourceName || @__resource.__entityName
356
+ field = name + "[#{field}]"
354
357
 
355
- result[field] = notifications
358
+ result[field] = notifications
356
359
 
357
360
  result
358
361
 
@@ -372,8 +375,8 @@ class Joosy.Form extends Joosy.Module
372
375
  # @return [Hash]
373
376
  #
374
377
  __foldInlineEntities: (hash, scope="", result={}) ->
375
- Object.each hash, (key, value) =>
376
- if Object.isObject(value) || @isArrayOfObjects(value)
378
+ for key, value of hash
379
+ if value?.constructor == Object || @isArrayOfObjects(value)
377
380
  @__foldInlineEntities(value, "#{scope}[#{key}]", result)
378
381
  else
379
382
  result["#{scope}[#{key}]"] = value
@@ -388,7 +391,7 @@ class Joosy.Form extends Joosy.Module
388
391
  items = name.split('][')
389
392
  first = items[0].split('[')
390
393
  if first.length == 2
391
- if first[0].isBlank()
394
+ if first[0].length == 0
392
395
  items.splice 0, 1, first[1]
393
396
  else
394
397
  items.splice 0, 1, first[0], first[1]
@@ -396,4 +399,8 @@ class Joosy.Form extends Joosy.Module
396
399
  items
397
400
 
398
401
  isArrayOfObjects: (array) ->
399
- Object.isArray(array) && array.every((elem) -> Object.isObject(elem))
402
+ array instanceof Array && array.filter((elem) -> elem?.constructor != Object).length == 0
403
+
404
+ # AMD wrapper
405
+ if define?.amd?
406
+ define 'joosy/form', -> Joosy.Form
@@ -0,0 +1,241 @@
1
+ #
2
+ # @private
3
+ #
4
+ class Form
5
+ constructor: (@context, @resource, @options) ->
6
+
7
+ __extend: (options) ->
8
+ options.extendIds = @options.extendIds
9
+ options
10
+
11
+ for type in ['text', 'file', 'hidden', 'password']
12
+ do (type) =>
13
+ @::[type+'Field'] = (property, options={}) ->
14
+ @context[type+'Field'] @resource, property, @__extend(options)
15
+
16
+ label: (property, options={}, content='') ->
17
+ # (property, content) ->
18
+ if arguments.length == 2
19
+ content = options
20
+ options = {}
21
+
22
+ @context.label @resource, property, @__extend(options), content
23
+
24
+ radioButton: (property, tagValue, options={}) ->
25
+ @context.radioButton @resource, property, tagValue, @__extend(options)
26
+
27
+ textArea: (property, options={}) ->
28
+ @context.textArea @resource, property, @__extend(options)
29
+
30
+ checkBox: (property, options={}, checkedValue=1, uncheckedValue=0) ->
31
+ @context.checkBox @resource, property, @__extend(options), checkedValue, uncheckedValue
32
+
33
+ select: (property, selectOptions={}, options={}) ->
34
+ @context.select @resource, property, selectOptions, @__extend(options)
35
+
36
+ #
37
+ # Form helper
38
+ #
39
+ Joosy.helpers 'Application', ->
40
+
41
+ separateOptions = (options, keys) ->
42
+ attributes = {}
43
+ parameters = {}
44
+
45
+ for key, value of options
46
+ if keys.indexOf(key) != -1
47
+ parameters[key] = value
48
+ else
49
+ attributes[key] = value
50
+
51
+ [parameters, attributes]
52
+
53
+ #
54
+ # Generates main attributes of a single field for a form
55
+ #
56
+ # @param [String] resource Name of resource
57
+ # @param [Object] resource Instance of something that includes Joosy.Modules.Resources.Module
58
+ # @param [String] property Name of attribute the field is for
59
+ # @param [Boolean] extendIds Marks whether DOM id of a field should contain primary key of resource
60
+ # @param [String] idSuffix Suffix to append to DOM id
61
+ # @param [Hash] DOM attributes Initial set that should be extended
62
+ #
63
+ domify = (resource, property, extendIds, idSuffix, attributes) ->
64
+ if resource.__entityName? && resource.id?
65
+ resourceId = resource.id()
66
+ resource = resource.__entityName
67
+
68
+ unless attributes
69
+ attributes = {}
70
+ else
71
+ attributes = Joosy.Module.merge {}, attributes
72
+
73
+ attributes.name = resource
74
+ attributes.name += if property.match(/^\[.*\]$/) then property else "[#{property}]"
75
+
76
+ # Parameterizing property
77
+ property = property.replace(/[^a-z0-9\-_]+/gi, '_')
78
+ property = property.replace /^_+|_+$|(_)_+/g, '$1'
79
+ property = property.toLowerCase()
80
+
81
+ attributes.id = resource
82
+ attributes.id += "_#{resourceId}" if resourceId? && extendIds
83
+ attributes.id += "_#{property}"
84
+ attributes.id += "_#{idSuffix}" if idSuffix
85
+
86
+ attributes
87
+
88
+ #
89
+ # Generates input field
90
+ #
91
+ input = (type, resource, property, extendIds, idSuffix, attributes={}) =>
92
+ attributes.type = type
93
+ attributes = domify(resource, property, extendIds, idSuffix, attributes)
94
+
95
+ @tag 'input', attributes
96
+
97
+ #
98
+ # ======================================================================
99
+ #
100
+
101
+ #
102
+ # Instantiates a form builder
103
+ #
104
+ # @param [String] resource Name of resource
105
+ # @param [Object] resource Instance of something that includes Joosy.Modules.Resources.Module
106
+ # @param [Function] block Inline template that will be rendered as a form
107
+ # @param [Object] options
108
+ #
109
+ # @option options [Boolean] extendIds Marks if DOM ids of fields should include primary key of resource (default: false)
110
+ #
111
+ # @example
112
+ # != @formFor Resource, {extendIds: true}, (form) =>
113
+ # != form.textField 'property'
114
+ #
115
+ @formFor = (resource, options={}, block) ->
116
+ # (options, block) ->
117
+ if arguments.length == 2
118
+ block = options
119
+ options = {}
120
+
121
+ attributes = Joosy.Module.merge(options.html || {}, id: uuid)
122
+ uuid = Joosy.uuid()
123
+ form = new Form @, resource, options
124
+
125
+ @tag 'form', attributes, block?.call(@, form)
126
+
127
+ #
128
+ # Generates `label` tag
129
+ #
130
+ # @param [String] resource Name of resource
131
+ # @param [Object] resource Instance of something that includes Joosy.Modules.Resources.Module
132
+ # @param [String] property Attribute of a resource to use
133
+ # @param [Object] options
134
+ # @option options [Boolean] extendIds Marks if DOM ids of fields should include primary key of resource (default: false)
135
+ # @param [String] content Content of the label
136
+ #
137
+ @label = (resource, property, options={}, content='') ->
138
+ # (resource, property, content) ->
139
+ if arguments.length == 3
140
+ content = options
141
+ options = {}
142
+
143
+ [parameters, attributes] = separateOptions options, ['extendIds']
144
+
145
+ attributes.for = domify(resource, property, parameters.extendIds, '', attributes).id
146
+
147
+ @contentTag 'label', content, attributes
148
+
149
+ #
150
+ # Set of typical generators for basic inputs: textField, fileField, hiddenField, passwordField
151
+ #
152
+ for type in ['text', 'file', 'hidden', 'password']
153
+ do (type) =>
154
+ @[type+'Field'] = (resource, property, options={}) ->
155
+ [parameters, attributes] = separateOptions options, ['extendIds']
156
+
157
+ input type, resource, property, parameters.extendIds, '', attributes
158
+
159
+ #
160
+ # Generates a radio button
161
+ #
162
+ # @param [String] resource Name of resource
163
+ # @param [Object] resource Instance of something that includes Joosy.Modules.Resources.Module
164
+ # @param [String] property Attribute of a resource to use
165
+ # @param [Object] options
166
+ # @option options [Boolean] extendIds Marks if DOM ids of fields should include primary key of resource (default: false)
167
+ # @param [String] tagValue Value of the button
168
+ #
169
+ @radioButton = (resource, property, tagValue, options={}) ->
170
+ [parameters, attributes] = separateOptions(options, ['extendIds'])
171
+
172
+ attributes.value = tagValue
173
+ input 'radio', resource, property, options.extendIds, tagValue, attributes
174
+
175
+ #
176
+ # Generates a checkbox
177
+ #
178
+ # @param [String] resource Name of resource
179
+ # @param [Object] resource Instance of something that includes Joosy.Modules.Resources.Module
180
+ # @param [String] property Attribute of a resource to use
181
+ # @param [Object] options
182
+ # @option options [Boolean] extendIds Marks if DOM ids of fields should include primary key of resource (default: false)
183
+ # @param [String] checkedValue Value for the checked condition
184
+ # @param [String] uncheckedValue Value for the unchecked condition
185
+ #
186
+ @checkBox = (resource, property, options={}, checkedValue=1, uncheckedValue=0) ->
187
+ [parameters, attributes] = separateOptions(options, ['extendIds'])
188
+
189
+ spyAttributes = domify resource, property, parameters.extendIds, '', attributes
190
+ spy = @tag 'input', name: spyAttributes.name, value: uncheckedValue, type: 'hidden'
191
+
192
+ attributes.value = checkedValue
193
+ box = input 'checkbox', resource, property, parameters.extendIds, '', attributes
194
+
195
+ spy+box
196
+
197
+ #
198
+ # Generates a select
199
+ #
200
+ # @param [String] resource Name of resource
201
+ # @param [Object] resource Instance of something that includes Joosy.Modules.Resources.Module
202
+ # @param [String] property Attribute of a resource to use
203
+ # @param [Object] options
204
+ # @option options [Boolean] extendIds Marks if DOM ids of fields should include primary key of resource (default: false)
205
+ # @option options [String] value Sets current value of a select
206
+ # @option options [Boolean] includeBlank Marks if select should contain blank starting option
207
+ # @param [Object] selectOptions Options to build select with `{foo: 'bar'}`
208
+ # @param [Array] selectOptions Options to build select with `['foo', 'bar']`
209
+ #
210
+ @select = (resource, property, rawSelectOptions, options) ->
211
+ [parameters, attributes] = separateOptions(options, ['extendIds', 'value', 'includeBlank'])
212
+
213
+ if rawSelectOptions instanceof Array
214
+ selectOptions = rawSelectOptions
215
+ else
216
+ selectOptions = []
217
+ selectOptions.push [val, key] for key, val of rawSelectOptions
218
+
219
+ selectOptions.unshift ['', ''] if parameters.includeBlank
220
+ selectOptions = selectOptions.reduce (str, vals) =>
221
+ params = if (vals instanceof Array) then ['option', vals[0], { value: vals[1] }] else ['option', vals, {}]
222
+ if parameters.value == (if (vals instanceof Array) then vals[1] else vals)
223
+ params[2].selected = 'selected'
224
+ str += @contentTag.apply @, params
225
+ , ''
226
+
227
+ @contentTag 'select', selectOptions, domify(resource, property, parameters.extendIds, '', attributes)
228
+
229
+ #
230
+ # Generates a text area
231
+ #
232
+ # @param [String] resource Name of resource
233
+ # @param [Object] resource Instance of something that includes Joosy.Modules.Resources.Module
234
+ # @param [String] property Attribute of a resource to use
235
+ # @param [Object] options
236
+ # @option options [Boolean] extendIds Marks if DOM ids of fields should include primary key of resource (default: false)
237
+ # @option options [String] value Value of the text area
238
+ #
239
+ @textArea = (resource, property, options={}) ->
240
+ [parameters, attributes] = separateOptions(options, ['extendIds', 'value'])
241
+ @contentTag 'textarea', parameters.value, domify(resource, property, parameters.extendIds, '', attributes)
@@ -0,0 +1,3 @@
1
+ #= require ./routes
2
+ #= require ./view
3
+ #= require ./widgets
@@ -7,7 +7,9 @@
7
7
  Joosy.helpers 'Routes', ->
8
8
 
9
9
  @linkTo = (name='', url='', tagOptions={}) ->
10
- if Object.isFunction tagOptions
10
+
11
+ # (url, tagOptions, block) ->
12
+ if typeof(tagOptions) == 'function'
11
13
  block = tagOptions
12
14
  [url, tagOptions] = [name, url]
13
15
  name = block()
@@ -55,9 +55,9 @@ Joosy.helpers 'Application', ->
55
55
  #
56
56
  # Possible arguments variations:
57
57
  # 1. @contentTag 'name', 'content'
58
- # 2. @contentTag 'name', {}, ->
59
- # 3. @contentTag 'name', {}, false, ->
60
- # 4. @contentTag 'name', ->
58
+ # 2. @contentTag 'name', ->
59
+ # 3. @contentTag 'name', {}, ->
60
+ # 4. @contentTag 'name', {}, false, ->
61
61
  #
62
62
  # Example
63
63
  # != @contentTag 'div', {class: 'foo'}, =>
@@ -66,20 +66,20 @@ Joosy.helpers 'Application', ->
66
66
  @contentTag = (name, contentOrOptions=null, options=null, escape=true) ->
67
67
  # This is a bit painfull but this is
68
68
  # how we emulate Ruby block with lambda :(
69
- if Object.isString(contentOrOptions)
69
+ if typeof(contentOrOptions) == 'string'
70
70
  options ||= {}
71
71
  content = contentOrOptions
72
- else if Object.isObject(contentOrOptions)
73
- if Object.isFunction(options)
72
+ else if typeof(contentOrOptions) == 'function'
73
+ options = {}
74
+ content = contentOrOptions()
75
+ else
76
+ if typeof(options) == 'function'
74
77
  escape = true
75
78
  content = options()
76
79
  else
77
80
  escape = options
78
81
  content = escape()
79
82
  options = contentOrOptions
80
- else
81
- options = {}
82
- content = contentOrOptions()
83
83
 
84
84
  element = document.createElement name
85
85
  temp = document.createElement 'div'
@@ -139,17 +139,15 @@
139
139
  #
140
140
  buildUrl: (url, params) ->
141
141
  paramsString = []
142
-
143
- Object.each params, (key, value) ->
144
- paramsString.push "#{key}=#{value}"
142
+ paramsString.push "#{key}=#{value}" for key, value of params
145
143
 
146
144
  hash = url.match(/(\#.*)?$/)[0]
147
145
  url = url.replace /\#.*$/, ''
148
- if !paramsString.isEmpty() && !url.has(/\?/)
146
+ if paramsString.length != 0 && url.indexOf('?') == -1
149
147
  url = url + "?"
150
148
 
151
149
  paramsString = paramsString.join '&'
152
- if !paramsString.isBlank() && url.last() != '?'
150
+ if paramsString.length > 0 && url[url.length-1] != '?'
153
151
  paramsString = '&' + paramsString
154
152
 
155
153
  url + paramsString + hash
@@ -19,7 +19,7 @@ class Joosy.Module
19
19
  # @return [String]
20
20
  #
21
21
  @__className: (klass) ->
22
- unless Object.isFunction(klass)
22
+ unless typeof(klass) == 'function'
23
23
  klass = klass.constructor
24
24
 
25
25
  if klass.name?
@@ -61,7 +61,7 @@ class Joosy.Module
61
61
  camelized = feature.charAt(0).toUpperCase() + feature.slice(1)
62
62
  chained = "#{method}Without#{camelized}"
63
63
 
64
- action = @::[action] unless Object.isFunction(action)
64
+ action = @::[action] unless typeof(action) == 'function'
65
65
 
66
66
  @::[chained] = @::[method]
67
67
  @::[method] = action
@@ -91,14 +91,19 @@ class Joosy.Module
91
91
  # @param [Object] destination Object to extend
92
92
  # @param [Object] source Source of new properties
93
93
  # @param [Boolean] unsafe Determines if we should rewrite destination properties
94
+ # @param [Boolean] deep Whether merge should go down recursively into nested objects
94
95
  #
95
96
  # @return [Object] The new and mighty destination Object
96
97
  #
97
- @merge: (destination, source, unsafe=true) ->
98
+ @merge: (destination, source, unsafe=true, deep=false) ->
98
99
  for key, value of source
99
100
  if source.hasOwnProperty(key)
100
101
  if unsafe || !destination.hasOwnProperty(key)
101
- destination[key] = value
102
+ if deep && value.constructor == Object
103
+ destination[key] = {} unless destination[key]?.constructor == Object
104
+ Joosy.Module.merge destination[key], value
105
+ else
106
+ destination[key] = value
102
107
  destination
103
108
 
104
109
  #