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.
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
  #