extjs-mvc 0.3.10 → 0.4.0.a

Sign up to get free protection for your applications and to get access to all the features.
Files changed (204) hide show
  1. data/LICENSE +1 -1
  2. data/README.rdoc +5 -173
  3. data/Rakefile +18 -20
  4. data/VERSION +1 -1
  5. data/bin/xmvc +13 -0
  6. data/lib/extjs-mvc/README +20 -0
  7. data/lib/extjs-mvc/builder.rb +83 -0
  8. data/lib/extjs-mvc/builders/all_builder.rb +15 -0
  9. data/lib/extjs-mvc/builders/app_builder.rb +36 -0
  10. data/lib/extjs-mvc/builders/base.rb +138 -0
  11. data/lib/extjs-mvc/builders/css_builder.rb +36 -0
  12. data/lib/extjs-mvc/builders/docs_builder.rb +20 -0
  13. data/lib/extjs-mvc/builders/mvc_builder.rb +33 -0
  14. data/lib/extjs-mvc/builders/plugin_builder.rb +53 -0
  15. data/lib/extjs-mvc/cli.rb +52 -0
  16. data/lib/extjs-mvc/generator.rb +79 -0
  17. data/lib/extjs-mvc/generators/app.rb +57 -0
  18. data/lib/extjs-mvc/generators/base.rb +53 -0
  19. data/lib/extjs-mvc/generators/controller.rb +41 -0
  20. data/lib/extjs-mvc/generators/model.rb +41 -0
  21. data/lib/extjs-mvc/generators/scaffold.rb +17 -0
  22. data/lib/extjs-mvc/generators/templates/Controller.js +17 -0
  23. data/lib/extjs-mvc/generators/templates/Model.js +9 -0
  24. data/lib/extjs-mvc/generators/templates/ModelSpec.js +12 -0
  25. data/lib/extjs-mvc/generators/templates/View.js +16 -0
  26. data/lib/extjs-mvc/generators/templates/_Action.js +7 -0
  27. data/lib/extjs-mvc/generators/templates/app/README.rdoc +152 -0
  28. data/lib/extjs-mvc/generators/templates/app/app/App.js +64 -0
  29. data/lib/extjs-mvc/generators/templates/app/app/controllers/ApplicationController.js +10 -0
  30. data/lib/extjs-mvc/generators/templates/app/app/controllers/HomeController.js +10 -0
  31. data/lib/extjs-mvc/generators/templates/app/app/views/home/Index.js +17 -0
  32. data/lib/extjs-mvc/generators/templates/app/app/views/layout/Menu.js +23 -0
  33. data/lib/extjs-mvc/generators/templates/app/config/application.js +1 -0
  34. data/lib/extjs-mvc/generators/templates/app/config/boot.js +67 -0
  35. data/lib/extjs-mvc/generators/templates/app/config/build.xml +77 -0
  36. data/lib/extjs-mvc/generators/templates/app/config/database.js +4 -0
  37. data/lib/extjs-mvc/generators/templates/app/config/environment.json +58 -0
  38. data/lib/extjs-mvc/generators/templates/app/config/environments/development.json +1 -0
  39. data/lib/extjs-mvc/generators/templates/app/config/environments/production.json +4 -0
  40. data/lib/extjs-mvc/generators/templates/app/config/routes.js +27 -0
  41. data/lib/extjs-mvc/generators/templates/app/config/settings.yml +3 -0
  42. data/lib/extjs-mvc/generators/templates/app/public/index.html +19 -0
  43. data/lib/extjs-mvc/generators/templates/app/public/stylesheets/ext-mvc-all.css +49 -0
  44. data/{test/active_record_test.rb → lib/extjs-mvc/generators/templates/app/spec/SpecHelper.js} +0 -0
  45. data/lib/extjs-mvc/generators/templates/app/spec/index.html +66 -0
  46. data/lib/extjs-mvc/generators/templates/app/vendor/screw-unit/EXAMPLE.html +68 -0
  47. data/lib/extjs-mvc/generators/templates/app/vendor/screw-unit/LICENSE +22 -0
  48. data/lib/extjs-mvc/generators/templates/app/vendor/screw-unit/README.markdown +307 -0
  49. data/lib/extjs-mvc/generators/templates/app/vendor/screw-unit/lib/jquery-1.2.3.js +3408 -0
  50. data/lib/extjs-mvc/generators/templates/app/vendor/screw-unit/lib/jquery.fn.js +29 -0
  51. data/lib/extjs-mvc/generators/templates/app/vendor/screw-unit/lib/jquery.print.js +108 -0
  52. data/lib/extjs-mvc/generators/templates/app/vendor/screw-unit/lib/screw.assets.js +36 -0
  53. data/lib/extjs-mvc/generators/templates/app/vendor/screw-unit/lib/screw.behaviors.js +91 -0
  54. data/lib/extjs-mvc/generators/templates/app/vendor/screw-unit/lib/screw.builder.js +80 -0
  55. data/lib/extjs-mvc/generators/templates/app/vendor/screw-unit/lib/screw.css +90 -0
  56. data/lib/extjs-mvc/generators/templates/app/vendor/screw-unit/lib/screw.events.js +42 -0
  57. data/lib/extjs-mvc/generators/templates/app/vendor/screw-unit/lib/screw.matchers.js +145 -0
  58. data/lib/extjs-mvc/generators/templates/app/vendor/screw-unit/lib/screw.server.js +21 -0
  59. data/lib/extjs-mvc/generators/templates/app/vendor/screw-unit/spec/behaviors_spec.js +178 -0
  60. data/lib/extjs-mvc/generators/templates/app/vendor/screw-unit/spec/matchers_spec.js +237 -0
  61. data/lib/extjs-mvc/generators/templates/app/vendor/screw-unit/spec/print_spec.js +119 -0
  62. data/{test/controller_test.rb → lib/extjs-mvc/generators/templates/app/vendor/screw-unit/spec/spec_helper.js} +0 -0
  63. data/lib/extjs-mvc/generators/templates/app/vendor/screw-unit/spec/suite.html +18 -0
  64. data/lib/extjs-mvc/generators/templates/scaffold/ScaffoldController.js +18 -0
  65. data/lib/extjs-mvc/generators/view.rb +29 -0
  66. data/lib/extjs-mvc/plugin.rb +105 -0
  67. data/lib/extjs-mvc/scripts.rb +15 -0
  68. data/lib/extjs-mvc/settings.rb +75 -0
  69. data/lib/extjs-mvc/setup.rb +5 -0
  70. data/lib/extjs-mvc/stats.rb +241 -0
  71. data/lib/extjs-mvc/test.rb +11 -0
  72. data/lib/extjs-mvc/testserver.ru +95 -0
  73. data/lib/extjs-mvc/ui.rb +58 -0
  74. data/lib/extjs-mvc/update.rb +73 -0
  75. data/lib/extjs-mvc.rb +70 -32
  76. data/lib/js/App.js +219 -0
  77. data/lib/js/MVC.js +260 -0
  78. data/lib/js/Presenter.js +52 -0
  79. data/lib/js/README.rdoc +69 -0
  80. data/lib/js/build +21 -0
  81. data/lib/js/controller/Controller.js +278 -0
  82. data/lib/js/controller/CrudController.js +460 -0
  83. data/lib/js/lib/Array.js +26 -0
  84. data/lib/js/lib/Booter.js +415 -0
  85. data/lib/js/lib/ClassManager.js +191 -0
  86. data/lib/js/lib/ControllerClassManager.js +95 -0
  87. data/lib/js/lib/Dependencies.js +44 -0
  88. data/lib/js/lib/DispatchMatcher.js +98 -0
  89. data/lib/js/lib/Dispatcher.js +129 -0
  90. data/lib/js/lib/Environment.js +43 -0
  91. data/lib/js/lib/Inflector.js +138 -0
  92. data/lib/js/lib/ModelClassManager.js +19 -0
  93. data/lib/js/lib/Route.js +139 -0
  94. data/lib/js/lib/Router.js +282 -0
  95. data/lib/js/lib/String.js +94 -0
  96. data/lib/js/lib/ViewClassManager.js +229 -0
  97. data/lib/js/lib/notes.txt +32 -0
  98. data/lib/js/model/AdapterManager.js +30 -0
  99. data/lib/js/model/Association.js +26 -0
  100. data/lib/js/model/Base.js +63 -0
  101. data/lib/js/model/BelongsToAssociation.js +116 -0
  102. data/lib/js/model/Cache.js +131 -0
  103. data/lib/js/model/HasManyAssociation.js +160 -0
  104. data/lib/js/model/Model.js +331 -0
  105. data/lib/js/model/UrlBuilder.js +106 -0
  106. data/lib/js/model/adapters/AbstractAdapter.js +296 -0
  107. data/lib/js/model/adapters/MemoryAdapter.js +103 -0
  108. data/lib/js/model/adapters/RESTAdapter.js +345 -0
  109. data/lib/js/model/adapters/RESTJSONAdapter.js +68 -0
  110. data/lib/js/model/adapters/notes.txt +42 -0
  111. data/lib/js/model/associations/Association.js +192 -0
  112. data/lib/js/model/associations/notes.txt +87 -0
  113. data/lib/js/model/validations/Errors.js +136 -0
  114. data/lib/js/model/validations/Plugin.js +139 -0
  115. data/lib/js/model/validations/Validations.js +276 -0
  116. data/lib/js/notes/Charts.graffle +0 -0
  117. data/lib/js/overrides/Ext.Component.js +21 -0
  118. data/lib/js/overrides/Ext.extend.js +142 -0
  119. data/lib/js/spec/Array.spec.js +15 -0
  120. data/lib/js/spec/ExtMVC.spec.js +65 -0
  121. data/lib/js/spec/Model.spec.js +370 -0
  122. data/lib/js/spec/OS.spec.js +83 -0
  123. data/lib/js/spec/Router.spec.js +99 -0
  124. data/lib/js/spec/SpecHelper.js +106 -0
  125. data/lib/js/spec/String.spec.js +83 -0
  126. data/lib/js/spec/model/AbstractAdapter.spec.js +49 -0
  127. data/lib/js/spec/model/Associations.spec.js +99 -0
  128. data/lib/js/spec/model/Cache.spec.js +5 -0
  129. data/lib/js/spec/model/RESTAdapter.spec.js +19 -0
  130. data/lib/js/spec/model/ValidationErrors.spec.js +64 -0
  131. data/lib/js/spec/model/Validations.spec.js +166 -0
  132. data/lib/js/spec/model/ValidationsPlugin.spec.js +108 -0
  133. data/lib/js/spec/suite.html +60 -0
  134. data/lib/js/specs-old/JSSpec.css +216 -0
  135. data/lib/js/specs-old/JSSpec.js +1512 -0
  136. data/lib/js/specs-old/all.html +66 -0
  137. data/lib/js/specs-old/base.js +14 -0
  138. data/lib/js/specs-old/controller.js +17 -0
  139. data/lib/js/specs-old/diff_match_patch.js +1 -0
  140. data/lib/js/specs-old/model.js +70 -0
  141. data/lib/js/specs-old/route.js +38 -0
  142. data/lib/js/specs-old/router.js +59 -0
  143. data/lib/js/specs-old/string.js +22 -0
  144. data/lib/js/testrunner/JSpecFormatter.js +111 -0
  145. data/lib/js/testrunner/TestClient.js +181 -0
  146. data/lib/js/testrunner/TestGrid.js +351 -0
  147. data/lib/js/testrunner/TestRunner.js +110 -0
  148. data/lib/js/testrunner/TestViewport.js +94 -0
  149. data/lib/js/vendor/screw-unit/EXAMPLE.html +68 -0
  150. data/lib/js/vendor/screw-unit/LICENSE +22 -0
  151. data/lib/js/vendor/screw-unit/README.markdown +307 -0
  152. data/lib/js/vendor/screw-unit/lib/jquery-1.2.3.js +3408 -0
  153. data/lib/js/vendor/screw-unit/lib/jquery.fn.js +29 -0
  154. data/lib/js/vendor/screw-unit/lib/jquery.print.js +108 -0
  155. data/lib/js/vendor/screw-unit/lib/screw.assets.js +36 -0
  156. data/lib/js/vendor/screw-unit/lib/screw.behaviors.js +91 -0
  157. data/lib/js/vendor/screw-unit/lib/screw.builder.js +80 -0
  158. data/lib/js/vendor/screw-unit/lib/screw.css +91 -0
  159. data/lib/js/vendor/screw-unit/lib/screw.events.js +42 -0
  160. data/lib/js/vendor/screw-unit/lib/screw.matchers.js +145 -0
  161. data/lib/js/vendor/screw-unit/lib/screw.server.js +21 -0
  162. data/lib/js/vendor/screw-unit/spec/behaviors_spec.js +178 -0
  163. data/lib/js/vendor/screw-unit/spec/matchers_spec.js +237 -0
  164. data/lib/js/vendor/screw-unit/spec/print_spec.js +119 -0
  165. data/{test/data_mapper_test.rb → lib/js/vendor/screw-unit/spec/spec_helper.js} +0 -0
  166. data/lib/js/vendor/screw-unit/spec/suite.html +18 -0
  167. data/lib/js/view/FormWindow.js +184 -0
  168. data/lib/js/view/HasManyEditorGridPanel.js +211 -0
  169. data/lib/js/view/scaffold/Edit.js +46 -0
  170. data/lib/js/view/scaffold/Index.js +561 -0
  171. data/lib/js/view/scaffold/New.js +20 -0
  172. data/lib/js/view/scaffold/ScaffoldFormPanel.js +255 -0
  173. data/test/helper.rb +10 -0
  174. data/test/test_extjs-mvc-gem.rb +7 -0
  175. metadata +232 -56
  176. data/README +0 -12
  177. data/lib/controller/controller.rb +0 -28
  178. data/lib/core_ext/array/extract_options.rb +0 -15
  179. data/lib/extjs/component.rb +0 -71
  180. data/lib/extjs/data/store.rb +0 -131
  181. data/lib/helpers/component.rb +0 -37
  182. data/lib/helpers/store.rb +0 -7
  183. data/lib/model/active_record.rb +0 -89
  184. data/lib/model/base.rb +0 -370
  185. data/lib/model/data_mapper.rb +0 -66
  186. data/lib/model/mongo_mapper.rb +0 -64
  187. data/lib/test/macros.rb +0 -20
  188. data/test/app/config/application.rb +0 -70
  189. data/test/app/config/database.yml +0 -3
  190. data/test/app/db/schema.rb +0 -75
  191. data/test/app/models/active_record/address.rb +0 -4
  192. data/test/app/models/active_record/data_type.rb +0 -3
  193. data/test/app/models/active_record/group.rb +0 -4
  194. data/test/app/models/active_record/house.rb +0 -4
  195. data/test/app/models/active_record/location.rb +0 -5
  196. data/test/app/models/active_record/person.rb +0 -4
  197. data/test/app/models/active_record/user.rb +0 -6
  198. data/test/app/models/active_record/user_group.rb +0 -4
  199. data/test/component_test.rb +0 -15
  200. data/test/debug.log +0 -2969
  201. data/test/model_test.rb +0 -526
  202. data/test/mongo_mapper_test.rb +0 -0
  203. data/test/store_test.rb +0 -0
  204. data/test/test_helper.rb +0 -32
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Method Collection Individual
3
+ * create yes yes (but different)
4
+ * build yes yes
5
+ * find yes no
6
+ * loaded yes yes (but different)
7
+ * count yes no
8
+ * destroy yes yes (but different)
9
+ */
10
+
11
+ /**
12
+ * Method HasMany BelongsTo
13
+ * create yes no
14
+ * build yes no
15
+ * destroy yes yes
16
+ * find yes yes
17
+ */
18
+
19
+ /**
20
+ * User.find(1, {
21
+ * success: function(user) {
22
+ * //on belongs to associations
23
+ * user.group.destroy();
24
+ * user.group.find({success: function(group) {}});
25
+ * user.group.set(someGroupInstance); //someGroupInstance must be a saved record (e.g. have an ID)
26
+ *
27
+ * //on has many associations
28
+ * user.posts.destroy(1);
29
+ * user.posts.find({id: 1, conditions: [{field: 'title', comparator: '=', value: 'some title'}]}, options);
30
+ * user.posts.create(data, options)
31
+ * user.posts.build(data)
32
+ * }
33
+ * };
34
+ */
35
+
36
+ // ExtMVC.Model.define('User', {
37
+ // fields: [],
38
+ // belongsTo: "Group",
39
+ // hasMany: [{
40
+ // name: 'posts',
41
+ // className: 'Post',
42
+ // foreignKey: 'user_id',
43
+ //
44
+ // extend: {
45
+ // //some functions
46
+ // }
47
+ // }]
48
+ // });
49
+ //
50
+ // user.posts.find(1, {
51
+ // success: function() {},
52
+ // failure: function() {}
53
+ // });
54
+ //
55
+ // user.posts.create({}, {
56
+ // success: function() {},
57
+ // failure: function() {}
58
+ // });
59
+ //
60
+ // user.posts.build({});
61
+ //
62
+ // user.posts.loaded();
63
+ // user.posts.count();
64
+ // user.posts.destroy(1);
65
+ //
66
+ // ExtMVC.Model.define('Post', {
67
+ // fields: [],
68
+ // belongsTo: [{
69
+ // name: 'user',
70
+ // className: 'User',
71
+ // foreignKey: 'user_id',
72
+ //
73
+ // extend: {
74
+ // //some functions
75
+ // }
76
+ // }],
77
+ // hasMany: 'Comment'
78
+ // });
79
+ //
80
+ // post.user.find();
81
+ // post.user.loaded();
82
+ // post.user.destroy();
83
+ //
84
+ // ExtMVC.Model.define('Comment', {
85
+ // fields: [],
86
+ // belongsTo: "Post"
87
+ // });
@@ -0,0 +1,136 @@
1
+ /**
2
+ * @class ExtMVC.model.plugin.validation
3
+ * @ignore
4
+ */
5
+
6
+ /**
7
+ * @class ExtMVC.model.plugin.validation.Errors
8
+ * Simple class to collect validation errors on a model and return them in various formats. Usage:
9
+ <pre><code>
10
+ ExtMVC.model.define("SomeModel", {
11
+ fields: [
12
+ {name: 'title', type: 'string'},
13
+ {name: 'price', type: 'int'},
14
+ {name: 'stock', type: 'int'},
15
+ {name: 'colour', type: 'string'}
16
+ ],
17
+
18
+ validatesPresenceOf : ["title", "price"],
19
+ validatesLengthOf : {field: 'title', minimum: 3, maximum: 12}
20
+ });
21
+
22
+ var s = new SomeModel({title: 'Some really long title'});
23
+ s.errors; //returns this Errors object
24
+ s.isValid(); //returns false, same as calling s.errors.isValid()
25
+
26
+ //manually add a validation error on the title field
27
+ s.errors.add('title', 'has an problem of some kind');
28
+
29
+ this.errors.forField('title'); //returns an array of problems with the title field
30
+
31
+ this.errors.forForm(); //returns an object suitable for marking fields invalid on a form
32
+ </code></pre>
33
+ */
34
+ ExtMVC.model.plugin.validation.Errors = function() {
35
+ /**
36
+ * @property errors
37
+ * @type Object
38
+ * Object containing all errors attached to this model. This is READ ONLY - do not interact with directly
39
+ */
40
+ this.all = {};
41
+ };
42
+
43
+ ExtMVC.model.plugin.validation.Errors.prototype = {
44
+
45
+ /**
46
+ * Returns an errors object suitable for applying to a form via BasicForm's markInvalid() method
47
+ * @return {Object} An object with field IDs as keys and formatted error strings as values
48
+ */
49
+ forForm: function() {
50
+ var formErrors = {};
51
+ for (key in this.all) {
52
+ formErrors[key] = this.forField(key, true);
53
+ }
54
+
55
+ return formErrors;
56
+ },
57
+
58
+ /**
59
+ * @property multipleErrorConnector
60
+ * @type String
61
+ * The string to use when connecting more than one error (defaults to 'and')
62
+ */
63
+ multipleErrorConnector: 'and',
64
+
65
+ /**
66
+ * Clears out all errors
67
+ */
68
+ clear: function() {
69
+ this.all = {};
70
+ },
71
+
72
+ /**
73
+ * Adds an error to a particular field
74
+ * @param {String} field The field to add an error onto
75
+ * @param {String} error The error message
76
+ */
77
+ add: function(field, error) {
78
+ this.all[field] = this.all[field] || [];
79
+ this.all[field].push(error);
80
+ },
81
+
82
+ /**
83
+ * Returns an array of all errors for the given field. Pass true as a second argument to
84
+ * return a human-readable string, e.g.:
85
+ <pre><code>
86
+ forField('title'); // ['must be present', 'is too short']
87
+ forField('title', true); // 'must be present and is too short'
88
+ </code></pre>
89
+ * @param {String} field The field to find errors for
90
+ * @param {Boolean} humanize True to turn the errors array into a human-readable string (defaults to false)
91
+ * @return {Array|String} An array of errors for this field, or a string
92
+ */
93
+ forField: function(field, humanize) {
94
+ humanize = humanize || false;
95
+ var errs = this.all[field] || [];
96
+
97
+ return humanize ? errs.toSentence(this.multipleErrorConnector) : errs;
98
+ },
99
+
100
+ /**
101
+ * Returns true if this model currently has no validation errors
102
+ * @return {Boolean} True if this model is currently valid
103
+ */
104
+ isValid: function(paramName) {
105
+ for (key in this.all) {return false;}
106
+
107
+ return true;
108
+ },
109
+
110
+ /**
111
+ * Parses server response to a failed save, adding each error message to the appropriate field. Override to provide
112
+ * an implementation for your own server responses. The default implementation accepts a response like this:
113
+ * {errors: [['some_field', 'some error regarding some_field'], ['another_field', 'another error']]}
114
+ * @param {Object/String} serverErrors A errors object returned by server-side validations. If this is a string it will
115
+ * @param {Boolean} preserveErrors False to clear all errors before adding errors from server (defaults to false)
116
+ * automatically be turned into an object via Ext.decode
117
+ */
118
+ readServerErrors: function(serverErrors, preserveErrors) {
119
+ var serverErrors = serverErrors || {};
120
+
121
+ //remove any existing errors unless instructed to preserve them
122
+ if (preserveErrors !== true) {this.clearErrors();}
123
+
124
+ //make sure we're dealing with an object
125
+ if (typeof(serverErrors) == 'string') {
126
+ serverErrors = Ext.decode(serverErrors);
127
+ };
128
+
129
+ var rawErrors = serverErrors.errors;
130
+ if (rawErrors) {
131
+ for (var i=0; i < rawErrors.length; i++) {
132
+ this.all.push(rawErrors[i]);
133
+ };
134
+ };
135
+ }
136
+ };
@@ -0,0 +1,139 @@
1
+ /**
2
+ * This is the Validation plugin definition, which mixes in validation.Errors
3
+ * and some other functions into a model prototype
4
+ * @ignore
5
+ */
6
+
7
+ /**
8
+ * Overrides Ext.data.Record's isValid() function.
9
+ * We apply this to Record's prototype as there is no need to define it per model or instance
10
+ * @ignore
11
+ */
12
+ Ext.apply(Ext.data.Record.prototype, {
13
+ isValid: function() {
14
+ if (this.validations) {
15
+ if (!this.errors) this.errors = new ExtMVC.model.plugin.validations.Errors();
16
+
17
+ this.errors.clear();
18
+
19
+ //test each validation, add to errors if any fail
20
+ Ext.each(this.validations, function(validation) {
21
+ if (!validation.isValid(this)) {
22
+ this.errors.add(validation.field, validation.message);
23
+ };
24
+ }, this);
25
+ };
26
+
27
+ return this.errors.isValid();
28
+ }
29
+ });
30
+
31
+ /**
32
+ * @ignore
33
+ * FIXME: This is possibly the most horrendous hack ever. I'm so sorry :(
34
+ *
35
+ * The basic problem is that we need to add an errors object to every Record instance,
36
+ * which means we need to hook into the constructor somehow. Sadly everything I tried
37
+ * to overload the constructor directly failed, so this horrific hack has been done instead
38
+ */
39
+ (function() {
40
+ var oldPrototype = Ext.data.Record.prototype,
41
+ oldConstructor = Ext.data.Record,
42
+ oldFunctionMethods = {};
43
+
44
+ for (var method in Ext.data.Record) {
45
+ oldFunctionMethods[method] = Ext.data.Record[method];
46
+ }
47
+
48
+ Ext.data.Record = function(data, id) {
49
+ oldConstructor.apply(this, arguments);
50
+
51
+ this.errors = new ExtMVC.model.plugin.validation.Errors();
52
+ };
53
+
54
+ for (var method in oldFunctionMethods) {
55
+ Ext.data.Record[method] = oldFunctionMethods[method];
56
+ }
57
+ })();
58
+ /**
59
+ * Again, I'm really sorry :(
60
+ * @ignore
61
+ */
62
+
63
+ /**
64
+ * @class ExtMVC.model.plugin.validation.Plugin
65
+ */
66
+ ExtMVC.model.plugin.validation.Plugin = {
67
+ /**
68
+ * Initializes this plugin for a given model. This is called every time a model is *created*
69
+ * via ExtMVC.model.create, not when a model object is *instantiated*
70
+ * @param {ExtMVC.model} model The model to initialize the plugin for
71
+ */
72
+ initialize: function(model) {
73
+ this.model = model;
74
+
75
+ Ext.apply(model.prototype, {
76
+ /**
77
+ * @property validations
78
+ * @type Array
79
+ * An array of all validations performed on this model
80
+ */
81
+ validations: this.parseValidations()
82
+ });
83
+ },
84
+
85
+ /**
86
+ * Parses a defined model's prototype for validation declarations and creates validation instances
87
+ * @return {Array} An Array of validation objects
88
+ */
89
+ parseValidations: function() {
90
+ var validations = [];
91
+
92
+ for (var validation in ExtMVC.model.plugin.validation) {
93
+ if (/^validate/.test(validation.toLowerCase())) {
94
+
95
+ //for each validation type defined on ExtMVC.model.plugin.validation, check to see if we are using
96
+ //it in on our model
97
+ for (var modelKey in this.model.prototype) {
98
+ if (modelKey.toLowerCase() == validation.toLowerCase()) {
99
+ //this validation is being used by the model, so add it now
100
+ var validationConstructor = ExtMVC.model.plugin.validation[validation],
101
+ validationOptions = this.model.prototype[modelKey];
102
+
103
+ if (!Ext.isArray(validationOptions)) {
104
+ validationOptions = [validationOptions];
105
+ };
106
+
107
+ Ext.each(validationOptions, function(options) {
108
+ validations.push(this.buildValidation(validationConstructor, options));
109
+ }, this);
110
+ };
111
+ }
112
+ };
113
+ }
114
+
115
+ return validations;
116
+ },
117
+
118
+ /**
119
+ * Creates a new Validation object based on the passed constructor and options
120
+ * @param {Function} validation The validation constructor function
121
+ * @param {Object|String} options A fieldname string, or config object
122
+ * @return {ExtMVC.model.plugin.validation.AbstractValidation} The validation instance
123
+ */
124
+ buildValidation: function(validation, options) {
125
+ var field, config = {};
126
+
127
+ if (typeof options == 'string') {
128
+ field = options;
129
+ } else {
130
+ field = options.field;
131
+ delete options.field;
132
+ config = options;
133
+ }
134
+
135
+ return new validation(this.model, field, config);
136
+ }
137
+ };
138
+
139
+ ExtMVC.model.addPlugin(ExtMVC.model.plugin.validation.Plugin);
@@ -0,0 +1,276 @@
1
+ Ext.ns('ExtMVC.model.plugin.validation');
2
+
3
+ /**
4
+ * @ignore
5
+ * The Validation classes themselves are defined here.
6
+ * Subclass ExtMVC.model.plugin.validation.AbstractValidation to create your own validations
7
+ */
8
+
9
+ /**
10
+ * @class ExtMVC.model.plugin.validation.AbstractValidation
11
+ * Base class for all validations - not used directly, but any of the following may be used:
12
+ <pre><code>
13
+ ExtMVC.model.define("SomeModel", {
14
+ fields: [
15
+ {name: 'title', type: 'string'},
16
+ {name: 'price', type: 'int'},
17
+ {name: 'stock', type: 'int'},
18
+ {name: 'gender', type: 'string'},
19
+ {name: 'colour', type: 'string'}
20
+ ],
21
+
22
+ validatesPresenceOf : ["title", "price"],
23
+ validatesLengthOf : {field: 'title', minimum: 3, maximum: 12},
24
+
25
+ validatesInclusionOf: {field: 'gender', allowed : ["Male", "Female"]},
26
+ validatesExclusionOf: {field: 'colour', disallowed: ["Red"]},
27
+ validatesFormatOf : {field: 'email', regex: /someRegex/},
28
+
29
+ validatesNumericalityOf: "stock"
30
+ });
31
+ </code></pre>
32
+ *
33
+ * Most validations will allow an array to be passed to set the validation up on more than one field (e.g.
34
+ * see the validatesPresenceOf declaration above). If only a string is provided it is assume to be the field name.
35
+ * The following are all equivalent:
36
+ <pre><code>
37
+ validatesPresenceOf: "title"
38
+ validatesPresenceOf: ["title"]
39
+ validatesPresenceOf: {field: "title"}
40
+ validatesPresenceOf: [{field: "title"}]
41
+ </code></pre>
42
+ *
43
+ * <h2>Running validations</h2>
44
+ * This plugin overrides ExtMVC.model.Base's usual isValid() function to provide feedback from the validations:
45
+ *
46
+ <pre><code>
47
+ var user = new SomeModel({title: "A really long title", colour: "Blue"});
48
+ user.isValid(); //returns false if any of the validations failed
49
+ user.errors; //returns an {@link ExtMVC.model.plugin.validation.Errors Errors} object
50
+ </code></pre>
51
+ */
52
+ ExtMVC.model.plugin.validation.AbstractValidation = function(ownerClass, field, config) {
53
+ this.ownerClass = ownerClass;
54
+ this.field = field;
55
+
56
+ Ext.apply(this, config);
57
+ };
58
+
59
+ ExtMVC.model.plugin.validation.AbstractValidation.prototype = {
60
+ /**
61
+ * Returns the current value of the field to which this validation applies
62
+ * @param {ExtMVC.model.Base} instance The model instance to get the value from
63
+ * @return {Mixed} The current value of the field
64
+ */
65
+ getValue: function(instance) {
66
+ return instance.get(this.field);
67
+ },
68
+
69
+ /**
70
+ * Empty function which must be overridden by a validation subclass. Make your function return
71
+ * true if the validation passes, false otherwise
72
+ * @return {Boolean} True if this validation passes
73
+ */
74
+ isValid: function(instance) {
75
+ return true;
76
+ }
77
+ };
78
+
79
+ /**
80
+ * @class ExtMVC.model.plugin.validation.ValidatesPresenceOf
81
+ * @extends ExtMVC.model.plugin.validation.AbstractValidation
82
+ * Ensures that a field is present. See {*link ExtMVC.model.plugin.validation.AbstractValidation AbstractValidation} for example.
83
+ */
84
+ ExtMVC.model.plugin.validation.ValidatesPresenceOf = Ext.extend(ExtMVC.model.plugin.validation.AbstractValidation, {
85
+ /**
86
+ * @property message
87
+ * @type String
88
+ * The textual message returned if this validation didn't pass
89
+ */
90
+ message: 'must be present',
91
+
92
+ /**
93
+ * Returns true if the field is an object or a non-empty string
94
+ * @return {Boolean} True if the field is present
95
+ */
96
+ isValid: function(instance) {
97
+ var value = this.getValue(instance),
98
+ valid = false;
99
+
100
+ switch(typeof value) {
101
+ case 'object': if (value != null) valid = true; break;
102
+ case 'string': if (value.length != 0) valid = true; break;
103
+ };
104
+
105
+ return valid;
106
+ }
107
+ });
108
+
109
+ /**
110
+ * @class ExtMVC.model.plugin.validation.ValidatesLengthOf
111
+ * @extends ExtMVC.model.plugin.validation.AbstractValidation
112
+ * Returns true if the field is within the length bounds imposed. See {*link ExtMVC.model.plugin.validation.AbstractValidation AbstractValidation} for example.
113
+ */
114
+ ExtMVC.model.plugin.validation.ValidatesLengthOf = Ext.extend(ExtMVC.model.plugin.validation.AbstractValidation, {
115
+
116
+ /**
117
+ * @property tooShortMessage
118
+ * @type String
119
+ * The message returned if this field was too short
120
+ */
121
+ tooShortMessage: 'is too short',
122
+
123
+ /**
124
+ * @property tooLongMessage
125
+ * @type String
126
+ * The message returned if this field was too long
127
+ */
128
+ tooLongMessage: 'is too long',
129
+
130
+ message: '',
131
+
132
+ /**
133
+ * Tests that the mimimum and maximum length of this field are met.
134
+ * Intended to be used on strings and arrays
135
+ * @return {Boolean} True if the conditions are met
136
+ */
137
+ isValid: function(instance) {
138
+ var value = this.getValue(instance);
139
+
140
+ if (typeof value == 'undefined') return true;
141
+
142
+ if (this.minimum && value.length < this.minimum) {
143
+ this.message = this.tooShortMessage;
144
+ return false;
145
+ }
146
+
147
+ if (this.maximum & value.length > this.maximum) {
148
+ this.message = this.tooLongMessage;
149
+ return false;
150
+ }
151
+
152
+ return true;
153
+ }
154
+ });
155
+
156
+ /**
157
+ * @class ExtMVC.model.plugin.validation.ValidatesNumericalityOf
158
+ * @extends ExtMVC.model.plugin.validation.AbstractValidation
159
+ * Ensures that the field is a number. See {*link ExtMVC.model.plugin.validation.AbstractValidation AbstractValidation} for example.
160
+ */
161
+ ExtMVC.model.plugin.validation.ValidatesNumericalityOf = Ext.extend(ExtMVC.model.plugin.validation.AbstractValidation, {
162
+ /**
163
+ * @property message
164
+ * @type String
165
+ * The message returned if this field is not a number
166
+ */
167
+ message: 'must be a number',
168
+
169
+ /**
170
+ * Returns true if the typeof this field is a number
171
+ * @return {Boolean} True if this is a number
172
+ */
173
+ isValid: function(instance) {
174
+ return 'number' == typeof this.getValue(instance);
175
+ }
176
+ });
177
+
178
+ /**
179
+ * @class ExtMVC.model.plugin.validation.ValidatesInclusionOf
180
+ * @extends ExtMVC.model.plugin.validation.AbstractValidation
181
+ * Ensures that the field is one of the allowed values. See {*link ExtMVC.model.plugin.validation.AbstractValidation AbstractValidation} for example.
182
+ */
183
+ ExtMVC.model.plugin.validation.ValidatesInclusionOf = Ext.extend(ExtMVC.model.plugin.validation.AbstractValidation, {
184
+
185
+
186
+ /**
187
+ * Override Abstract constructor to build the validation message
188
+ */
189
+ constructor: function(m, f, config) {
190
+ //set up defaults
191
+ config = config || {};
192
+ Ext.applyIf(config, { allowed: [] });
193
+
194
+ ExtMVC.model.plugin.validation.ValidatesInclusionOf.superclass.constructor.call(this, m, f, config);
195
+
196
+ Ext.applyIf(this, {
197
+ message: 'must be one of ' + this.allowed.toSentence('or')
198
+ });
199
+ },
200
+
201
+ /**
202
+ * Returns true if the value of this field is one of those specified in this.allowed
203
+ * @return {Boolean} True if the field's value is allowed
204
+ */
205
+ isValid: function(instance) {
206
+ var value = this.getValue(instance);
207
+
208
+ for (var i=0; i < this.allowed.length; i++) {
209
+ if (this.allowed[i] == value) return true;
210
+ };
211
+
212
+ return false;
213
+ }
214
+ });
215
+
216
+ /**
217
+ * @class ExtMVC.model.plugin.validation.ValidatesExclusionOf
218
+ * @extends ExtMVC.model.plugin.validation.AbstractValidation
219
+ * Ensures that the field is not one of the allowed values. See {*link ExtMVC.model.plugin.validation.AbstractValidation AbstractValidation} for example.
220
+ */
221
+ ExtMVC.model.plugin.validation.ValidatesExclusionOf = Ext.extend(ExtMVC.model.plugin.validation.AbstractValidation, {
222
+
223
+ /**
224
+ * Override Abstract constructor to build the validation message
225
+ * @ignore
226
+ */
227
+ constructor: function(m, f, config) {
228
+ //set up defaults
229
+ config = config || {};
230
+ Ext.applyIf(config, { disallowed: [] });
231
+
232
+ ExtMVC.model.plugin.validation.ValidatesExclusionOf.superclass.constructor.call(this, m, f, config);
233
+
234
+ Ext.applyIf(this, {
235
+ message: 'must not be ' + this.disallowed.toSentence('or')
236
+ });
237
+ },
238
+
239
+ /**
240
+ * Returns true if the value of this field is one of those specified in this.allowed
241
+ * @return {Boolean} True if the field's value is allowed
242
+ */
243
+ isValid: function(instance) {
244
+ var value = this.getValue(instance),
245
+ valid = true;
246
+
247
+ for (var i=0; i < this.disallowed.length; i++) {
248
+ if (this.disallowed[i] == value) valid = false;
249
+ };
250
+
251
+ return valid;
252
+ }
253
+ });
254
+
255
+ /**
256
+ * @class ExtMVC.model.plugin.validation.ValidatesFormatOf
257
+ * @extends ExtMVC.model.plugin.validation.AbstractValidation
258
+ * Ensures that the field matches the given regular expression. See {*link ExtMVC.model.plugin.validation.AbstractValidation AbstractValidation} for example.
259
+ */
260
+ ExtMVC.model.plugin.validation.ValidatesFormatOf = Ext.extend(ExtMVC.model.plugin.validation.AbstractValidation, {
261
+
262
+ /**
263
+ * @property message
264
+ * @type String
265
+ * The default message to return if this validation does not pass
266
+ */
267
+ message: 'is invalid',
268
+
269
+ /**
270
+ * Returns true if the value of this field matches the suppled regular expression
271
+ * @return {Boolean} True if the field's value matches
272
+ */
273
+ isValid: function(instance) {
274
+ return this.regex.test(this.getValue(instance));
275
+ }
276
+ });
Binary file
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Override how getXTypes works so that it doesn't require that every single class has
3
+ * an xtype registered for it.
4
+ */
5
+ Ext.override(Ext.Component, {
6
+ getXTypes : function(){
7
+ var tc = this.constructor;
8
+ if(!tc.xtypes){
9
+ var c = [], sc = this;
10
+ while(sc){ //was: while(sc && sc.constructor.xtype) {
11
+ var xtype = sc.constructor.xtype;
12
+ if (xtype != undefined) c.unshift(xtype);
13
+
14
+ sc = sc.constructor.superclass;
15
+ }
16
+ tc.xtypeChain = c;
17
+ tc.xtypes = c.join('/');
18
+ }
19
+ return tc.xtypes;
20
+ }
21
+ });