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.
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/extjs-mvc.rb +0 -14
- data/lib/extjs-mvc/api.rb +14 -27
- data/lib/extjs-mvc/src/App.js +219 -0
- data/lib/extjs-mvc/src/MVC.js +260 -0
- data/lib/extjs-mvc/src/Presenter.js +52 -0
- data/lib/extjs-mvc/src/README.rdoc +69 -0
- data/lib/extjs-mvc/src/controller/Controller.js +278 -0
- data/lib/extjs-mvc/src/controller/CrudController.js +460 -0
- data/lib/extjs-mvc/src/lib/Array.js +26 -0
- data/lib/extjs-mvc/src/lib/Booter.js +417 -0
- data/lib/extjs-mvc/src/lib/ClassManager.js +191 -0
- data/lib/extjs-mvc/src/lib/ControllerClassManager.js +95 -0
- data/lib/extjs-mvc/src/lib/Dependencies.js +44 -0
- data/lib/extjs-mvc/src/lib/DispatchMatcher.js +98 -0
- data/lib/extjs-mvc/src/lib/Dispatcher.js +129 -0
- data/lib/extjs-mvc/src/lib/Environment.js +43 -0
- data/lib/extjs-mvc/src/lib/Inflector.js +155 -0
- data/lib/extjs-mvc/src/lib/ModelClassManager.js +19 -0
- data/lib/extjs-mvc/src/lib/Route.js +139 -0
- data/lib/extjs-mvc/src/lib/Router.js +282 -0
- data/lib/extjs-mvc/src/lib/String.js +94 -0
- data/lib/extjs-mvc/src/lib/ViewClassManager.js +229 -0
- data/lib/extjs-mvc/src/lib/notes.txt +32 -0
- data/lib/extjs-mvc/src/model/AdapterManager.js +30 -0
- data/lib/extjs-mvc/src/model/Association.js +26 -0
- data/lib/extjs-mvc/src/model/Base.js +63 -0
- data/lib/extjs-mvc/src/model/BelongsToAssociation.js +116 -0
- data/lib/extjs-mvc/src/model/Cache.js +131 -0
- data/lib/extjs-mvc/src/model/HasManyAssociation.js +160 -0
- data/lib/extjs-mvc/src/model/Model.js +331 -0
- data/lib/extjs-mvc/src/model/UrlBuilder.js +106 -0
- data/lib/extjs-mvc/src/model/adapters/AbstractAdapter.js +296 -0
- data/lib/extjs-mvc/src/model/adapters/MemoryAdapter.js +103 -0
- data/lib/extjs-mvc/src/model/adapters/RESTAdapter.js +345 -0
- data/lib/extjs-mvc/src/model/adapters/RESTJSONAdapter.js +68 -0
- data/lib/extjs-mvc/src/model/adapters/notes.txt +42 -0
- data/lib/extjs-mvc/src/model/associations/Association.js +192 -0
- data/lib/extjs-mvc/src/model/associations/notes.txt +87 -0
- data/lib/extjs-mvc/src/model/validations/Errors.js +136 -0
- data/lib/extjs-mvc/src/model/validations/Plugin.js +139 -0
- data/lib/extjs-mvc/src/model/validations/Validations.js +276 -0
- data/lib/extjs-mvc/src/notes/Charts.graffle +0 -0
- data/lib/extjs-mvc/src/overrides/Ext.Component.js +21 -0
- data/lib/extjs-mvc/src/overrides/Ext.extend.js +142 -0
- data/lib/extjs-mvc/src/spec/Array.spec.js +15 -0
- data/lib/extjs-mvc/src/spec/ExtMVC.spec.js +65 -0
- data/lib/extjs-mvc/src/spec/Model.spec.js +370 -0
- data/lib/extjs-mvc/src/spec/OS.spec.js +83 -0
- data/lib/extjs-mvc/src/spec/Router.spec.js +99 -0
- data/lib/extjs-mvc/src/spec/SpecHelper.js +106 -0
- data/lib/extjs-mvc/src/spec/String.spec.js +83 -0
- data/lib/extjs-mvc/src/spec/model/AbstractAdapter.spec.js +49 -0
- data/lib/extjs-mvc/src/spec/model/Associations.spec.js +99 -0
- data/lib/extjs-mvc/src/spec/model/Cache.spec.js +5 -0
- data/lib/extjs-mvc/src/spec/model/RESTAdapter.spec.js +19 -0
- data/lib/extjs-mvc/src/spec/model/ValidationErrors.spec.js +64 -0
- data/lib/extjs-mvc/src/spec/model/Validations.spec.js +166 -0
- data/lib/extjs-mvc/src/spec/model/ValidationsPlugin.spec.js +108 -0
- data/lib/extjs-mvc/src/spec/suite.html +60 -0
- data/lib/extjs-mvc/src/specs-old/JSSpec.css +216 -0
- data/lib/extjs-mvc/src/specs-old/JSSpec.js +1512 -0
- data/lib/extjs-mvc/src/specs-old/all.html +66 -0
- data/lib/extjs-mvc/src/specs-old/base.js +14 -0
- data/lib/extjs-mvc/src/specs-old/controller.js +17 -0
- data/lib/extjs-mvc/src/specs-old/diff_match_patch.js +1 -0
- data/lib/extjs-mvc/src/specs-old/model.js +70 -0
- data/lib/extjs-mvc/src/specs-old/route.js +38 -0
- data/lib/extjs-mvc/src/specs-old/router.js +59 -0
- data/lib/extjs-mvc/src/specs-old/string.js +22 -0
- data/lib/extjs-mvc/src/testrunner/JSpecFormatter.js +111 -0
- data/lib/extjs-mvc/src/testrunner/TestClient.js +181 -0
- data/lib/extjs-mvc/src/testrunner/TestGrid.js +351 -0
- data/lib/extjs-mvc/src/testrunner/TestRunner.js +110 -0
- data/lib/extjs-mvc/src/testrunner/TestViewport.js +94 -0
- data/lib/extjs-mvc/src/vendor.yml +30 -0
- data/lib/extjs-mvc/src/vendor/ext-3.1.1/vendor.yml +16 -0
- data/lib/extjs-mvc/src/view/FormWindow.js +184 -0
- data/lib/extjs-mvc/src/view/HasManyEditorGridPanel.js +211 -0
- data/lib/extjs-mvc/src/view/scaffold/Edit.js +46 -0
- data/lib/extjs-mvc/src/view/scaffold/Index.js +561 -0
- data/lib/extjs-mvc/src/view/scaffold/New.js +20 -0
- data/lib/extjs-mvc/src/view/scaffold/ScaffoldFormPanel.js +255 -0
- data/lib/{vendor.yml → extjs-mvc/vendor.yml} +0 -0
- data/test/app/vendor/extjs-mvc/App.js +219 -0
- data/test/app/vendor/extjs-mvc/MVC.js +260 -0
- data/test/app/vendor/extjs-mvc/Presenter.js +52 -0
- data/test/app/vendor/extjs-mvc/README.rdoc +69 -0
- data/test/app/vendor/extjs-mvc/controller/Controller.js +278 -0
- data/test/app/vendor/extjs-mvc/controller/CrudController.js +460 -0
- data/test/app/vendor/extjs-mvc/lib/Array.js +26 -0
- data/test/app/vendor/extjs-mvc/lib/Booter.js +417 -0
- data/test/app/vendor/extjs-mvc/lib/ClassManager.js +191 -0
- data/test/app/vendor/extjs-mvc/lib/ControllerClassManager.js +95 -0
- data/test/app/vendor/extjs-mvc/lib/Dependencies.js +44 -0
- data/test/app/vendor/extjs-mvc/lib/DispatchMatcher.js +98 -0
- data/test/app/vendor/extjs-mvc/lib/Dispatcher.js +129 -0
- data/test/app/vendor/extjs-mvc/lib/Environment.js +43 -0
- data/test/app/vendor/extjs-mvc/lib/Inflector.js +155 -0
- data/test/app/vendor/extjs-mvc/lib/ModelClassManager.js +19 -0
- data/test/app/vendor/extjs-mvc/lib/Route.js +139 -0
- data/test/app/vendor/extjs-mvc/lib/Router.js +282 -0
- data/test/app/vendor/extjs-mvc/lib/String.js +94 -0
- data/test/app/vendor/extjs-mvc/lib/ViewClassManager.js +229 -0
- data/test/app/vendor/extjs-mvc/lib/notes.txt +32 -0
- data/test/app/vendor/extjs-mvc/model/AdapterManager.js +30 -0
- data/test/app/vendor/extjs-mvc/model/Association.js +26 -0
- data/test/app/vendor/extjs-mvc/model/Base.js +63 -0
- data/test/app/vendor/extjs-mvc/model/BelongsToAssociation.js +116 -0
- data/test/app/vendor/extjs-mvc/model/Cache.js +131 -0
- data/test/app/vendor/extjs-mvc/model/HasManyAssociation.js +160 -0
- data/test/app/vendor/extjs-mvc/model/Model.js +331 -0
- data/test/app/vendor/extjs-mvc/model/UrlBuilder.js +106 -0
- data/test/app/vendor/extjs-mvc/model/adapters/AbstractAdapter.js +296 -0
- data/test/app/vendor/extjs-mvc/model/adapters/MemoryAdapter.js +103 -0
- data/test/app/vendor/extjs-mvc/model/adapters/RESTAdapter.js +345 -0
- data/test/app/vendor/extjs-mvc/model/adapters/RESTJSONAdapter.js +68 -0
- data/test/app/vendor/extjs-mvc/model/adapters/notes.txt +42 -0
- data/test/app/vendor/extjs-mvc/model/associations/Association.js +192 -0
- data/test/app/vendor/extjs-mvc/model/associations/notes.txt +87 -0
- data/test/app/vendor/extjs-mvc/model/validations/Errors.js +136 -0
- data/test/app/vendor/extjs-mvc/model/validations/Plugin.js +139 -0
- data/test/app/vendor/extjs-mvc/model/validations/Validations.js +276 -0
- data/test/app/vendor/extjs-mvc/notes/Charts.graffle +0 -0
- data/test/app/vendor/extjs-mvc/overrides/Ext.Component.js +21 -0
- data/test/app/vendor/extjs-mvc/overrides/Ext.extend.js +142 -0
- data/test/app/vendor/extjs-mvc/spec/Array.spec.js +15 -0
- data/test/app/vendor/extjs-mvc/spec/ExtMVC.spec.js +65 -0
- data/test/app/vendor/extjs-mvc/spec/Model.spec.js +370 -0
- data/test/app/vendor/extjs-mvc/spec/OS.spec.js +83 -0
- data/test/app/vendor/extjs-mvc/spec/Router.spec.js +99 -0
- data/test/app/vendor/extjs-mvc/spec/SpecHelper.js +106 -0
- data/test/app/vendor/extjs-mvc/spec/String.spec.js +83 -0
- data/test/app/vendor/extjs-mvc/spec/model/AbstractAdapter.spec.js +49 -0
- data/test/app/vendor/extjs-mvc/spec/model/Associations.spec.js +99 -0
- data/test/app/vendor/extjs-mvc/spec/model/Cache.spec.js +5 -0
- data/test/app/vendor/extjs-mvc/spec/model/RESTAdapter.spec.js +19 -0
- data/test/app/vendor/extjs-mvc/spec/model/ValidationErrors.spec.js +64 -0
- data/test/app/vendor/extjs-mvc/spec/model/Validations.spec.js +166 -0
- data/test/app/vendor/extjs-mvc/spec/model/ValidationsPlugin.spec.js +108 -0
- data/test/app/vendor/extjs-mvc/spec/suite.html +60 -0
- data/test/app/vendor/extjs-mvc/specs-old/JSSpec.css +216 -0
- data/test/app/vendor/extjs-mvc/specs-old/JSSpec.js +1512 -0
- data/test/app/vendor/extjs-mvc/specs-old/all.html +66 -0
- data/test/app/vendor/extjs-mvc/specs-old/base.js +14 -0
- data/test/app/vendor/extjs-mvc/specs-old/controller.js +17 -0
- data/test/app/vendor/extjs-mvc/specs-old/diff_match_patch.js +1 -0
- data/test/app/vendor/extjs-mvc/specs-old/model.js +70 -0
- data/test/app/vendor/extjs-mvc/specs-old/route.js +38 -0
- data/test/app/vendor/extjs-mvc/specs-old/router.js +59 -0
- data/test/app/vendor/extjs-mvc/specs-old/string.js +22 -0
- data/test/app/vendor/extjs-mvc/testrunner/JSpecFormatter.js +111 -0
- data/test/app/vendor/extjs-mvc/testrunner/TestClient.js +181 -0
- data/test/app/vendor/extjs-mvc/testrunner/TestGrid.js +351 -0
- data/test/app/vendor/extjs-mvc/testrunner/TestRunner.js +110 -0
- data/test/app/vendor/extjs-mvc/testrunner/TestViewport.js +94 -0
- data/test/app/vendor/extjs-mvc/vendor.yml +30 -0
- data/test/app/vendor/extjs-mvc/vendor/ext-3.1.1/vendor.yml +16 -0
- data/test/app/vendor/extjs-mvc/view/FormWindow.js +184 -0
- data/test/app/vendor/extjs-mvc/view/HasManyEditorGridPanel.js +211 -0
- data/test/app/vendor/extjs-mvc/view/scaffold/Edit.js +46 -0
- data/test/app/vendor/extjs-mvc/view/scaffold/Index.js +561 -0
- data/test/app/vendor/extjs-mvc/view/scaffold/New.js +20 -0
- data/test/app/vendor/extjs-mvc/view/scaffold/ScaffoldFormPanel.js +255 -0
- data/test/helper.rb +7 -1
- data/test/test_extjs-mvc.rb +46 -0
- metadata +167 -7
- data/test/test_extjs-mvc-gem.rb +0 -7
@@ -0,0 +1,260 @@
|
|
1
|
+
/**
|
2
|
+
* @class ExtMVC
|
3
|
+
* ExtMVC
|
4
|
+
* @singleton
|
5
|
+
*/
|
6
|
+
ExtMVC = Ext.extend(Ext.util.Observable, {
|
7
|
+
version: "0.7a",
|
8
|
+
|
9
|
+
constructor: function() {
|
10
|
+
ExtMVC.superclass.constructor.apply(this, arguments);
|
11
|
+
|
12
|
+
/**
|
13
|
+
* @property dispatcher
|
14
|
+
* @type Ext.lib.Dispatcher
|
15
|
+
* The dispatcher object which finds the right controller and action when ExtMVC.dispatch is called
|
16
|
+
*/
|
17
|
+
// this.dispatcher = new Ext.lib.Dispatcher({
|
18
|
+
//
|
19
|
+
// });
|
20
|
+
},
|
21
|
+
|
22
|
+
dispatch: function() {
|
23
|
+
var dispatcher = this.dispatcher;
|
24
|
+
|
25
|
+
return dispatcher.dispatch.apply(dispatcher, arguments);
|
26
|
+
},
|
27
|
+
|
28
|
+
/**
|
29
|
+
* Sets the Ext.Application instance currently in use. This is currently required :/
|
30
|
+
* @param {Ext.Application} app The application currently in use
|
31
|
+
*/
|
32
|
+
setApplication: function(app) {
|
33
|
+
this.app = app;
|
34
|
+
this.name = app.name;
|
35
|
+
|
36
|
+
ExtMVC.model.modelNamespace = window[app.name].models;
|
37
|
+
},
|
38
|
+
|
39
|
+
fields: {
|
40
|
+
|
41
|
+
},
|
42
|
+
|
43
|
+
registerFields: function(name, fields) {
|
44
|
+
this.fields[name] = fields;
|
45
|
+
},
|
46
|
+
|
47
|
+
getFields: function(name) {
|
48
|
+
return this.fields[name];
|
49
|
+
},
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
/**
|
54
|
+
* Registers a model class with Ext MVC
|
55
|
+
* @param {String} name The name to give this model
|
56
|
+
* @param {Object} config Model definition configuration
|
57
|
+
*/
|
58
|
+
registerModel: function(name, config) {
|
59
|
+
this.registerClass('model', arguments);
|
60
|
+
},
|
61
|
+
|
62
|
+
/**
|
63
|
+
* Registers a controller class with Ext MVC
|
64
|
+
* @param {String} name The name to give this controller
|
65
|
+
* @param {Object} config Controller definition configuration
|
66
|
+
*/
|
67
|
+
registerController: function(name, config) {
|
68
|
+
this.registerClass('controller', arguments);
|
69
|
+
},
|
70
|
+
|
71
|
+
/**
|
72
|
+
* Registers a view class with Ext MVC.
|
73
|
+
* @param {String} namesapce The namespace to add this view to
|
74
|
+
* @param {String} name The name to give this view
|
75
|
+
* @param {Object} config View definition configuration
|
76
|
+
*/
|
77
|
+
registerView: function(namespace, name, config) {
|
78
|
+
this.registerClass('view', arguments);
|
79
|
+
},
|
80
|
+
|
81
|
+
/**
|
82
|
+
* Abstraction for registering views, models and controllers
|
83
|
+
* @param {String} managerName The name of the class manager to register with
|
84
|
+
* @param {Array} args The args to pass to the manager's register method
|
85
|
+
*/
|
86
|
+
registerClass: function(managerName, args) {
|
87
|
+
var manager = this.getClassManager(managerName);
|
88
|
+
|
89
|
+
manager.register.apply(manager, args);
|
90
|
+
},
|
91
|
+
|
92
|
+
/**
|
93
|
+
* @property classManagers
|
94
|
+
* @type Object
|
95
|
+
* {name: classManager} mappings used by this.getClassManager and this.registerClassManager
|
96
|
+
*/
|
97
|
+
classManagers: {},
|
98
|
+
|
99
|
+
/**
|
100
|
+
* @private
|
101
|
+
* Sets up model, view and controller class managers
|
102
|
+
*/
|
103
|
+
initializeClassManagers: function() {
|
104
|
+
this.registerClassManager('model', new ExtMVC.lib.ModelClassManager());
|
105
|
+
this.registerClassManager('view', new ExtMVC.lib.ViewClassManager());
|
106
|
+
this.registerClassManager('controller', new ExtMVC.lib.ControllerClassManager());
|
107
|
+
},
|
108
|
+
|
109
|
+
/**
|
110
|
+
* Returns the class manager for the given name
|
111
|
+
* @param {String} name The name of the manager (model, view or controller)
|
112
|
+
* @return {ExtMVC.lib.ClassManager} The class manager instance
|
113
|
+
*/
|
114
|
+
getClassManager: function(name) {
|
115
|
+
return this.classManagers[name];
|
116
|
+
},
|
117
|
+
|
118
|
+
/**
|
119
|
+
* Registers a class manager instance under a given name
|
120
|
+
* @param {String} name The name of the class manager
|
121
|
+
* @param {ExtMVC.lib.ClassManager} manager The ClassManager instance to register
|
122
|
+
*/
|
123
|
+
registerClassManager: function(name, manager) {
|
124
|
+
this.classManagers[name] = manager;
|
125
|
+
},
|
126
|
+
|
127
|
+
/**
|
128
|
+
* Returns the canonical controller instance for the given controller name
|
129
|
+
* @return {ExtMVC.Controller} The controller instance
|
130
|
+
*/
|
131
|
+
getController: function(name) {
|
132
|
+
return this.getClassManager('controller').getInstance(name);
|
133
|
+
},
|
134
|
+
|
135
|
+
/**
|
136
|
+
* Returns the constructor for a given model name
|
137
|
+
* @param {String} name The name of the model
|
138
|
+
* @return {Function} The model constructor
|
139
|
+
*/
|
140
|
+
getModel: function(name) {
|
141
|
+
return this.getClassManager('model').getConstructor(name);
|
142
|
+
},
|
143
|
+
|
144
|
+
/**
|
145
|
+
* Instantiates a model of the given name with the data supplied
|
146
|
+
* @param {String} modelName The name of the model to instantiate
|
147
|
+
* @param {Object} data Data object to instantiate the instance with
|
148
|
+
* @return {ExtMVC.Model} The new model instance
|
149
|
+
*/
|
150
|
+
buildModel: function(modelName, data) {
|
151
|
+
return new (this.getModel(modelName))(data);
|
152
|
+
},
|
153
|
+
|
154
|
+
/**
|
155
|
+
* Returns the constructor for a given view namespace/name combination
|
156
|
+
* @param {String} namespace The view namespace to look in
|
157
|
+
* @param {String} name The name of the view within the view namespace
|
158
|
+
* @return {Function} The view constructor
|
159
|
+
*/
|
160
|
+
getView: function getView(namespace, name) {
|
161
|
+
return this.getClassManager('view').getConstructor(namespace, name);
|
162
|
+
},
|
163
|
+
|
164
|
+
/**
|
165
|
+
* Returns a new view instance for the given namespace/name combo, using the supplied config
|
166
|
+
* @param {String} namespace The namespace to find the view from
|
167
|
+
* @param {String} name The view name
|
168
|
+
* @param {Object} config Optional config object
|
169
|
+
* @return {Ext.Component} The new view instance
|
170
|
+
*/
|
171
|
+
buildView: function buildView(namespace, name, config) {
|
172
|
+
var constructor = this.getView(namespace, name);
|
173
|
+
|
174
|
+
return new (constructor)(config);
|
175
|
+
},
|
176
|
+
|
177
|
+
/**
|
178
|
+
* Loads packaged classes from a given url, calling a callback when they have been registered. Sample return:
|
179
|
+
<pre>
|
180
|
+
{
|
181
|
+
controllers: [
|
182
|
+
{
|
183
|
+
name: 'comments',
|
184
|
+
superclass: 'crud',
|
185
|
+
config: {
|
186
|
+
index: function() {
|
187
|
+
this.render('index', {
|
188
|
+
title: "Loaded on demand!"
|
189
|
+
});
|
190
|
+
}
|
191
|
+
}
|
192
|
+
}
|
193
|
+
],
|
194
|
+
views: [
|
195
|
+
{
|
196
|
+
name: 'new',
|
197
|
+
namespace: 'comments',
|
198
|
+
config: {
|
199
|
+
xtype: 'scaffoldnew',
|
200
|
+
title: "New Comment"
|
201
|
+
}
|
202
|
+
}
|
203
|
+
],
|
204
|
+
models: [
|
205
|
+
{
|
206
|
+
name : 'Comment',
|
207
|
+
config: {
|
208
|
+
fields: [
|
209
|
+
{name: 'id', type: 'int'},
|
210
|
+
{name: 'title', type: 'string'},
|
211
|
+
{name: 'message', type: 'string'}
|
212
|
+
]
|
213
|
+
}
|
214
|
+
}
|
215
|
+
]
|
216
|
+
}
|
217
|
+
</pre>
|
218
|
+
* @param {String} url The url to retrieve the package from
|
219
|
+
* @param {Function} callback Optional callback function, called after the package has been read and registered
|
220
|
+
* @param {Object} scope The scope to execute the callback function in
|
221
|
+
*/
|
222
|
+
loadOnDemand: function(url, callback, scope) {
|
223
|
+
Ext.Ajax.request({
|
224
|
+
url : url,
|
225
|
+
scope : scope || this,
|
226
|
+
success: function(response) {
|
227
|
+
var pkg = Ext.decode(response.responseText);
|
228
|
+
|
229
|
+
Ext.each(pkg.controllers || [], function(config) {
|
230
|
+
this.registerController(config.name, config);
|
231
|
+
}, this);
|
232
|
+
|
233
|
+
Ext.each(pkg.models || [], function(config) {
|
234
|
+
this.registerModel(config.name, config);
|
235
|
+
}, this);
|
236
|
+
|
237
|
+
Ext.each(pkg.views || [], function(config) {
|
238
|
+
this.registerView(config.namespace, config.name, config);
|
239
|
+
}, this);
|
240
|
+
|
241
|
+
if (Ext.isFunction(callback)) callback.call(scope, pkg);
|
242
|
+
}
|
243
|
+
});
|
244
|
+
}
|
245
|
+
});
|
246
|
+
|
247
|
+
ExtMVC = new ExtMVC();
|
248
|
+
|
249
|
+
// ExtMVC.initializeClassManagers();
|
250
|
+
|
251
|
+
Ext.onReady(function() {
|
252
|
+
/**
|
253
|
+
* @property dispatcher
|
254
|
+
* @type Ext.lib.Dispatcher
|
255
|
+
* The dispatcher object which finds the right controller and action when ExtMVC.dispatch is called
|
256
|
+
*/
|
257
|
+
ExtMVC.dispatcher = new ExtMVC.lib.Dispatcher();
|
258
|
+
});
|
259
|
+
|
260
|
+
Ext.ns('ExtMVC.router', 'ExtMVC.plugin', 'ExtMVC.controller', 'ExtMVC.view', 'ExtMVC.view.scaffold', 'ExtMVC.lib', 'ExtMVC.test');
|
@@ -0,0 +1,52 @@
|
|
1
|
+
/**
|
2
|
+
* @class ExtMVC.Presenter
|
3
|
+
* @extends Ext.util.Observable
|
4
|
+
* Used as an interface between a controller and its views
|
5
|
+
*/
|
6
|
+
ExtMVC.Presenter = Ext.extend(Ext.util.Observable, {
|
7
|
+
|
8
|
+
constructor: function(config) {
|
9
|
+
ExtMVC.Presenter.superclass.constructor.apply(this, arguments);
|
10
|
+
|
11
|
+
this.addEvents(
|
12
|
+
/**
|
13
|
+
* @event load
|
14
|
+
* Fires when all items in the Presenter have been loaded
|
15
|
+
*/
|
16
|
+
'load'
|
17
|
+
);
|
18
|
+
|
19
|
+
/**
|
20
|
+
* @property loaded
|
21
|
+
* @type Boolean
|
22
|
+
* True if all items that must be loaded before rendering have been
|
23
|
+
*/
|
24
|
+
this.loaded = false;
|
25
|
+
|
26
|
+
/**
|
27
|
+
* @property loading
|
28
|
+
* @type Boolean
|
29
|
+
* True while the loader is loading
|
30
|
+
*/
|
31
|
+
this.loading = false;
|
32
|
+
},
|
33
|
+
|
34
|
+
load: function() {
|
35
|
+
if (this.loaded || this.loading) return;
|
36
|
+
|
37
|
+
this.each(function(item, index, length) {
|
38
|
+
var callback = function(index) {
|
39
|
+
return function() {
|
40
|
+
if (index == length) {
|
41
|
+
this.loaded = true;
|
42
|
+
this.loading = false;
|
43
|
+
|
44
|
+
this.fireEvent('load');
|
45
|
+
}
|
46
|
+
};
|
47
|
+
}(index);
|
48
|
+
|
49
|
+
item.on('load', callback, this, {single: true});
|
50
|
+
}, this);
|
51
|
+
}
|
52
|
+
});
|
@@ -0,0 +1,69 @@
|
|
1
|
+
= Ext MVC
|
2
|
+
|
3
|
+
EXT MVC is a complete MVC stack on top of Ext JS (http://extjs.com).
|
4
|
+
|
5
|
+
== Base App
|
6
|
+
|
7
|
+
You are advised to use the base app to get up and running with Ext MVC as it sets everything up for you.
|
8
|
+
|
9
|
+
If you're comfortable with git:
|
10
|
+
|
11
|
+
1. git clone git://github.com/extmvc/baseapp.git myapp
|
12
|
+
2. cd myapp
|
13
|
+
3. rm -rf .git/
|
14
|
+
4. git init
|
15
|
+
|
16
|
+
If not:
|
17
|
+
|
18
|
+
1. Download the latest zip file from Github at http://github.com/extmvc/baseapp/zipball/master and unzip.
|
19
|
+
|
20
|
+
== Getting started
|
21
|
+
|
22
|
+
Read the readme file inside the base app and refer to http://extmvc.com
|
23
|
+
|
24
|
+
== Building
|
25
|
+
|
26
|
+
Ext MVC comes with a set of build tools for itself and your applications, written in Ruby. You need to be using
|
27
|
+
the Baseapp or a structure similar to it for these to work effectively.
|
28
|
+
|
29
|
+
=== Building your Ext MVC application
|
30
|
+
|
31
|
+
Build any app started from the base app by running this from the app's root directory:
|
32
|
+
|
33
|
+
ruby script/build all
|
34
|
+
|
35
|
+
This will examine the contents of index.html, pull out all of the javascript includes and concatenate them into
|
36
|
+
public/application-all.js. If you have the yui-compressor in your vendor directory (this is included by default)
|
37
|
+
and you have java installed, the build process will also minify your application-all.js into application-all-min.js.
|
38
|
+
|
39
|
+
Building your app also concatenates any CSS includes in index.html into public/application-all.css.
|
40
|
+
|
41
|
+
*NOTE*: Building looks at your index.html, NOT public/index.html. index.html is your development version,
|
42
|
+
public/index.html should simply include those concatenated/minified files.
|
43
|
+
|
44
|
+
=== Autobuild
|
45
|
+
|
46
|
+
If you need your app to be built every time you change any of the source files for whatever reason, use:
|
47
|
+
|
48
|
+
ruby script/build auto
|
49
|
+
|
50
|
+
This will again look at index.html and will force a rebuild any time any of those files are changed.
|
51
|
+
|
52
|
+
=== Other app build options
|
53
|
+
|
54
|
+
There are several other build commands, most of which are used by the two above:
|
55
|
+
|
56
|
+
- ruby script/build css - only build CSS files, no JS concatenation or minification
|
57
|
+
- ruby script/build js - only builds JS files, not CSS
|
58
|
+
- ruby script/build concatenate_js - concatenates but does not attempt to minify your JS
|
59
|
+
- ruby script/build minify_js - minifies an already concatenated public/application-all.js file
|
60
|
+
|
61
|
+
=== Building Ext MVC
|
62
|
+
|
63
|
+
If you are changing Ext MVC files and need to build Ext MVC itself, use:
|
64
|
+
|
65
|
+
- ruby script/build mvc
|
66
|
+
- ruby script/build mvc_auto
|
67
|
+
|
68
|
+
Again run from the app root directory. Like with ruby script/build auto, mvc_auto automatically rebuilds whenever
|
69
|
+
any Ext MVC file is changed.
|
@@ -0,0 +1,278 @@
|
|
1
|
+
/**
|
2
|
+
* @class ExtMVC.controller.Controller
|
3
|
+
* @extends Ext.util.Observable
|
4
|
+
* <h1>Controllers in Ext MVC</h1>
|
5
|
+
* <p>Controllers are the glue that stick applications together. They listen to events emitted by the UI as the user
|
6
|
+
* clicks interface elements, and take actions as appropriate. The relevant action may be to create or save a model
|
7
|
+
* instance, to render another view, to perform AJAX requests, or any other action.</p>
|
8
|
+
*
|
9
|
+
* <p>Controllers should be kept skinny as far as possible - receive an event, then hand any processing off to the
|
10
|
+
* appropriate model. This ensures we can keep the code as DRY as possible and makes refactoring easier.</p>
|
11
|
+
*
|
12
|
+
* <h2>Example Controller</h2>
|
13
|
+
* Here is a simple example controller which renders a couple of views and listens to events:
|
14
|
+
<pre><code>
|
15
|
+
//simple controller which manages the Page model within our application
|
16
|
+
MyApp.controllers.PagesController = Ext.extend(ExtMVC.controller.Controller, {
|
17
|
+
name: 'pages',
|
18
|
+
|
19
|
+
//renders the 'Index' template and sets up listeners
|
20
|
+
index: function() {
|
21
|
+
this.render('Index', {
|
22
|
+
listeners: {
|
23
|
+
scope : this,
|
24
|
+
'edit' : this.edit,
|
25
|
+
'delete': this.destroy
|
26
|
+
}
|
27
|
+
});
|
28
|
+
},
|
29
|
+
|
30
|
+
//renders the 'Edit' template (let's say it's a FormPanel), and loads the instance
|
31
|
+
edit: function(instance) {
|
32
|
+
this.render('Edit', {
|
33
|
+
listeners: {
|
34
|
+
scope : this,
|
35
|
+
save : this.update,
|
36
|
+
cancel : function() {
|
37
|
+
alert("You cancelled the update!");
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}).loadRecord(instance);
|
41
|
+
},
|
42
|
+
|
43
|
+
//when the 'delete' event is fired by our 'Index' template (see the index action), this method is called.
|
44
|
+
//In this fictional example, we assume that the templates 'delete' event was called with the single argument
|
45
|
+
//of the Page instance the user wishes to destroy
|
46
|
+
destroy: function(instance) {
|
47
|
+
instance.destroy({
|
48
|
+
success: function() {
|
49
|
+
alert("The Page was deleted");
|
50
|
+
//at this point we might render another page for the user to look at
|
51
|
+
},
|
52
|
+
failure: function() {
|
53
|
+
alert('Curses! The Page could not be deleted');
|
54
|
+
}
|
55
|
+
});
|
56
|
+
},
|
57
|
+
|
58
|
+
//when the 'save' event is fired by our 'Edit' template, this method is called.
|
59
|
+
//Again, we assume that our template fired the event with the Page instance, and also an object with updates
|
60
|
+
update: function(instance, updates) {
|
61
|
+
//this applies the updates to the model instance and saves
|
62
|
+
instance.update(updates, {
|
63
|
+
success: function(updatedInstance) {
|
64
|
+
alert('Success! It saved');
|
65
|
+
//at this point we might render another page for the user to look at
|
66
|
+
},
|
67
|
+
failure: function(updatedInstance) {
|
68
|
+
alert('Darn it. Did not save');
|
69
|
+
|
70
|
+
//here we're firing the controller's update-failed event, which the view can pick up on
|
71
|
+
//The view can simply listen to our Pages controller and add errors from this instance to the form
|
72
|
+
//using form.markInvalid(instance.errors.forForm())
|
73
|
+
this.fireEvent('update-failed', instance);
|
74
|
+
};
|
75
|
+
});
|
76
|
+
},
|
77
|
+
|
78
|
+
//Sets up events emitted by this controller. Controllers are expected to fire events, so this method is called
|
79
|
+
//automatically when a controller is instantiated. Don't forget to call super here
|
80
|
+
initEvents: function() {
|
81
|
+
this.addEvents(
|
82
|
+
//this event will be fired when the controller can't update a Page instance
|
83
|
+
'update-failed'
|
84
|
+
);
|
85
|
+
|
86
|
+
MyApp.controllers.PagesController.superclass.initEvents.apply(this, arguments);
|
87
|
+
}
|
88
|
+
})
|
89
|
+
</code></pre>
|
90
|
+
* Note that many of the methods above are provided by the {@link ExtMVC.controller.CrudController CrudController}
|
91
|
+
*
|
92
|
+
* <h2>Rendering Views</h2>
|
93
|
+
* Each controller can automatically render view classes inside its views package. In the Pages controller above the
|
94
|
+
* views package is MyApp.views.pages - the application itself is called MyApp, and the 'pages' segment comes from the
|
95
|
+
* controller's 'name' property
|
96
|
+
* <br />
|
97
|
+
* <br />
|
98
|
+
* In the example above, the line: <pre><code>this.render('Edit', {})</code></pre> will automatically find the
|
99
|
+
* MyApp.views.pages.Edit class, with the second argument to this.render being a config argument passed to the view's constructor.
|
100
|
+
*
|
101
|
+
* <br />
|
102
|
+
* <h4>Rendering strategies</h4>
|
103
|
+
* Not all applications will render views in the same way
|
104
|
+
*/
|
105
|
+
// ExtMVC.controller.Controller = Ext.extend(Ext.util.Observable,
|
106
|
+
ExtMVC.registerController('controller', {
|
107
|
+
|
108
|
+
constructor: function(config) {
|
109
|
+
Ext.util.Observable.prototype.constructor.apply(this, arguments);
|
110
|
+
|
111
|
+
Ext.apply(this, {
|
112
|
+
/**
|
113
|
+
* @property renderStrategies
|
114
|
+
* @type Object
|
115
|
+
* An object of the form {xtype: function} which keys a container's xtype to the function to use
|
116
|
+
* when rendering a view to that container (see registerRenderStrategy)
|
117
|
+
*/
|
118
|
+
renderStrategies: {}
|
119
|
+
}, config || {});
|
120
|
+
|
121
|
+
this.registerDefaultRenderStrategies();
|
122
|
+
|
123
|
+
this.initEvents();
|
124
|
+
this.initListeners();
|
125
|
+
},
|
126
|
+
|
127
|
+
/**
|
128
|
+
* Registers a rendering function for a given container xtype. When a view is rendered via this.render,
|
129
|
+
* the xtype of the container it is being rendered to is compared to the registered strategy xtypes, and
|
130
|
+
* the most specific match will be used to perform the rendering.
|
131
|
+
* @param {String} xtype The container xtype to register
|
132
|
+
* @param {Function} strategy The function to call when rendering to a container of the given xtype
|
133
|
+
*/
|
134
|
+
registerRenderStrategy: function(xtype, strategy) {
|
135
|
+
this.renderStrategies[xtype] = strategy;
|
136
|
+
},
|
137
|
+
|
138
|
+
/**
|
139
|
+
* Returns the strategy function to use when rendering to the given container instance.
|
140
|
+
* @param {Ext.Container} container The container to add to
|
141
|
+
* @return {Function} The rendering strategy to use
|
142
|
+
*/
|
143
|
+
getRenderStrategy: function(container) {
|
144
|
+
var xtypes = container.getXTypes().split("/");
|
145
|
+
|
146
|
+
for (var i = xtypes.length - 1; i >= 0; i--){
|
147
|
+
var strategy = this.renderStrategies[xtypes[i]];
|
148
|
+
|
149
|
+
if (strategy != undefined) return strategy;
|
150
|
+
};
|
151
|
+
|
152
|
+
throw new Ext.Error("No render strategy could be found for the container you specified");
|
153
|
+
},
|
154
|
+
|
155
|
+
/**
|
156
|
+
* @private
|
157
|
+
* Adds the default strategies for panel and tabpanel
|
158
|
+
*/
|
159
|
+
registerDefaultRenderStrategies: function() {
|
160
|
+
this.registerRenderStrategy('panel', this.panelRenderStrategy);
|
161
|
+
this.registerRenderStrategy('tabpanel', this.tabPanelRenderStrategy);
|
162
|
+
},
|
163
|
+
|
164
|
+
/**
|
165
|
+
* Sets up events emitted by this controller. This defaults to an empty function and is
|
166
|
+
* called automatically when the controller is constructed so can simply be overridden
|
167
|
+
*/
|
168
|
+
initEvents: function() {},
|
169
|
+
|
170
|
+
/**
|
171
|
+
* Sets up events this controller listens to, and the actions the controller should take
|
172
|
+
* when each event is received. This defaults to an empty function and is called when
|
173
|
+
* the controller is constructed so can simply be overridden
|
174
|
+
*/
|
175
|
+
initListeners: function() {},
|
176
|
+
|
177
|
+
/**
|
178
|
+
* Shows the user a notification message. Usually used to inform user of a successful save, deletion, etc
|
179
|
+
* This is an empty function which you must implement yourself
|
180
|
+
* @param {String} notice The string notice to display
|
181
|
+
*/
|
182
|
+
showNotice: function(notice) {},
|
183
|
+
|
184
|
+
/**
|
185
|
+
* @property addTo
|
186
|
+
* @type Ext.Container
|
187
|
+
* The container to add views to using the 'add' renderMethod. Usually set to an Ext.TabPanel instance or similar
|
188
|
+
*/
|
189
|
+
addTo: null,
|
190
|
+
|
191
|
+
/**
|
192
|
+
* Renders a given view name in the way set up by the controller. For this to work you must have passed a
|
193
|
+
* 'name' property when creating the controller, which is automatically used to find the view namespace for
|
194
|
+
* this controller. For example, in an application called MyApp, and a controller with a name of 'users',
|
195
|
+
* the view namespace would be MyApp.views.users, and render('Index') would search for a class called
|
196
|
+
* MyApp.views.users.Index and instantiate it with the passed config.
|
197
|
+
* An error is thrown if the view could not be found.
|
198
|
+
* @param {String} viewName The name of the view class within the view namespace used by this controller
|
199
|
+
* @param {Object} config Configuration options passed through to the view class' constructor
|
200
|
+
* @return {Ext.Component} The view object that was just created
|
201
|
+
*/
|
202
|
+
render: function render() {
|
203
|
+
//handle both method signatures
|
204
|
+
switch(arguments.length) {
|
205
|
+
case 1:
|
206
|
+
//this just falls through into case 2, which provides a config {} if one is not supplied
|
207
|
+
case 2:
|
208
|
+
var namespace = this.name,
|
209
|
+
viewName = arguments[0],
|
210
|
+
config = arguments[1] || {};
|
211
|
+
break;
|
212
|
+
case 3:
|
213
|
+
var namespace = arguments[0],
|
214
|
+
viewName = arguments[1],
|
215
|
+
config = arguments[2] || {};
|
216
|
+
break;
|
217
|
+
}
|
218
|
+
|
219
|
+
//we also use this constructor object to define whether or not the view should be added to the default
|
220
|
+
//container or not
|
221
|
+
Ext.applyIf(config, {
|
222
|
+
autoAdd: true,
|
223
|
+
addTo : ExtMVC.app.main
|
224
|
+
});
|
225
|
+
|
226
|
+
//NOTE: ExtMVC.getView will throw an error if the view hasn't been defined anywhere yet. At the moment this
|
227
|
+
//error will just propagate up as it's probably pretty clear, but we could provide a custom Error message here instead
|
228
|
+
var view = new (this.getView(namespace, viewName))(config);
|
229
|
+
|
230
|
+
if (config.autoAdd === true) {
|
231
|
+
if (view.isXType('window')) {
|
232
|
+
view.show();
|
233
|
+
} else {
|
234
|
+
this.getRenderStrategy(config.addTo)(config.addTo, view);
|
235
|
+
}
|
236
|
+
}
|
237
|
+
|
238
|
+
return view;
|
239
|
+
},
|
240
|
+
|
241
|
+
/**
|
242
|
+
* Just calls ExtMVC.getView and returns. This is here because we override it in Crud Controller
|
243
|
+
* @param {String} namespace The view namespace
|
244
|
+
* @param {String} name The view name
|
245
|
+
* @return {Function} The view constructor function
|
246
|
+
*/
|
247
|
+
getView: function(namespace, name) {
|
248
|
+
return ExtMVC.getView(namespace, name);
|
249
|
+
},
|
250
|
+
|
251
|
+
/**
|
252
|
+
* @private
|
253
|
+
* The tabpanel render strategy
|
254
|
+
*/
|
255
|
+
tabPanelRenderStrategy: function(container, view) {
|
256
|
+
var existing = container.getItem(view.id);
|
257
|
+
|
258
|
+
//don't add a tab with the same id as an existing one
|
259
|
+
if (existing == undefined) {
|
260
|
+
container.add(view);
|
261
|
+
container.doLayout();
|
262
|
+
container.activate(view);
|
263
|
+
} else {
|
264
|
+
container.setActiveTab(view.id);
|
265
|
+
view.destroy();
|
266
|
+
}
|
267
|
+
},
|
268
|
+
|
269
|
+
/**
|
270
|
+
* @private
|
271
|
+
* The panel render strategy
|
272
|
+
*/
|
273
|
+
panelRenderStrategy: function(container, view) {
|
274
|
+
container.removeAll();
|
275
|
+
container.add(view);
|
276
|
+
container.doLayout();
|
277
|
+
}
|
278
|
+
});
|