joosy 1.2.0.alpha.14 → 1.2.0.alpha.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/Gruntfile.coffee +42 -18
  4. data/README.md +16 -12
  5. data/bower.json +1 -1
  6. data/lib/extensions/form.js +592 -0
  7. data/lib/extensions/preloaders.js +193 -0
  8. data/lib/extensions/resources.js +667 -0
  9. data/lib/joosy.js +1141 -2680
  10. data/lib/joosy.rb +0 -5
  11. data/package.json +1 -1
  12. data/spec/helpers/helper.coffee +1 -1
  13. data/spec/joosy/core/joosy_spec.coffee +1 -28
  14. data/spec/joosy/core/modules/renderer_spec.coffee +0 -95
  15. data/spec/joosy/{core → extensions/form}/form_spec.coffee +2 -2
  16. data/spec/joosy/{core → extensions/form}/helpers/forms_spec.coffee +1 -1
  17. data/spec/joosy/{preloaders → extensions/preloaders}/caching_spec.coffee +0 -0
  18. data/spec/joosy/{preloaders → extensions/preloaders}/inline_spec.coffee +0 -0
  19. data/spec/joosy/{core/resource/generic_spec.coffee → extensions/resources/base_spec.coffee} +19 -20
  20. data/spec/joosy/{core/resource → extensions/resources}/collection_spec.coffee +4 -4
  21. data/spec/joosy/{core/resource → extensions/resources}/rest_collection_spec.coffee +4 -4
  22. data/spec/joosy/{core/resource → extensions/resources}/rest_spec.coffee +6 -7
  23. data/src/joosy.coffee +1 -2
  24. data/src/joosy/core/helpers/view.coffee +0 -8
  25. data/src/joosy/core/joosy.coffee +5 -44
  26. data/src/joosy/core/modules/renderer.coffee +10 -29
  27. data/src/joosy/core/{resource → resources}/watcher.coffee +2 -1
  28. data/src/joosy/{core → extensions/form}/form.coffee +3 -9
  29. data/src/joosy/{core → extensions/form}/helpers/form.coffee +2 -2
  30. data/src/joosy/extensions/form/index.coffee +1 -0
  31. data/src/joosy/{preloaders → extensions/preloaders}/caching.coffee +0 -0
  32. data/src/joosy/extensions/preloaders/index.coffee +1 -0
  33. data/src/joosy/{preloaders → extensions/preloaders}/inline.coffee +0 -0
  34. data/src/joosy/{core/resource/generic.coffee → extensions/resources/base.coffee} +21 -21
  35. data/src/joosy/{core/resource → extensions/resources}/collection.coffee +11 -11
  36. data/src/joosy/extensions/resources/index.coffee +1 -0
  37. data/src/joosy/{core/resource → extensions/resources}/rest.coffee +15 -12
  38. data/src/joosy/{core/resource → extensions/resources}/rest_collection.coffee +4 -2
  39. data/src/joosy/generators/base.coffee +1 -1
  40. metadata +25 -20
  41. data/src/joosy/core/preloader.coffee +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e7efe3701ce2f216a6e1733e322573234cd19737
4
- data.tar.gz: c41874a7bd7ce743e6f4c8232d5bad56acd4d8df
3
+ metadata.gz: f5dd10943aa7e77f3b2b8819b0fe66a8849bf6f6
4
+ data.tar.gz: e97611fc855f28795886e99af976aaabc3a048ca
5
5
  SHA512:
6
- metadata.gz: 3ac1bc38b42830cda852e9b46ff543d499d9057c7e290bc58b9d01b0995e5eb31604b05e8187f8dd87bbe37cf6de4dd659d95f4ba2baa29cc013a29cf2fbf1d7
7
- data.tar.gz: 44265f5626c425a31c5ddcec40be293538a0b75e7d8d7f63a4b8ac92c116d3ee19d50befa8634c9c86a166b4457043d6cc6d747917b9549864ec726f23134d77
6
+ metadata.gz: 054a7481dab1f1f7f354d7390eb18fcd0d962531f361cc5b5844dcf8e18315794b2f101b32695e3526c973c50b4e615ccc039e6916c99292a0e8f03becc30b17
7
+ data.tar.gz: 3dd8453a8d90b61f489a4b5a699aed6d42d61fd593fa626951dc9b72c2562c1557603e0f7fd1933b183181b5ee8e503555111e871dda2cc9e25de45dfdc5c293
data/.gitignore CHANGED
@@ -1,6 +1,6 @@
1
1
  node_modules
2
2
  components
3
3
  .grunt
4
- index.html
4
+ *.html
5
5
  *.gem
6
6
  Gemfile.lock
data/Gruntfile.coffee CHANGED
@@ -12,11 +12,29 @@ module.exports = (grunt) ->
12
12
  root: 'joosy.coffee'
13
13
  path: 'src'
14
14
  build: 'lib/joosy.js'
15
+ extensions: (name) ->
16
+ root: "joosy/extensions/#{name}"
17
+ build: "lib/extensions/#{name}.js"
15
18
  specs:
16
- units: 'spec/**/*_spec.*'
19
+ units:
20
+ core: 'spec/joosy/core/**/*_spec.*'
21
+ extensions: 'spec/joosy/extensions/**/*_spec.*'
17
22
  helpers: 'spec/helpers/**/*.*'
18
23
  build: '.grunt'
19
24
 
25
+ specOptions = (category, specs) ->
26
+ host: 'http://localhost:8888/'
27
+ keepRunner: true
28
+ outfile: "#{category}.html"
29
+ vendor: [
30
+ 'components/sinonjs/sinon.js',
31
+ 'components/jquery/jquery.js',
32
+ 'components/jquery-form/jquery.form.js',
33
+ 'components/sugar/release/sugar-full.min.js'
34
+ ],
35
+ specs: "#{locations.specs.build}/#{specs}"
36
+ helpers: locations.specs.build + '/' + locations.specs.helpers
37
+
20
38
  #
21
39
  # Grunt extensions
22
40
  #
@@ -48,21 +66,33 @@ module.exports = (grunt) ->
48
66
  specs:
49
67
  options:
50
68
  nospawn: true
51
- files: [locations.specs.units, locations.specs.helpers]
69
+ files: [locations.specs.units.core, locations.specs.units.extensions, locations.specs.helpers]
52
70
  tasks: ['coffee', 'jasmine']
53
71
 
54
72
  coffee:
55
73
  specs:
56
74
  expand: true
57
- src: [locations.specs.units, locations.specs.helpers]
75
+ src: [locations.specs.units.core, locations.specs.units.extensions, locations.specs.helpers]
58
76
  dest: locations.specs.build
59
77
  ext: '.js'
60
78
 
61
79
  mince:
62
- main:
80
+ core:
63
81
  include: [locations.source.path]
64
82
  src: locations.source.root
65
83
  dest: locations.source.build
84
+ preloaders:
85
+ include: [locations.source.path]
86
+ src: locations.source.extensions('preloaders').root
87
+ dest: locations.source.extensions('preloaders').build
88
+ resources:
89
+ include: [locations.source.path]
90
+ src: locations.source.extensions('resources').root
91
+ dest: locations.source.extensions('resources').build
92
+ form:
93
+ include: [locations.source.path]
94
+ src: locations.source.extensions('form').root
95
+ dest: locations.source.extensions('form').build
66
96
 
67
97
  coffeelint:
68
98
  source:
@@ -73,20 +103,14 @@ module.exports = (grunt) ->
73
103
  level: 'ignore'
74
104
 
75
105
  jasmine:
76
- joosy:
106
+ core:
107
+ options: specOptions('core', locations.specs.units.core)
77
108
  src: locations.source.build
78
- options:
79
- host: 'http://localhost:8888/'
80
- keepRunner: true
81
- outfile: 'index.html'
82
- vendor: [
83
- 'components/sinonjs/sinon.js',
84
- 'components/jquery/jquery.js',
85
- 'components/jquery-form/jquery.form.js',
86
- 'components/sugar/release/sugar-full.min.js'
87
- ],
88
- specs: locations.specs.build + '/' + locations.specs.units
89
- helpers: locations.specs.build + '/' + locations.specs.helpers
109
+
110
+ extensions:
111
+ options: specOptions('extensions', locations.specs.units.extensions)
112
+ src: [locations.source.build].include ['preloaders', 'resources', 'form'].map (x) ->
113
+ locations.source.extensions(x).build
90
114
 
91
115
  grunt.event.on 'watch', (action, filepath) ->
92
116
  grunt.config ['coffee', 'specs', 'src'], filepath
@@ -96,7 +120,7 @@ module.exports = (grunt) ->
96
120
  #
97
121
  grunt.registerTask 'default', ['connect', 'build', 'watch']
98
122
 
99
- grunt.registerTask 'build', ['mince', 'coffee', 'jasmine:joosy:build', 'bowerize']
123
+ grunt.registerTask 'build', ['mince', 'coffee', 'jasmine:core:build', 'jasmine:extensions:build', 'bowerize']
100
124
 
101
125
  grunt.registerTask 'test', ['connect', 'mince', 'coffee', 'bowerize', 'jasmine']
102
126
 
data/README.md CHANGED
@@ -1,9 +1,15 @@
1
1
  # Joosy 1.2: Feather
2
2
 
3
+ ![Joosy](http://f.cl.ly/items/2N2J453J2B353F1A0t0I/joocy1.1.png)
4
+
5
+ Joosy is a javascript framework. Being a harmonious extensions to Rails it introduces everything you like about backend right to your browser. Ready conventions set, extensive CoffeeScript, HAML support, Helpers, seamless backend integration, automatic code generation and more.
6
+
3
7
  [![NPM version](https://badge.fury.io/js/joosy.png)](http://badge.fury.io/js/joosy)
4
8
  [![Build Status](https://travis-ci.org/joosy/joosy.png)](https://travis-ci.org/joosy/joosy)
5
9
  [![Dependency Status](https://gemnasium.com/joosy/joosy.png)](https://gemnasium.com/joosy/joosy)
6
10
 
11
+ ---
12
+
7
13
  ## WARNING!!!
8
14
 
9
15
  Master branch is currently totally incompatible with the stable 1.1 and 1.0 branches. 1.2 features
@@ -31,11 +37,9 @@ to change or work not as expected while 1.2 branch is still early alpha.
31
37
 
32
38
  Keep track on what's going on at the [Wiki](https://github.com/joosy/joosy/wiki#12-feather)
33
39
 
34
- ## What is Joosy
35
-
36
- ![Joosy](http://f.cl.ly/items/2N2J453J2B353F1A0t0I/joocy1.1.png)
40
+ ---
37
41
 
38
- Joosy is a javascript framework. Being a harmonious extensions to Rails it introduces everything you like about this framework right to your browser. Ready conventions set, extensive CoffeeScript, HAML support, Helpers, seamless backend integration, automatic code generation and more.
42
+ ## What is Joosy
39
43
 
40
44
  Joosy allows you to create web apps which work completely in the browser. So that, it helps you to relocate all your Rails Views to the client side. It also helps you with managing the growing quantity of JS code. On another hand, it makes your backend to have exactly one function – to be a simple REST provider. That leads to easier development support and improves the scalability greatly.
41
45
 
@@ -51,11 +55,11 @@ Add Joosy gem to your Gemfile:
51
55
  gem 'joosy-rails', '~> 1.0.0'
52
56
  ```
53
57
 
54
- Using built-in generators you can quickly generate small app inside your Rails app to see Joosy application from inside a bit.
58
+ Use built-in generator to seed a basic application:
55
59
 
56
- rails g joosy:application dummy
60
+ rails g joosy:application
57
61
 
58
- Now you can run `rails s` to get Joosy placeholder at [localhost:3000/dummy](http://localhost:3000/dummy). Generated application will consist of one `Layout` and one `Page` both including very basic practices of Joosy.
62
+ Make sure to remove `public/index.html` and you are ready to go with [localhost:3000](http://localhost:3000/). The main application code can be found at `app/assets/javascripts` directory. HTML canvas of the application is at `app/views/layouts/joosy.html.erb`.
59
63
 
60
64
  ### Jump in with Sinatra
61
65
 
@@ -69,24 +73,24 @@ Now run basic application generator with the following command:
69
73
 
70
74
  joosy new dummy
71
75
 
72
- The main application code will appear at `source` directory. `stylesheets` is for Stylus-based styles and the main canvas of page is defined at `source/index.haml`. Now you can `grunt joosy:server` to start development server at [localhost:4000/](http://localhost:4000/).
76
+ The main application code will appear at `source` directory. `stylesheets` is for Stylus-based styles and the main canvas of page is defined at `source/index.haml`. Now you can `grunt joosy:server` to start development server at [localhost:4000](http://localhost:4000/).
73
77
 
74
- To generate assets statically prior to the deployment run
78
+ To generate assets statically prior to the deployment run:
75
79
 
76
80
  grunt joosy:compile
77
81
 
78
- Your assets will appear at `public/` directory.
82
+ You assets are at `public/` directory, enjoy!
79
83
 
80
84
  ## Hacking
81
85
 
82
86
  * Ensure you have Node.js available on your system
83
87
  * Clone the project
84
88
  * Run `npm install` to get required Node modules
85
- * Run `bower install` to get require JS components
89
+ * Run `bower install` to get required JS components
86
90
  * Run `grunt test` to run specs once
87
91
  * Run `grunt` to watch sources (automatic changes compilations) and run test-server (get your browser to http://localhost:8888/)
88
92
 
89
- While current repository is, at the same time: NPM package, Ruby gem and Bower component – the main Core
93
+ While current repository is at the same time NPM package, Ruby gem and Bower component, – the main Core
90
94
  environment is Node.js.
91
95
 
92
96
  ## Credits
data/bower.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "joosy",
3
- "version": "1.2.0-alpha.14",
3
+ "version": "1.2.0-alpha.15",
4
4
  "main": "lib/joosy.js",
5
5
  "ignore": [
6
6
  "bin",
@@ -0,0 +1,592 @@
1
+
2
+
3
+ /*** src/joosy/extensions/form/form ***/
4
+
5
+ var __hasProp = {}.hasOwnProperty,
6
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
7
+
8
+ Joosy.Form = (function(_super) {
9
+ __extends(Form, _super);
10
+
11
+ Form.include(Joosy.Modules.Container);
12
+
13
+ Form.include(Joosy.Modules.Log);
14
+
15
+ Form.include(Joosy.Modules.Events);
16
+
17
+ Form.prototype.invalidationClass = 'field_with_errors';
18
+
19
+ Form.prototype.substitutions = {};
20
+
21
+ Form.prototype.elements = {
22
+ 'fields': 'input,select,textarea'
23
+ };
24
+
25
+ Form.submit = function(form, options) {
26
+ if (options == null) {
27
+ options = {};
28
+ }
29
+ form = new this(form, options);
30
+ form.container.submit();
31
+ form.unbind();
32
+ return null;
33
+ };
34
+
35
+ Form.attach = function() {
36
+ return (function(func, args, ctor) {
37
+ ctor.prototype = func.prototype;
38
+ var child = new ctor, result = func.apply(child, args);
39
+ return Object(result) === result ? result : child;
40
+ })(Joosy.Form, arguments, function(){});
41
+ };
42
+
43
+ function Form(form, options) {
44
+ var method, _ref,
45
+ _this = this;
46
+ if (options == null) {
47
+ options = {};
48
+ }
49
+ if (Object.isFunction(options)) {
50
+ this.success = options;
51
+ } else {
52
+ Object.each(options, function(key, value) {
53
+ return _this[key] = value;
54
+ });
55
+ }
56
+ this.container = $(form);
57
+ if (this.container.length === 0) {
58
+ return;
59
+ }
60
+ this.refreshElements();
61
+ this.__delegateEvents();
62
+ method = (_ref = this.container.get(0).getAttribute('method')) != null ? _ref.toLowerCase() : void 0;
63
+ if (method && !['get', 'post'].any(method)) {
64
+ this.__markMethod(method);
65
+ this.container.attr('method', 'POST');
66
+ }
67
+ this.container.ajaxForm({
68
+ dataType: 'json',
69
+ beforeSend: function() {
70
+ if (_this.__debounce.apply(_this, arguments)) {
71
+ return false;
72
+ }
73
+ _this.__before.apply(_this, arguments);
74
+ _this.__pending_request = true;
75
+ _this.debugAs(_this, 'beforeSend: pending_request = true');
76
+ return true;
77
+ },
78
+ success: function() {
79
+ _this.__pending_request = false;
80
+ _this.debugAs(_this, 'success: pending_request = false');
81
+ return _this.__success.apply(_this, arguments);
82
+ },
83
+ error: function() {
84
+ _this.__pending_request = false;
85
+ _this.debugAs(_this, 'error: pending_request = false');
86
+ return _this.__error.apply(_this, arguments);
87
+ },
88
+ xhr: function() {
89
+ var xhr;
90
+ xhr = $.ajaxSettings.xhr();
91
+ if ((xhr.upload != null) && _this.progress) {
92
+ xhr.upload.onprogress = function(event) {
93
+ if (event.lengthComputable) {
94
+ return _this.progress((event.position / event.total * 100).round(2));
95
+ }
96
+ };
97
+ }
98
+ return xhr;
99
+ }
100
+ });
101
+ if (this.resource != null) {
102
+ this.fill(this.resource, options);
103
+ delete this.resource;
104
+ }
105
+ if (this.action != null) {
106
+ this.container.attr('action', this.action);
107
+ this.container.attr('method', 'POST');
108
+ }
109
+ if (this.method != null) {
110
+ this.__markMethod(this.method);
111
+ }
112
+ }
113
+
114
+ Form.prototype.unbind = function() {
115
+ return this.container.unbind('submit').find('input:submit,input:image,button:submit').unbind('click');
116
+ };
117
+
118
+ Form.prototype.fill = function(resource, options) {
119
+ var data, filler, url,
120
+ _this = this;
121
+ if (Object.isFunction(resource.build)) {
122
+ resource = resource.build();
123
+ }
124
+ this.__resource = resource;
125
+ if ((options != null ? options.decorator : void 0) != null) {
126
+ data = options.decorator(resource.data);
127
+ } else {
128
+ data = resource.data;
129
+ }
130
+ filler = function(data, scope) {
131
+ if (data.__joosy_form_filler_lock) {
132
+ return;
133
+ }
134
+ data.__joosy_form_filler_lock = true;
135
+ Object.each(data, function(property, val) {
136
+ var entity, i, input, key, _i, _len, _ref, _results;
137
+ key = _this.concatFieldName(scope, property);
138
+ input = _this.$fields.filter("[name='" + key + "']:not(:file),[name='" + (key.underscore()) + "']:not(:file),[name='" + (key.camelize(false)) + "']:not(:file)");
139
+ if (input.length > 0) {
140
+ if (input.is(':checkbox')) {
141
+ if (val) {
142
+ input.attr('checked', 'checked');
143
+ } else {
144
+ input.removeAttr('checked');
145
+ }
146
+ } else if (input.is(':radio')) {
147
+ input.filter("[value='" + val + "']").attr('checked', 'checked');
148
+ } else {
149
+ input.val(val);
150
+ }
151
+ }
152
+ if (val instanceof Joosy.Resources.RESTCollection) {
153
+ _ref = val.data;
154
+ _results = [];
155
+ for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
156
+ entity = _ref[i];
157
+ _results.push(filler(entity.data, _this.concatFieldName(scope, "[" + property + "_attributes][" + i + "]")));
158
+ }
159
+ return _results;
160
+ } else if (val instanceof Joosy.Resources.REST) {
161
+ return filler(val.data, _this.concatFieldName(scope, "[" + property + "_attributes][0]"));
162
+ } else if (Object.isObject(val) || Object.isArray(val)) {
163
+ return filler(val, key);
164
+ } else {
165
+
166
+ }
167
+ });
168
+ return delete data.__joosy_form_filler_lock;
169
+ };
170
+ filler(data, resource.__entityName || options.resourceName);
171
+ $('input[name=_method]', this.container).remove();
172
+ if (resource.id()) {
173
+ this.__markMethod((options != null ? options.method : void 0) || 'PUT');
174
+ }
175
+ url = (options != null ? options.action : void 0) || (resource.id() != null ? resource.memberPath() : resource.collectionPath());
176
+ this.container.attr('action', url);
177
+ return this.container.attr('method', 'POST');
178
+ };
179
+
180
+ Form.prototype.submit = function() {
181
+ return this.container.submit();
182
+ };
183
+
184
+ Form.prototype.serialize = function(skipMethod) {
185
+ var data;
186
+ if (skipMethod == null) {
187
+ skipMethod = true;
188
+ }
189
+ data = this.container.serialize();
190
+ if (skipMethod) {
191
+ data = data.replace(/\&?\_method\=put/i, '');
192
+ }
193
+ return data;
194
+ };
195
+
196
+ Form.prototype.__success = function(response, status, xhr) {
197
+ var _ref;
198
+ if (xhr) {
199
+ return typeof this.success === "function" ? this.success(response) : void 0;
200
+ } else if ((200 <= (_ref = response.status) && _ref < 300)) {
201
+ return this.success(response.json);
202
+ } else {
203
+ return this.__error(response.json);
204
+ }
205
+ };
206
+
207
+ Form.prototype.__before = function(xhr, settings) {
208
+ if ((this.before == null) || this.before.apply(this, arguments) === true) {
209
+ return this.$fields.removeClass(this.invalidationClass);
210
+ }
211
+ };
212
+
213
+ Form.prototype.__error = function(data) {
214
+ var error, errors,
215
+ _this = this;
216
+ errors = (function() {
217
+ if (data.responseText) {
218
+ try {
219
+ return data = jQuery.parseJSON(data.responseText);
220
+ } catch (_error) {
221
+ error = _error;
222
+ return {};
223
+ }
224
+ } else {
225
+ return data;
226
+ }
227
+ })();
228
+ if ((this.error == null) || this.error(errors) === true) {
229
+ errors = this.__stringifyErrors(errors);
230
+ Object.each(errors, function(field, notifications) {
231
+ var input;
232
+ input = _this.findField(field).addClass(_this.invalidationClass);
233
+ return typeof _this.notification === "function" ? _this.notification(input, notifications) : void 0;
234
+ });
235
+ return errors;
236
+ }
237
+ return false;
238
+ };
239
+
240
+ Form.prototype.__debounce = function(xhr) {
241
+ this.debugAs(this, "debounce: pending_request == " + this.__pending_request);
242
+ if (this.__pending_request && this.debounce !== false) {
243
+ if (this.debounce || Joosy.Application.debounceForms) {
244
+ xhr.abort();
245
+ this.debugAs(this, "debounce: xhr aborted");
246
+ return true;
247
+ }
248
+ }
249
+ return false;
250
+ };
251
+
252
+ Form.prototype.findField = function(field) {
253
+ return this.$fields.filter("[name='" + field + "']");
254
+ };
255
+
256
+ Form.prototype.__markMethod = function(method) {
257
+ if (method == null) {
258
+ method = 'PUT';
259
+ }
260
+ method = $('<input/>', {
261
+ type: 'hidden',
262
+ name: '_method',
263
+ value: method
264
+ });
265
+ return this.container.append(method);
266
+ };
267
+
268
+ Form.prototype.__stringifyErrors = function(errors) {
269
+ var result,
270
+ _this = this;
271
+ result = {};
272
+ Object.each(errors, function(field, notifications) {
273
+ var f, name, splited, _i, _len;
274
+ if (_this.substitutions[field] != null) {
275
+ field = _this.substitutions[field];
276
+ }
277
+ if (Object.isObject(notifications) || _this.isArrayOfObjects(notifications)) {
278
+ return Object.each(_this.__foldInlineEntities(notifications), function(key, value) {
279
+ return result[field + key] = value;
280
+ });
281
+ } else {
282
+ if (field.indexOf(".") !== -1) {
283
+ splited = field.split('.');
284
+ field = splited.shift();
285
+ if (_this.resourceName || _this.__resource) {
286
+ name = _this.resourceName || _this.__resource.__entityName;
287
+ field = name + ("[" + field + "]");
288
+ }
289
+ for (_i = 0, _len = splited.length; _i < _len; _i++) {
290
+ f = splited[_i];
291
+ field += "[" + f + "]";
292
+ }
293
+ } else if (_this.resourceName || _this.__resource) {
294
+ name = _this.resourceName || _this.__resource.__entityName;
295
+ field = name + ("[" + field + "]");
296
+ }
297
+ return result[field] = notifications;
298
+ }
299
+ });
300
+ return result;
301
+ };
302
+
303
+ Form.prototype.__foldInlineEntities = function(hash, scope, result) {
304
+ var _this = this;
305
+ if (scope == null) {
306
+ scope = "";
307
+ }
308
+ if (result == null) {
309
+ result = {};
310
+ }
311
+ Object.each(hash, function(key, value) {
312
+ if (Object.isObject(value) || _this.isArrayOfObjects(value)) {
313
+ return _this.__foldInlineEntities(value, "" + scope + "[" + key + "]", result);
314
+ } else {
315
+ return result["" + scope + "[" + key + "]"] = value;
316
+ }
317
+ });
318
+ return result;
319
+ };
320
+
321
+ Form.prototype.concatFieldName = function(wrapper, name) {
322
+ var items;
323
+ items = this.splitFieldName(wrapper).concat(this.splitFieldName(name));
324
+ return "" + items[0] + "[" + (items.slice(1).join('][')) + "]";
325
+ };
326
+
327
+ Form.prototype.splitFieldName = function(name) {
328
+ var first, items;
329
+ items = name.split('][');
330
+ first = items[0].split('[');
331
+ if (first.length === 2) {
332
+ if (first[0].isBlank()) {
333
+ items.splice(0, 1, first[1]);
334
+ } else {
335
+ items.splice(0, 1, first[0], first[1]);
336
+ }
337
+ items[items.length - 1] = items[items.length - 1].split(']')[0];
338
+ }
339
+ return items;
340
+ };
341
+
342
+ Form.prototype.isArrayOfObjects = function(array) {
343
+ return Object.isArray(array) && array.every(function(elem) {
344
+ return Object.isObject(elem);
345
+ });
346
+ };
347
+
348
+ return Form;
349
+
350
+ })(Joosy.Module);
351
+
352
+
353
+ /*** src/joosy/extensions/form/helpers/form ***/
354
+
355
+ Joosy.helpers('Application', function() {
356
+ var Form, description, input,
357
+ _this = this;
358
+ description = function(resource, method, extendIds, idSuffix) {
359
+ var id;
360
+ if (Joosy.Module.hasAncestor(resource.constructor, Joosy.Resources.Base)) {
361
+ id = resource.id();
362
+ resource = resource.__entityName;
363
+ }
364
+ return {
365
+ name: resource + ("" + (method.match(/^\[.*\]$/) ? method : "[" + method + "]")),
366
+ id: resource + (id && extendIds ? '_' + id : '') + ("_" + (method.parameterize().underscore())) + (idSuffix ? '_' + idSuffix : '')
367
+ };
368
+ };
369
+ input = function(type, resource, method, options) {
370
+ var d;
371
+ if (options == null) {
372
+ options = {};
373
+ }
374
+ d = description(resource, method, options.extendIds, options.idSuffix);
375
+ delete options.extendIds;
376
+ delete options.idSuffix;
377
+ return _this.tag('input', Joosy.Module.merge({
378
+ type: type,
379
+ name: d.name,
380
+ id: d.id
381
+ }, options));
382
+ };
383
+ Form = (function() {
384
+ function Form(context, resource, options) {
385
+ this.context = context;
386
+ this.resource = resource;
387
+ this.options = options;
388
+ }
389
+
390
+ Form.prototype.label = function(method, options, content) {
391
+ if (options == null) {
392
+ options = {};
393
+ }
394
+ if (content == null) {
395
+ content = '';
396
+ }
397
+ if (!Object.isObject(options)) {
398
+ content = options;
399
+ options = {};
400
+ }
401
+ return this.context.label(this.resource, method, Joosy.Module.merge({
402
+ extendIds: this.options.extendIds
403
+ }, options), content);
404
+ };
405
+
406
+ Form.prototype.radioButton = function(method, tagValue, options) {
407
+ if (options == null) {
408
+ options = {};
409
+ }
410
+ return this.context.radioButton(this.resource, method, tagValue, Joosy.Module.merge({
411
+ extendIds: this.options.extendIds
412
+ }, options));
413
+ };
414
+
415
+ Form.prototype.textArea = function(method, options) {
416
+ if (options == null) {
417
+ options = {};
418
+ }
419
+ return this.context.textArea(this.resource, method, Joosy.Module.merge({
420
+ extendIds: this.options.extendIds
421
+ }, options));
422
+ };
423
+
424
+ Form.prototype.checkBox = function(method, options, checkedValue, uncheckedValue) {
425
+ if (options == null) {
426
+ options = {};
427
+ }
428
+ if (checkedValue == null) {
429
+ checkedValue = 1;
430
+ }
431
+ if (uncheckedValue == null) {
432
+ uncheckedValue = 0;
433
+ }
434
+ return this.context.checkBox(this.resource, method, Joosy.Module.merge({
435
+ extendIds: this.options.extendIds
436
+ }, options), checkedValue, uncheckedValue);
437
+ };
438
+
439
+ Form.prototype.select = function(method, options, htmlOptions) {
440
+ if (options == null) {
441
+ options = {};
442
+ }
443
+ if (htmlOptions == null) {
444
+ htmlOptions = {};
445
+ }
446
+ return this.context.select(this.resource, method, options, Joosy.Module.merge({
447
+ extendIds: this.options.extendIds
448
+ }, htmlOptions));
449
+ };
450
+
451
+ return Form;
452
+
453
+ })();
454
+ ['text', 'file', 'hidden', 'password'].each(function(type) {
455
+ return Form.prototype[type + 'Field'] = function(method, options) {
456
+ if (options == null) {
457
+ options = {};
458
+ }
459
+ return this.context[type + 'Field'](this.resource, method, Joosy.Module.merge({
460
+ extendIds: this.options.extendIds
461
+ }, options));
462
+ };
463
+ });
464
+ this.formFor = function(resource, options, block) {
465
+ var form, uuid;
466
+ if (options == null) {
467
+ options = {};
468
+ }
469
+ if (Object.isFunction(options)) {
470
+ block = options;
471
+ options = {};
472
+ }
473
+ uuid = Joosy.uuid();
474
+ form = this.tag('form', Joosy.Module.merge(options.html || {}, {
475
+ id: uuid
476
+ }), block != null ? block.call(this, new Form(this, resource, options)) : void 0);
477
+ if (typeof this.onRefresh === "function") {
478
+ this.onRefresh(function() {
479
+ return Joosy.Form.attach('#' + uuid, Joosy.Module.merge(options, {
480
+ resource: resource
481
+ }));
482
+ });
483
+ }
484
+ return form;
485
+ };
486
+ this.label = function(resource, method, options, content) {
487
+ var d;
488
+ if (options == null) {
489
+ options = {};
490
+ }
491
+ if (content == null) {
492
+ content = '';
493
+ }
494
+ if (!Object.isObject(options)) {
495
+ content = options;
496
+ options = {};
497
+ }
498
+ d = description(resource, method, options.extendIds);
499
+ delete options.extendIds;
500
+ return this.tag('label', Joosy.Module.merge(options, {
501
+ "for": d.id
502
+ }), content);
503
+ };
504
+ ['text', 'file', 'hidden', 'password'].each(function(type) {
505
+ return _this[type + 'Field'] = function(resource, method, options) {
506
+ if (options == null) {
507
+ options = {};
508
+ }
509
+ return input(type, resource, method, options);
510
+ };
511
+ });
512
+ this.radioButton = function(resource, method, tagValue, options) {
513
+ if (options == null) {
514
+ options = {};
515
+ }
516
+ return input('radio', resource, method, Joosy.Module.merge({
517
+ value: tagValue,
518
+ idSuffix: tagValue
519
+ }, options));
520
+ };
521
+ this.checkBox = function(resource, method, options, checkedValue, uncheckedValue) {
522
+ var box, spy;
523
+ if (options == null) {
524
+ options = {};
525
+ }
526
+ if (checkedValue == null) {
527
+ checkedValue = 1;
528
+ }
529
+ if (uncheckedValue == null) {
530
+ uncheckedValue = 0;
531
+ }
532
+ spy = this.tag('input', Joosy.Module.merge({
533
+ name: description(resource, method).name,
534
+ value: uncheckedValue,
535
+ type: 'hidden'
536
+ }));
537
+ box = input('checkbox', resource, method, Joosy.Module.merge({
538
+ value: checkedValue
539
+ }, options));
540
+ return spy + box;
541
+ };
542
+ this.select = function(resource, method, options, htmlOptions) {
543
+ var extendIds, key, opts, val,
544
+ _this = this;
545
+ if (Object.isObject(options)) {
546
+ opts = [];
547
+ for (key in options) {
548
+ val = options[key];
549
+ opts.push([val, key]);
550
+ }
551
+ } else {
552
+ opts = options;
553
+ }
554
+ if (htmlOptions.includeBlank) {
555
+ delete htmlOptions.includeBlank;
556
+ opts.unshift(['', '']);
557
+ }
558
+ opts = opts.reduce(function(str, vals) {
559
+ var params;
560
+ params = Object.isArray(vals) ? [
561
+ 'option', {
562
+ value: vals[1]
563
+ }, vals[0]
564
+ ] : ['option', {}, vals];
565
+ if (htmlOptions.value === (Object.isArray(vals) ? vals[1] : vals)) {
566
+ params[1].selected = 'selected';
567
+ }
568
+ return str += _this.tag.apply(_this, params);
569
+ }, '');
570
+ extendIds = htmlOptions.extendIds;
571
+ delete htmlOptions.value;
572
+ delete htmlOptions.extendIds;
573
+ return this.tag('select', Joosy.Module.merge(description(resource, method, extendIds), htmlOptions), opts);
574
+ };
575
+ return this.textArea = function(resource, method, options) {
576
+ var extendIds, value;
577
+ if (options == null) {
578
+ options = {};
579
+ }
580
+ value = options.value;
581
+ extendIds = options.extendIds;
582
+ delete options.value;
583
+ delete options.extendIds;
584
+ return this.tag('textarea', Joosy.Module.merge(description(resource, method, extendIds), options), value);
585
+ };
586
+ });
587
+
588
+
589
+ /*** src/joosy/extensions/form/index ***/
590
+
591
+
592
+ ;