Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / src / app / Application.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.app.Application
17  * @extend Ext.app.Controller
18  * 
19  * Represents an Ext JS 4 application, which is typically a single page app using a {@link Ext.container.Viewport Viewport}.
20  * A typical Ext.app.Application might look like this:
21  * 
22  *     Ext.application({
23  *         name: 'MyApp',
24  *         launch: function() {
25  *             Ext.create('Ext.container.Viewport', {
26  *                 items: {
27  *                     html: 'My App'
28  *                 }
29  *             });
30  *         }
31  *     });
32  * 
33  * This does several things. First it creates a global variable called 'MyApp' - all of your Application's classes (such
34  * as its Models, Views and Controllers) will reside under this single namespace, which drastically lowers the chances
35  * of colliding global variables.
36  * 
37  * When the page is ready and all of your JavaScript has loaded, your Application's {@link #launch} function is called,
38  * at which time you can run the code that starts your app. Usually this consists of creating a Viewport, as we do in
39  * the example above.
40  * 
41  * <u>Telling Application about the rest of the app</u>
42  * 
43  * Because an Ext.app.Application represents an entire app, we should tell it about the other parts of the app - namely
44  * the Models, Views and Controllers that are bundled with the application. Let's say we have a blog management app; we
45  * might have Models and Controllers for Posts and Comments, and Views for listing, adding and editing Posts and Comments.
46  * Here's how we'd tell our Application about all these things:
47  * 
48  *     Ext.application({
49  *         name: 'Blog',
50  *         models: ['Post', 'Comment'],
51  *         controllers: ['Posts', 'Comments'],
52  *     
53  *         launch: function() {
54  *             ...
55  *         }
56  *     });
57  * 
58  * Note that we didn't actually list the Views directly in the Application itself. This is because Views are managed by
59  * Controllers, so it makes sense to keep those dependencies there. The Application will load each of the specified 
60  * Controllers using the pathing conventions laid out in the <a href="../guide/application_architecture">application 
61  * architecture guide</a> - in this case expecting the controllers to reside in app/controller/Posts.js and
62  * app/controller/Comments.js. In turn, each Controller simply needs to list the Views it uses and they will be
63  * automatically loaded. Here's how our Posts controller like be defined:
64  * 
65  *     Ext.define('MyApp.controller.Posts', {
66  *         extend: 'Ext.app.Controller',
67  *         views: ['posts.List', 'posts.Edit'],
68  *     
69  *         //the rest of the Controller here
70  *     });
71  * 
72  * Because we told our Application about our Models and Controllers, and our Controllers about their Views, Ext JS will
73  * automatically load all of our app files for us. This means we don't have to manually add script tags into our html
74  * files whenever we add a new class, but more importantly it enables us to create a minimized build of our entire 
75  * application using the Ext JS 4 SDK Tools.
76  * 
77  * For more information about writing Ext JS 4 applications, please see the
78  * [application architecture guide](#/guide/application_architecture).
79  * 
80  * @docauthor Ed Spencer
81  */
82 Ext.define('Ext.app.Application', {
83     extend: 'Ext.app.Controller',
84
85     requires: [
86         'Ext.ModelManager',
87         'Ext.data.Model',
88         'Ext.data.StoreManager',
89         'Ext.tip.QuickTipManager',
90         'Ext.ComponentManager',
91         'Ext.app.EventBus'
92     ],
93
94     /**
95      * @cfg {String} name The name of your application. This will also be the namespace for your views, controllers
96      * models and stores. Don't use spaces or special characters in the name.
97      */
98
99     /**
100      * @cfg {Object} scope The scope to execute the {@link #launch} function in. Defaults to the Application
101      * instance.
102      */
103     scope: undefined,
104
105     /**
106      * @cfg {Boolean} enableQuickTips True to automatically set up Ext.tip.QuickTip support (defaults to true)
107      */
108     enableQuickTips: true,
109
110     /**
111      * @cfg {String} defaultUrl When the app is first loaded, this url will be redirected to. Defaults to undefined
112      */
113
114     /**
115      * @cfg {String} appFolder The path to the directory which contains all application's classes.
116      * This path will be registered via {@link Ext.Loader#setPath} for the namespace specified in the {@link #name name} config.
117      * Defaults to 'app'
118      */
119     appFolder: 'app',
120
121     /**
122      * @cfg {Boolean} autoCreateViewport True to automatically load and instantiate AppName.view.Viewport
123      * before firing the launch function (defaults to false).
124      */
125     autoCreateViewport: false,
126
127     /**
128      * Creates new Application.
129      * @param {Object} config (optional) Config object.
130      */
131     constructor: function(config) {
132         config = config || {};
133         Ext.apply(this, config);
134
135         var requires = config.requires || [];
136
137         Ext.Loader.setPath(this.name, this.appFolder);
138
139         if (this.paths) {
140             Ext.Object.each(this.paths, function(key, value) {
141                 Ext.Loader.setPath(key, value);
142             });
143         }
144
145         this.callParent(arguments);
146
147         this.eventbus = Ext.create('Ext.app.EventBus');
148
149         var controllers = Ext.Array.from(this.controllers),
150             ln = controllers && controllers.length,
151             i, controller;
152
153         this.controllers = Ext.create('Ext.util.MixedCollection');
154
155         if (this.autoCreateViewport) {
156             requires.push(this.getModuleClassName('Viewport', 'view'));
157         }
158
159         for (i = 0; i < ln; i++) {
160             requires.push(this.getModuleClassName(controllers[i], 'controller'));
161         }
162
163         Ext.require(requires);
164
165         Ext.onReady(function() {
166             for (i = 0; i < ln; i++) {
167                 controller = this.getController(controllers[i]);
168                 controller.init(this);
169             }
170
171             this.onBeforeLaunch.call(this);
172         }, this);
173     },
174
175     control: function(selectors, listeners, controller) {
176         this.eventbus.control(selectors, listeners, controller);
177     },
178
179     /**
180      * Called automatically when the page has completely loaded. This is an empty function that should be
181      * overridden by each application that needs to take action on page load
182      * @property launch
183      * @type Function
184      * @param {String} profile The detected {@link #profiles application profile}
185      * @return {Boolean} By default, the Application will dispatch to the configured startup controller and
186      * action immediately after running the launch function. Return false to prevent this behavior.
187      */
188     launch: Ext.emptyFn,
189
190     /**
191      * @private
192      */
193     onBeforeLaunch: function() {
194         if (this.enableQuickTips) {
195             Ext.tip.QuickTipManager.init();
196         }
197
198         if (this.autoCreateViewport) {
199             this.getView('Viewport').create();
200         }
201
202         this.launch.call(this.scope || this);
203         this.launched = true;
204         this.fireEvent('launch', this);
205
206         this.controllers.each(function(controller) {
207             controller.onLaunch(this);
208         }, this);
209     },
210
211     getModuleClassName: function(name, type) {
212         var namespace = Ext.Loader.getPrefix(name);
213
214         if (namespace.length > 0 && namespace !== name) {
215             return name;
216         }
217
218         return this.name + '.' + type + '.' + name;
219     },
220
221     getController: function(name) {
222         var controller = this.controllers.get(name);
223
224         if (!controller) {
225             controller = Ext.create(this.getModuleClassName(name, 'controller'), {
226                 application: this,
227                 id: name
228             });
229
230             this.controllers.add(controller);
231         }
232
233         return controller;
234     },
235
236     getStore: function(name) {
237         var store = Ext.StoreManager.get(name);
238
239         if (!store) {
240             store = Ext.create(this.getModuleClassName(name, 'store'), {
241                 storeId: name
242             });
243         }
244
245         return store;
246     },
247
248     getModel: function(model) {
249         model = this.getModuleClassName(model, 'model');
250
251         return Ext.ModelManager.getModel(model);
252     },
253
254     getView: function(view) {
255         view = this.getModuleClassName(view, 'view');
256
257         return Ext.ClassManager.get(view);
258     }
259 });
260