extjs-mvc 0.4.0.j → 0.4.0.k

Sign up to get free protection for your applications and to get access to all the features.
Files changed (169) hide show
  1. data/Rakefile +1 -1
  2. data/VERSION +1 -1
  3. data/lib/extjs-mvc.rb +0 -14
  4. data/lib/extjs-mvc/api.rb +14 -27
  5. data/lib/extjs-mvc/src/App.js +219 -0
  6. data/lib/extjs-mvc/src/MVC.js +260 -0
  7. data/lib/extjs-mvc/src/Presenter.js +52 -0
  8. data/lib/extjs-mvc/src/README.rdoc +69 -0
  9. data/lib/extjs-mvc/src/controller/Controller.js +278 -0
  10. data/lib/extjs-mvc/src/controller/CrudController.js +460 -0
  11. data/lib/extjs-mvc/src/lib/Array.js +26 -0
  12. data/lib/extjs-mvc/src/lib/Booter.js +417 -0
  13. data/lib/extjs-mvc/src/lib/ClassManager.js +191 -0
  14. data/lib/extjs-mvc/src/lib/ControllerClassManager.js +95 -0
  15. data/lib/extjs-mvc/src/lib/Dependencies.js +44 -0
  16. data/lib/extjs-mvc/src/lib/DispatchMatcher.js +98 -0
  17. data/lib/extjs-mvc/src/lib/Dispatcher.js +129 -0
  18. data/lib/extjs-mvc/src/lib/Environment.js +43 -0
  19. data/lib/extjs-mvc/src/lib/Inflector.js +155 -0
  20. data/lib/extjs-mvc/src/lib/ModelClassManager.js +19 -0
  21. data/lib/extjs-mvc/src/lib/Route.js +139 -0
  22. data/lib/extjs-mvc/src/lib/Router.js +282 -0
  23. data/lib/extjs-mvc/src/lib/String.js +94 -0
  24. data/lib/extjs-mvc/src/lib/ViewClassManager.js +229 -0
  25. data/lib/extjs-mvc/src/lib/notes.txt +32 -0
  26. data/lib/extjs-mvc/src/model/AdapterManager.js +30 -0
  27. data/lib/extjs-mvc/src/model/Association.js +26 -0
  28. data/lib/extjs-mvc/src/model/Base.js +63 -0
  29. data/lib/extjs-mvc/src/model/BelongsToAssociation.js +116 -0
  30. data/lib/extjs-mvc/src/model/Cache.js +131 -0
  31. data/lib/extjs-mvc/src/model/HasManyAssociation.js +160 -0
  32. data/lib/extjs-mvc/src/model/Model.js +331 -0
  33. data/lib/extjs-mvc/src/model/UrlBuilder.js +106 -0
  34. data/lib/extjs-mvc/src/model/adapters/AbstractAdapter.js +296 -0
  35. data/lib/extjs-mvc/src/model/adapters/MemoryAdapter.js +103 -0
  36. data/lib/extjs-mvc/src/model/adapters/RESTAdapter.js +345 -0
  37. data/lib/extjs-mvc/src/model/adapters/RESTJSONAdapter.js +68 -0
  38. data/lib/extjs-mvc/src/model/adapters/notes.txt +42 -0
  39. data/lib/extjs-mvc/src/model/associations/Association.js +192 -0
  40. data/lib/extjs-mvc/src/model/associations/notes.txt +87 -0
  41. data/lib/extjs-mvc/src/model/validations/Errors.js +136 -0
  42. data/lib/extjs-mvc/src/model/validations/Plugin.js +139 -0
  43. data/lib/extjs-mvc/src/model/validations/Validations.js +276 -0
  44. data/lib/extjs-mvc/src/notes/Charts.graffle +0 -0
  45. data/lib/extjs-mvc/src/overrides/Ext.Component.js +21 -0
  46. data/lib/extjs-mvc/src/overrides/Ext.extend.js +142 -0
  47. data/lib/extjs-mvc/src/spec/Array.spec.js +15 -0
  48. data/lib/extjs-mvc/src/spec/ExtMVC.spec.js +65 -0
  49. data/lib/extjs-mvc/src/spec/Model.spec.js +370 -0
  50. data/lib/extjs-mvc/src/spec/OS.spec.js +83 -0
  51. data/lib/extjs-mvc/src/spec/Router.spec.js +99 -0
  52. data/lib/extjs-mvc/src/spec/SpecHelper.js +106 -0
  53. data/lib/extjs-mvc/src/spec/String.spec.js +83 -0
  54. data/lib/extjs-mvc/src/spec/model/AbstractAdapter.spec.js +49 -0
  55. data/lib/extjs-mvc/src/spec/model/Associations.spec.js +99 -0
  56. data/lib/extjs-mvc/src/spec/model/Cache.spec.js +5 -0
  57. data/lib/extjs-mvc/src/spec/model/RESTAdapter.spec.js +19 -0
  58. data/lib/extjs-mvc/src/spec/model/ValidationErrors.spec.js +64 -0
  59. data/lib/extjs-mvc/src/spec/model/Validations.spec.js +166 -0
  60. data/lib/extjs-mvc/src/spec/model/ValidationsPlugin.spec.js +108 -0
  61. data/lib/extjs-mvc/src/spec/suite.html +60 -0
  62. data/lib/extjs-mvc/src/specs-old/JSSpec.css +216 -0
  63. data/lib/extjs-mvc/src/specs-old/JSSpec.js +1512 -0
  64. data/lib/extjs-mvc/src/specs-old/all.html +66 -0
  65. data/lib/extjs-mvc/src/specs-old/base.js +14 -0
  66. data/lib/extjs-mvc/src/specs-old/controller.js +17 -0
  67. data/lib/extjs-mvc/src/specs-old/diff_match_patch.js +1 -0
  68. data/lib/extjs-mvc/src/specs-old/model.js +70 -0
  69. data/lib/extjs-mvc/src/specs-old/route.js +38 -0
  70. data/lib/extjs-mvc/src/specs-old/router.js +59 -0
  71. data/lib/extjs-mvc/src/specs-old/string.js +22 -0
  72. data/lib/extjs-mvc/src/testrunner/JSpecFormatter.js +111 -0
  73. data/lib/extjs-mvc/src/testrunner/TestClient.js +181 -0
  74. data/lib/extjs-mvc/src/testrunner/TestGrid.js +351 -0
  75. data/lib/extjs-mvc/src/testrunner/TestRunner.js +110 -0
  76. data/lib/extjs-mvc/src/testrunner/TestViewport.js +94 -0
  77. data/lib/extjs-mvc/src/vendor.yml +30 -0
  78. data/lib/extjs-mvc/src/vendor/ext-3.1.1/vendor.yml +16 -0
  79. data/lib/extjs-mvc/src/view/FormWindow.js +184 -0
  80. data/lib/extjs-mvc/src/view/HasManyEditorGridPanel.js +211 -0
  81. data/lib/extjs-mvc/src/view/scaffold/Edit.js +46 -0
  82. data/lib/extjs-mvc/src/view/scaffold/Index.js +561 -0
  83. data/lib/extjs-mvc/src/view/scaffold/New.js +20 -0
  84. data/lib/extjs-mvc/src/view/scaffold/ScaffoldFormPanel.js +255 -0
  85. data/lib/{vendor.yml → extjs-mvc/vendor.yml} +0 -0
  86. data/test/app/vendor/extjs-mvc/App.js +219 -0
  87. data/test/app/vendor/extjs-mvc/MVC.js +260 -0
  88. data/test/app/vendor/extjs-mvc/Presenter.js +52 -0
  89. data/test/app/vendor/extjs-mvc/README.rdoc +69 -0
  90. data/test/app/vendor/extjs-mvc/controller/Controller.js +278 -0
  91. data/test/app/vendor/extjs-mvc/controller/CrudController.js +460 -0
  92. data/test/app/vendor/extjs-mvc/lib/Array.js +26 -0
  93. data/test/app/vendor/extjs-mvc/lib/Booter.js +417 -0
  94. data/test/app/vendor/extjs-mvc/lib/ClassManager.js +191 -0
  95. data/test/app/vendor/extjs-mvc/lib/ControllerClassManager.js +95 -0
  96. data/test/app/vendor/extjs-mvc/lib/Dependencies.js +44 -0
  97. data/test/app/vendor/extjs-mvc/lib/DispatchMatcher.js +98 -0
  98. data/test/app/vendor/extjs-mvc/lib/Dispatcher.js +129 -0
  99. data/test/app/vendor/extjs-mvc/lib/Environment.js +43 -0
  100. data/test/app/vendor/extjs-mvc/lib/Inflector.js +155 -0
  101. data/test/app/vendor/extjs-mvc/lib/ModelClassManager.js +19 -0
  102. data/test/app/vendor/extjs-mvc/lib/Route.js +139 -0
  103. data/test/app/vendor/extjs-mvc/lib/Router.js +282 -0
  104. data/test/app/vendor/extjs-mvc/lib/String.js +94 -0
  105. data/test/app/vendor/extjs-mvc/lib/ViewClassManager.js +229 -0
  106. data/test/app/vendor/extjs-mvc/lib/notes.txt +32 -0
  107. data/test/app/vendor/extjs-mvc/model/AdapterManager.js +30 -0
  108. data/test/app/vendor/extjs-mvc/model/Association.js +26 -0
  109. data/test/app/vendor/extjs-mvc/model/Base.js +63 -0
  110. data/test/app/vendor/extjs-mvc/model/BelongsToAssociation.js +116 -0
  111. data/test/app/vendor/extjs-mvc/model/Cache.js +131 -0
  112. data/test/app/vendor/extjs-mvc/model/HasManyAssociation.js +160 -0
  113. data/test/app/vendor/extjs-mvc/model/Model.js +331 -0
  114. data/test/app/vendor/extjs-mvc/model/UrlBuilder.js +106 -0
  115. data/test/app/vendor/extjs-mvc/model/adapters/AbstractAdapter.js +296 -0
  116. data/test/app/vendor/extjs-mvc/model/adapters/MemoryAdapter.js +103 -0
  117. data/test/app/vendor/extjs-mvc/model/adapters/RESTAdapter.js +345 -0
  118. data/test/app/vendor/extjs-mvc/model/adapters/RESTJSONAdapter.js +68 -0
  119. data/test/app/vendor/extjs-mvc/model/adapters/notes.txt +42 -0
  120. data/test/app/vendor/extjs-mvc/model/associations/Association.js +192 -0
  121. data/test/app/vendor/extjs-mvc/model/associations/notes.txt +87 -0
  122. data/test/app/vendor/extjs-mvc/model/validations/Errors.js +136 -0
  123. data/test/app/vendor/extjs-mvc/model/validations/Plugin.js +139 -0
  124. data/test/app/vendor/extjs-mvc/model/validations/Validations.js +276 -0
  125. data/test/app/vendor/extjs-mvc/notes/Charts.graffle +0 -0
  126. data/test/app/vendor/extjs-mvc/overrides/Ext.Component.js +21 -0
  127. data/test/app/vendor/extjs-mvc/overrides/Ext.extend.js +142 -0
  128. data/test/app/vendor/extjs-mvc/spec/Array.spec.js +15 -0
  129. data/test/app/vendor/extjs-mvc/spec/ExtMVC.spec.js +65 -0
  130. data/test/app/vendor/extjs-mvc/spec/Model.spec.js +370 -0
  131. data/test/app/vendor/extjs-mvc/spec/OS.spec.js +83 -0
  132. data/test/app/vendor/extjs-mvc/spec/Router.spec.js +99 -0
  133. data/test/app/vendor/extjs-mvc/spec/SpecHelper.js +106 -0
  134. data/test/app/vendor/extjs-mvc/spec/String.spec.js +83 -0
  135. data/test/app/vendor/extjs-mvc/spec/model/AbstractAdapter.spec.js +49 -0
  136. data/test/app/vendor/extjs-mvc/spec/model/Associations.spec.js +99 -0
  137. data/test/app/vendor/extjs-mvc/spec/model/Cache.spec.js +5 -0
  138. data/test/app/vendor/extjs-mvc/spec/model/RESTAdapter.spec.js +19 -0
  139. data/test/app/vendor/extjs-mvc/spec/model/ValidationErrors.spec.js +64 -0
  140. data/test/app/vendor/extjs-mvc/spec/model/Validations.spec.js +166 -0
  141. data/test/app/vendor/extjs-mvc/spec/model/ValidationsPlugin.spec.js +108 -0
  142. data/test/app/vendor/extjs-mvc/spec/suite.html +60 -0
  143. data/test/app/vendor/extjs-mvc/specs-old/JSSpec.css +216 -0
  144. data/test/app/vendor/extjs-mvc/specs-old/JSSpec.js +1512 -0
  145. data/test/app/vendor/extjs-mvc/specs-old/all.html +66 -0
  146. data/test/app/vendor/extjs-mvc/specs-old/base.js +14 -0
  147. data/test/app/vendor/extjs-mvc/specs-old/controller.js +17 -0
  148. data/test/app/vendor/extjs-mvc/specs-old/diff_match_patch.js +1 -0
  149. data/test/app/vendor/extjs-mvc/specs-old/model.js +70 -0
  150. data/test/app/vendor/extjs-mvc/specs-old/route.js +38 -0
  151. data/test/app/vendor/extjs-mvc/specs-old/router.js +59 -0
  152. data/test/app/vendor/extjs-mvc/specs-old/string.js +22 -0
  153. data/test/app/vendor/extjs-mvc/testrunner/JSpecFormatter.js +111 -0
  154. data/test/app/vendor/extjs-mvc/testrunner/TestClient.js +181 -0
  155. data/test/app/vendor/extjs-mvc/testrunner/TestGrid.js +351 -0
  156. data/test/app/vendor/extjs-mvc/testrunner/TestRunner.js +110 -0
  157. data/test/app/vendor/extjs-mvc/testrunner/TestViewport.js +94 -0
  158. data/test/app/vendor/extjs-mvc/vendor.yml +30 -0
  159. data/test/app/vendor/extjs-mvc/vendor/ext-3.1.1/vendor.yml +16 -0
  160. data/test/app/vendor/extjs-mvc/view/FormWindow.js +184 -0
  161. data/test/app/vendor/extjs-mvc/view/HasManyEditorGridPanel.js +211 -0
  162. data/test/app/vendor/extjs-mvc/view/scaffold/Edit.js +46 -0
  163. data/test/app/vendor/extjs-mvc/view/scaffold/Index.js +561 -0
  164. data/test/app/vendor/extjs-mvc/view/scaffold/New.js +20 -0
  165. data/test/app/vendor/extjs-mvc/view/scaffold/ScaffoldFormPanel.js +255 -0
  166. data/test/helper.rb +7 -1
  167. data/test/test_extjs-mvc.rb +46 -0
  168. metadata +167 -7
  169. data/test/test_extjs-mvc-gem.rb +0 -7
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @class Array
3
+ * Extensions to the array class
4
+ */
5
+
6
+ /**
7
+ * Turns an array into a sentence, joined by a specified connector - e.g.:
8
+ * ['Adama', 'Tigh', 'Roslin'].toSentence(); //'Adama, Tigh and Roslin'
9
+ * ['Adama', 'Tigh', 'Roslin'].toSentence('or'); //'Adama, Tigh or Roslin'
10
+ * @param {String} connector The string to use to connect the last two words. Usually 'and' or 'or', defaults to 'and'
11
+ */
12
+ Array.prototype.toSentence = function(connector) {
13
+ connector = connector || 'and';
14
+
15
+ var sentence = "";
16
+ if (this.length <= 1) {
17
+ sentence = this[0];
18
+ } else {
19
+ //we'll join all but the last error with commas
20
+ var firstErrors = this.slice(0, this.length - 1);
21
+
22
+ //add the last error, with the connector string
23
+ sentence = String.format("{0} {1} {2}", firstErrors.join(", "), connector, this[this.length - 1]);
24
+ }
25
+ return sentence;
26
+ };
@@ -0,0 +1,417 @@
1
+ /**
2
+ * @class ExtMVC.lib.Booter
3
+ * @extends Ext.util.Observable
4
+ * Boots an Ext MVC application by loading all application files and launching
5
+ */
6
+ ExtMVC.lib.Booter = Ext.extend(Ext.util.Observable, {
7
+
8
+ /**
9
+ * @property defaultBootParams
10
+ * @type Object
11
+ * Contains default boot parameters (e.g. sets the default environment to 'production')
12
+ */
13
+ defaultBootParams: {
14
+ environment: 'production'
15
+ },
16
+
17
+ constructor: function(config) {
18
+ config = config || {};
19
+ Ext.applyIf(config, this.parseLocationParams());
20
+ Ext.apply(this, config, this.defaultBootParams);
21
+
22
+ ExtMVC.lib.Booter.superclass.constructor.apply(this, arguments);
23
+
24
+ this.initEvents();
25
+ this.initListeners();
26
+ },
27
+
28
+ /**
29
+ * The Booter loads some code asynchronously, so uses events to proceed the logic. This sets up
30
+ * all of the internal event monitoring.
31
+ */
32
+ initListeners: function() {
33
+ this.on('environment-loaded', this.loadApplicationFiles, this);
34
+
35
+ this.on({
36
+ scope : this,
37
+ 'environment-loaded' : this.loadApplicationFiles,
38
+ 'application-files-loaded': this.launchApp,
39
+ 'boot-complete' : this.onBootComplete
40
+ });
41
+ },
42
+
43
+ /**
44
+ * Sets up events emitted by this component
45
+ */
46
+ initEvents: function() {
47
+ this.addEvents(
48
+ /**
49
+ * @event before-boot
50
+ * Called just before boot starts. Use this as a hook to tie in any pre-boot logic
51
+ * @param {ExtMVC.lib.Booter} this The Booter instance
52
+ */
53
+ 'before-boot',
54
+
55
+ /**
56
+ * @event boot-complete
57
+ * Fires when the entire boot sequence has been completed
58
+ */
59
+ 'boot-complete',
60
+
61
+ /**
62
+ * @event environment-loaded
63
+ * Fires when environment config data has been retrieved
64
+ * @param {ExtMVC.Environment} environment the Ext.Environment object
65
+ */
66
+ 'environment-loaded',
67
+
68
+ /**
69
+ * @event app-files-loaded
70
+ * Fires when all application files (overrides, config, models, views and controllers)
71
+ * have been loaded and are available
72
+ */
73
+ 'application-files-loaded',
74
+
75
+ /**
76
+ * @event application-launched
77
+ * Fires after the application has been launched
78
+ */
79
+ 'application-launched'
80
+ );
81
+ },
82
+
83
+ boot: function() {
84
+ this.fireEvent('before-boot');
85
+
86
+ if (this.useLoadingMask) this.addLoadingMask();
87
+
88
+ this.loadEnvironment();
89
+ },
90
+
91
+ /**
92
+ * Called when the app has been fully booted. Override to provide you own logic (defaults to an empty function)
93
+ */
94
+ onBootComplete: function() {},
95
+
96
+ /**
97
+ * Loads up the current environment by loading config/environment.json, and the appropriate file from within
98
+ * config/environments/ for the current environment (e.g. config/environments/production.json)
99
+ */
100
+ loadEnvironment: function() {
101
+ Ext.Ajax.request({
102
+ url : '/config/environment.json',
103
+ scope : this,
104
+ success: function(response, options) {
105
+ var envName = this.environment;
106
+
107
+ this.environment = new ExtMVC.Environment(Ext.decode(response.responseText));
108
+
109
+ Ext.Ajax.request({
110
+ url : String.format("/config/environments/{0}.json", envName),
111
+ success: function(response, options) {
112
+ this.environment.update(Ext.decode(response.responseText));
113
+
114
+ this.fireEvent('environment-loaded', this.environment);
115
+ },
116
+ scope : this
117
+ });
118
+ },
119
+ failure: function() {
120
+ Ext.Msg.alert(
121
+ 'Could not load environment',
122
+ 'The environment could not be found'
123
+ );
124
+ }
125
+ });
126
+ },
127
+
128
+ /**
129
+ * Loads all required application files, fires the 'app-files-loaded' event when done
130
+ * @param {ExtMVC.Environment} environment The ExtMVC.Environment to gather file list from
131
+ */
132
+ loadApplicationFiles: function(env) {
133
+ this.loadStylesheets(env);
134
+
135
+ //if the 'scripts' property on the Environment is present then models, controllers, plugins etc are ignored
136
+ if (Ext.isArray(env.scripts)) { //&& env.scripts.length > 0) {
137
+ if (env.scripts.length == 0) {
138
+ this.fireEvent('application-files-loaded');
139
+ } else {
140
+ this.loadFiles(env.scripts, false, function() {
141
+ this.fireEvent('application-files-loaded');
142
+ }, this);
143
+ }
144
+
145
+ return;
146
+ }
147
+
148
+
149
+ var order = ['overrides', 'config', 'plugins', 'models', 'controllers', 'views'],
150
+ baseFiles = [],
151
+ pluginFiles = [],
152
+ modelFiles = [],
153
+ controllerFiles = [],
154
+ viewFiles = [];
155
+
156
+ // var groups = {
157
+ // 'base': {preserveOrder: false, }
158
+ // };
159
+
160
+ var underscore = ExtMVC.Inflector.underscore;
161
+
162
+ Ext.each(env.config, function(file) {
163
+ baseFiles.push(String.format("{0}/{1}.js", env.configDir, file));
164
+ }, this);
165
+
166
+ Ext.each(env.plugins, function(file) {
167
+ pluginFiles.push(String.format("{0}/{1}/{2}-all.js", env.pluginsDir, file, file));
168
+ }, this);
169
+
170
+ Ext.each(env.overrides, function(file) {
171
+ pluginFiles.push(String.format("{0}/{1}.js", env.overridesDir, file));
172
+ }, this);
173
+
174
+ Ext.each(env.models, function(file) {
175
+ modelFiles.push(String.format("{0}/models/{1}.js", env.appDir, underscore(file)));
176
+ }, this);
177
+
178
+ Ext.each(env.controllers, function(file) {
179
+ controllerFiles.push(String.format("{0}/controllers/{1}_controller.js", env.appDir, underscore(file)));
180
+ }, this);
181
+
182
+ Ext.each(env.views, function(viewObj) {
183
+ Ext.iterate(viewObj, function(dir, fileList) {
184
+ Ext.each(fileList, function(file) {
185
+ viewFiles.push(String.format("{0}/views/{1}/{2}.js", env.appDir, dir, file));
186
+ }, this);
187
+ }, this);
188
+ }, this);
189
+
190
+ var me = this;
191
+ var doFireEvent = function() {
192
+ me.fireEvent('application-files-loaded');
193
+ };
194
+
195
+ this.loadFiles(baseFiles, false, function() {
196
+ this.loadFiles(pluginFiles, false, function() {
197
+ this.loadFiles(modelFiles, false, function() {
198
+ this.loadFiles(controllerFiles, true, function() {
199
+ this.loadFiles(viewFiles, true, function() {
200
+ doFireEvent();
201
+ });
202
+ });
203
+ });
204
+ });
205
+ });
206
+ },
207
+
208
+ /**
209
+ * Once all application files are loaded, this launches the application, hides the loading mask, fires the
210
+ * 'application-launched' event
211
+ */
212
+ launchApp: function() {
213
+ ExtMVC.app.onReady();
214
+
215
+ if (this.useLoadingMask) this.removeLoadingMask();
216
+
217
+ this.fireEvent('application-launched');
218
+ this.fireEvent('boot-complete');
219
+ },
220
+
221
+ /**
222
+ * @property useLoadingMask
223
+ * @type Boolean
224
+ * True to automatically add an application loading mask layer to give the user loading feedback (defaults to false)
225
+ */
226
+ useLoadingMask: false,
227
+
228
+ /**
229
+ * Adds loading mask HTML elements to the page (called at start of bootup)
230
+ */
231
+ addLoadingMask: function() {
232
+ var body = Ext.getBody();
233
+
234
+ body.createChild({
235
+ id: 'loading-mask'
236
+ });
237
+
238
+ body.createChild({
239
+ id: 'loading',
240
+ cn: [{
241
+ cls: 'loading-indicator',
242
+ html: this.getLoadingMaskMessage()
243
+ }]
244
+ });
245
+ },
246
+
247
+ /**
248
+ * Returns the loading mask message string. Override this to provide your own
249
+ * @return {String} The message to place inside the loading mask (defaults to "Loading...")
250
+ */
251
+ getLoadingMaskMessage: function() {
252
+ return "Loading...";
253
+ },
254
+
255
+ /**
256
+ * @property loadingMaskFadeDelay
257
+ * @type Number
258
+ * Number of milliseconds after app launch is called before the loading mask will fade away.
259
+ * Gives your app a little time to draw its UI (defaults to 250)
260
+ */
261
+ loadingMaskFadeDelay: 250,
262
+
263
+ /**
264
+ * Fades out the loading mask (called after bootup is complete)
265
+ */
266
+ removeLoadingMask: function() {
267
+ (function(){
268
+ Ext.get('loading').remove();
269
+ Ext.get('loading-mask').fadeOut({remove:true});
270
+ }).defer(this.loadingMaskFadeDelay);
271
+ },
272
+
273
+ /**
274
+ * @private
275
+ * Inspects document.location and returns an object containing all of the url params
276
+ * @return {Object} The url params
277
+ */
278
+ parseLocationParams: function() {
279
+ var args = window.location.search.split("?")[1],
280
+ params = {};
281
+
282
+ /**
283
+ * Read config data from url parameters
284
+ */
285
+ if (args != undefined) {
286
+ Ext.each(args.split("&"), function(arg) {
287
+ var splits = arg.split("="),
288
+ key = splits[0],
289
+ value = splits[1];
290
+
291
+ params[key] = value;
292
+ }, this);
293
+ }
294
+
295
+ return params;
296
+ },
297
+
298
+ /**
299
+ * Inserts <link> tags to load stylesheets contained in the environment
300
+ * @param {ExtMVC.lib.Environment} env The environment to load stylesheets from
301
+ */
302
+ loadStylesheets: function(env) {
303
+
304
+ var body = Ext.getBody();
305
+ Ext.each(env.stylesheets, function(filename) {
306
+ body.createChild({
307
+ tag : 'link',
308
+ rel : 'stylesheet',
309
+ type: 'text/css',
310
+ href: this.linkToStylesheet(filename)
311
+ });
312
+ }, this);
313
+ },
314
+
315
+ linkToStylesheet: function(filename) {
316
+ if (filename.match(/^http:/)) {
317
+ return filename
318
+ } else if (filename[0] === '/') {
319
+ return String.format("/public{0}.css", filename);
320
+ } else {
321
+ return String.format("/public/stylesheets/{0}.css", filename)
322
+ }
323
+ },
324
+
325
+ /**
326
+ * Creates and returns a script tag, but does not place it into the document. If a callback function
327
+ * is passed, this is called when the script has been loaded
328
+ * @param {String} filename The name of the file to create a script tag for
329
+ * @param {Function} callback Optional callback, which is called when the script has been loaded
330
+ * @return {Element} The new script ta
331
+ */
332
+ buildScriptTag: function(filename, callback) {
333
+ var script = document.createElement('script');
334
+ script.type = "text/javascript";
335
+ script.src = filename;
336
+
337
+ //IE has a different way of handling <script> loads, so we need to check for it here
338
+ if (script.readyState) {
339
+ script.onreadystatechange = function(){
340
+ if (script.readyState == "loaded" || script.readyState == "complete") {
341
+ script.onreadystatechange = null;
342
+ callback();
343
+ }
344
+ };
345
+ } else {
346
+ script.onload = callback;
347
+ }
348
+
349
+ return script;
350
+ },
351
+
352
+ /**
353
+ * Loads a given set of application .js files. Calls the callback function when all files have been loaded
354
+ * Set preserveOrder to true to ensure non-parallel loading of files, if load ordering is important
355
+ * @param {Array} fileList Array of all files to load
356
+ * @param {Boolean} preserveOrder True to make files load in serial, one after the other (defaults to false)
357
+ * @param {Function} callback Callback to call after all files have been loaded
358
+ * @param {Object} scope The scope to call the callback in
359
+ */
360
+ loadFiles: function(fileList, preserveOrder, callback, scope) {
361
+ console.info("fileList: ", fileList);
362
+ var scope = scope || this,
363
+ head = document.getElementsByTagName("head")[0],
364
+ fragment = document.createDocumentFragment(),
365
+ numFiles = fileList.length,
366
+ loadedFiles = 0,
367
+ me = this;
368
+
369
+ if (fileList.length == 0) {
370
+ callback.call(scope);
371
+ return;
372
+ }
373
+
374
+ /**
375
+ * Loads a particular file from the fileList by index. This is used when preserving order
376
+ */
377
+ var loadFileIndex = function(index) {
378
+ head.appendChild(
379
+ me.buildScriptTag(fileList[index], onFileLoaded)
380
+ );
381
+ };
382
+
383
+ /**
384
+ * Callback function which is called after each file has been loaded. This calls the callback
385
+ * passed to loadFiles once the final file in the fileList has been loaded
386
+ */
387
+ var onFileLoaded = function() {
388
+ loadedFiles ++;
389
+
390
+ //if this was the last file, call the callback, otherwise load the next file
391
+ if (numFiles == loadedFiles && Ext.isFunction(callback)) {
392
+ callback.call(scope);
393
+ } else {
394
+ if (preserveOrder === true) loadFileIndex(loadedFiles);
395
+ }
396
+ };
397
+
398
+ if (preserveOrder === true) {
399
+ loadFileIndex.call(this, 0);
400
+ } else {
401
+ //load each file (most browsers will do this in parallel)
402
+ Ext.each(fileList, function(file, index) {
403
+ fragment.appendChild(
404
+ this.buildScriptTag(file, onFileLoaded)
405
+ );
406
+ }, this);
407
+
408
+ head.appendChild(fragment);
409
+ }
410
+ }
411
+ });
412
+
413
+ Ext.onReady(function() {
414
+ ExtMVC.booter = new ExtMVC.lib.Booter();
415
+
416
+ ExtMVC.booter.boot();
417
+ });
@@ -0,0 +1,191 @@
1
+ ExtMVC.lib.ClassManager = Ext.extend(Ext.util.Observable, {
2
+ /**
3
+ * @property autoDefine
4
+ * @type Boolean
5
+ * If true, the ClassManager will attempt to define classes immediately via this.define (defaults to true)
6
+ */
7
+ autoDefine: true,
8
+
9
+ constructor: function constructor(config) {
10
+ config = config || {};
11
+
12
+ Ext.applyIf(config, {
13
+ /**
14
+ * @property registeredClasses
15
+ * @type Object
16
+ * {name: config} mapping of all registered classes
17
+ */
18
+ registeredClasses: {},
19
+
20
+ /**
21
+ * @property constructors
22
+ * @type Object
23
+ * {name: Function} mapping of all registered classes to their constructor functions
24
+ */
25
+ constructors: {}
26
+ });
27
+
28
+ Ext.apply(this, config);
29
+
30
+ this.addEvents(
31
+ /**
32
+ * @event class-registered
33
+ * Fires when a class has been registered to this package
34
+ * @param {String} name The name of the class
35
+ * @param {Object} config The class config object
36
+ */
37
+ 'class-registered',
38
+
39
+ /**
40
+ * @event class-defined
41
+ * Fires after a class has been registered and then defined using Ext.extend
42
+ * @param {String} name The name of the class
43
+ * @param {Function} constructor The class constructor
44
+ */
45
+ 'class-defined'
46
+ );
47
+
48
+ // this.on({
49
+ // scope : this,
50
+ // 'class-registered': this.afterRegister,
51
+ // 'class-defined' : this.afterDefine
52
+ // });
53
+ },
54
+
55
+ /**
56
+ * Registers a config object or class constructor to a given class name
57
+ * @param {String} name The name to register this class under
58
+ * @param {Object/Function} config Either a config object or a constructor function
59
+ */
60
+ register: function register(name, config) {
61
+ this.registeredClasses[name] = config;
62
+
63
+ this.fireEvent('class-registered', name, config);
64
+
65
+ if (this.autoDefine === true) this.define(name);
66
+ },
67
+
68
+ /**
69
+ * Returns the config object for a given class name. Only really useful privately
70
+ * @param {String} name The name of the class
71
+ * @return {Object} The config object for this class
72
+ */
73
+ getRegistered: function getRegistered(name) {
74
+ return this.registeredClasses[name];
75
+ },
76
+
77
+ /**
78
+ * Defines the given class name by using Ext.extend to declare it. The result of Ext.extend
79
+ * is then stored in this.constructors, and the constructor can then be retrieved with this.getConstructor(name)
80
+ * @param {String} name The name of the class to define
81
+ * @return {Function} The newly defined class constructor
82
+ */
83
+ define: function define(name) {
84
+ console.log('defining');
85
+ console.log(name);
86
+
87
+ var overrides = this.getRegistered(name);
88
+
89
+ //extend the parent object and register the constructor
90
+ var klass = Ext.extend(this.getConstructor(overrides.extend), overrides);
91
+ this.constructors[name] = klass;
92
+
93
+ this.fireEvent('class-defined', name, klass);
94
+
95
+ return klass;
96
+ },
97
+
98
+ /**
99
+ * Returns the constructor function for a registered class name. If the constructor
100
+ * itself hasn't been defined yet, it is defined first using this.define(), then returned
101
+ * @param {String} name The name of the class to return the constructor for
102
+ * @return {Function} The constructor function
103
+ */
104
+ getConstructor: function getConstructor(name) {
105
+ return this.constructors[name] || this.define(name);
106
+ }
107
+ });
108
+
109
+ /**
110
+ * Ideal syntax after these changes:
111
+ */
112
+
113
+ // ExtMVC.registerView('index', 'index', {
114
+ // xtype: "panel",
115
+ // title: "Welcome to Ext MVC",
116
+ // html : "This is a test"
117
+ // });
118
+ //
119
+ // Ext.registerController("index", {
120
+ // index: function() {
121
+ // this.render("index", {
122
+ // title: "Different Title"
123
+ // });
124
+ // },
125
+ //
126
+ // //this would actually be here by default
127
+ // welcome: function() {
128
+ // this.render("index");
129
+ // },
130
+ //
131
+ // //if we give the function a name, we can accept alternative render format:
132
+ // //all MVC Crud controller methods can be made like this
133
+ // search: function search() {
134
+ // this.render({
135
+ // //options for new MyApp.views.index.search
136
+ // });
137
+ // },
138
+ //
139
+ // create: function(data) {
140
+ // var newUser = ExtMVC.buildModel("SuperUser", data);
141
+ //
142
+ // newUser.save({
143
+ // success: function(user) {
144
+ //
145
+ // },
146
+ // failure: function(user) {
147
+ //
148
+ // }
149
+ // });
150
+ //
151
+ // //or how about
152
+ // ExtMVC.createModel("SuperUser", data, {
153
+ // success: function(user) {
154
+ //
155
+ // },
156
+ // failure: function(user) {
157
+ //
158
+ // }
159
+ // });
160
+ // },
161
+ //
162
+ // update: function(user, changes) {
163
+ // user.update(changes, {
164
+ // success: function(user) {
165
+ //
166
+ // },
167
+ // failure: function(user) {
168
+ //
169
+ // }
170
+ // });
171
+ // }
172
+ // });
173
+ //
174
+ // ExtMVC.registerController("someSubController", {
175
+ // extend: "index",
176
+ //
177
+ // index: function() {
178
+ // this.superclass.index.call(this);
179
+ // }
180
+ // });
181
+ //
182
+ //
183
+ // ExtMVC.registerModel("SuperUser", {
184
+ // extend: "User",
185
+ // fields: [
186
+ // {name: 'id', type: 'int'}
187
+ // ]
188
+ // });
189
+
190
+
191
+