linuxwindowsinboxwhatsappicloudtweetdeckhipchattelegramhangoutsslackgmailskypefacebook-workplaceoutlookemailmicrosoft-teamsdiscordmessengercustom-servicesmacos
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
621 lines
22 KiB
621 lines
22 KiB
9 years ago
|
/**
|
||
|
* @protected
|
||
|
* @class Ext.app.BaseController
|
||
|
* Base class for Controllers.
|
||
|
*
|
||
|
*/
|
||
|
Ext.define('Ext.app.BaseController', {
|
||
|
requires: [
|
||
|
'Ext.app.EventBus',
|
||
|
'Ext.app.domain.Global'
|
||
|
],
|
||
|
|
||
|
uses: [
|
||
|
'Ext.app.domain.Controller'
|
||
|
],
|
||
|
|
||
|
mixins: ['Ext.mixin.Observable'],
|
||
|
|
||
|
isController: true,
|
||
|
|
||
|
config : {
|
||
|
/**
|
||
|
* @cfg {String} id The id of this controller. You can use this id when dispatching.
|
||
|
*
|
||
|
* For an example of dispatching, see the examples under the
|
||
|
* {@link Ext.app.Controller#cfg-listen listen} config.
|
||
|
*
|
||
|
* If an id is not explicitly set, it will default to the controller's full classname.
|
||
|
*
|
||
|
* @accessor
|
||
|
*/
|
||
|
id: null,
|
||
|
|
||
|
/**
|
||
|
* @cfg {Object} control
|
||
|
* @accessor
|
||
|
*
|
||
|
* Adds listeners to components selected via {@link Ext.ComponentQuery}. Accepts an
|
||
|
* object containing component paths mapped to a hash of listener functions.
|
||
|
* The function value may also be a string matching the name of a method on the
|
||
|
* controller.
|
||
|
*
|
||
|
* In the following example the `updateUser` function is mapped to to the `click`
|
||
|
* event on a button component, which is a child of the `useredit` component.
|
||
|
*
|
||
|
* Ext.define('MyApp.controller.Users', {
|
||
|
* extend: 'Ext.app.Controller',
|
||
|
*
|
||
|
* control: {
|
||
|
* 'useredit button[action=save]': {
|
||
|
* click: 'updateUser'
|
||
|
* }
|
||
|
* },
|
||
|
*
|
||
|
* updateUser: function(button) {
|
||
|
* console.log('clicked the Save button');
|
||
|
* }
|
||
|
* });
|
||
|
*
|
||
|
* The method you pass to the listener will automatically be resolved on the controller.
|
||
|
* In this case, the `updateUser` method that will get executed on the `button` `click`
|
||
|
* event will resolve to the `updateUser` method on the controller,
|
||
|
*
|
||
|
* See {@link Ext.ComponentQuery} for more information on component selectors.
|
||
|
*/
|
||
|
|
||
|
control: null,
|
||
|
|
||
|
/**
|
||
|
* @cfg {Object} listen
|
||
|
* @accessor
|
||
|
*
|
||
|
* Adds listeners to different event sources (also called "event domains"). The
|
||
|
* primary event domain is that of components, but there are also other event domains:
|
||
|
* {@link Ext.app.domain.Global Global} domain that intercepts events fired from
|
||
|
* {@link Ext.GlobalEvents} Observable instance,
|
||
|
* {@link Ext.app.domain.Controller Controller} domain can be used to listen to events
|
||
|
* fired by other Controllers, {@link Ext.app.domain.Store Store} domain gives access to
|
||
|
* Store events, and {@link Ext.app.domain.Direct Direct} domain can be used with
|
||
|
* Ext.Direct Providers to listen to their events.
|
||
|
*
|
||
|
* To listen to "bar" events fired by a controller with id="foo":
|
||
|
*
|
||
|
* Ext.define('AM.controller.Users', {
|
||
|
* extend: 'Ext.app.Controller',
|
||
|
*
|
||
|
* listen: {
|
||
|
* controller: {
|
||
|
* '#foo': {
|
||
|
* bar: 'onFooBar'
|
||
|
* }
|
||
|
* }
|
||
|
* }
|
||
|
* });
|
||
|
*
|
||
|
* To listen to "bar" events fired by any controller, and "baz" events
|
||
|
* fired by Store with storeId="baz":
|
||
|
*
|
||
|
* Ext.define('AM.controller.Users', {
|
||
|
* extend: 'Ext.app.Controller',
|
||
|
*
|
||
|
* listen: {
|
||
|
* controller: {
|
||
|
* '*': {
|
||
|
* bar: 'onAnyControllerBar'
|
||
|
* }
|
||
|
* },
|
||
|
* store: {
|
||
|
* '#baz': {
|
||
|
* baz: 'onStoreBaz'
|
||
|
* }
|
||
|
* }
|
||
|
* }
|
||
|
* });
|
||
|
*
|
||
|
* To listen to "idle" events fired by {@link Ext.GlobalEvents} when other event
|
||
|
* processing is complete and Ext JS is about to return control to the browser:
|
||
|
*
|
||
|
* Ext.define('AM.controller.Users', {
|
||
|
* extend: 'Ext.app.Controller',
|
||
|
*
|
||
|
* listen: {
|
||
|
* global: { // Global events are always fired
|
||
|
* idle: 'onIdle' // from the same object, so there
|
||
|
* } // are no selectors
|
||
|
* }
|
||
|
* });
|
||
|
*
|
||
|
* As this relates to components, the following example:
|
||
|
*
|
||
|
* Ext.define('AM.controller.Users', {
|
||
|
* extend: 'Ext.app.Controller',
|
||
|
*
|
||
|
* listen: {
|
||
|
* component: {
|
||
|
* 'useredit button[action=save]': {
|
||
|
* click: 'updateUser'
|
||
|
* }
|
||
|
* }
|
||
|
* }
|
||
|
* });
|
||
|
*
|
||
|
* Is equivalent to:
|
||
|
*
|
||
|
* Ext.define('AM.controller.Users', {
|
||
|
* extend: 'Ext.app.Controller',
|
||
|
*
|
||
|
* control: {
|
||
|
* 'useredit button[action=save]': {
|
||
|
* click: 'updateUser'
|
||
|
* }
|
||
|
* }
|
||
|
* });
|
||
|
*
|
||
|
* Of course, these can all be combined in a single call and used instead of
|
||
|
* `control`, like so:
|
||
|
*
|
||
|
* Ext.define('AM.controller.Users', {
|
||
|
* extend: 'Ext.app.Controller',
|
||
|
*
|
||
|
* listen: {
|
||
|
* global: {
|
||
|
* idle: 'onIdle'
|
||
|
* },
|
||
|
* controller: {
|
||
|
* '*': {
|
||
|
* foobar: 'onAnyFooBar'
|
||
|
* },
|
||
|
* '#foo': {
|
||
|
* bar: 'onFooBar'
|
||
|
* }
|
||
|
* },
|
||
|
* component: {
|
||
|
* 'useredit button[action=save]': {
|
||
|
* click: 'updateUser'
|
||
|
* }
|
||
|
* },
|
||
|
* store: {
|
||
|
* '#qux': {
|
||
|
* load: 'onQuxLoad'
|
||
|
* }
|
||
|
* }
|
||
|
* }
|
||
|
* });
|
||
|
*/
|
||
|
listen: null,
|
||
|
|
||
|
/**
|
||
|
* @cfg {Object} routes
|
||
|
* @accessor
|
||
|
*
|
||
|
* An object of routes to handle hash changes. A route can be defined in a simple way:
|
||
|
*
|
||
|
* routes : {
|
||
|
* 'foo/bar' : 'handleFoo',
|
||
|
* 'user/:id' : 'showUser'
|
||
|
* }
|
||
|
*
|
||
|
* Where the property is the hash (which can accept a parameter defined by a colon) and the value
|
||
|
* is the method on the controller to execute. The parameters will get sent in the action method.
|
||
|
*
|
||
|
* At the application level, you can define a event that will be executed when no matching
|
||
|
* routes are found.
|
||
|
*
|
||
|
* Ext.application({
|
||
|
* name: 'MyApp',
|
||
|
* listen: {
|
||
|
* controller: {
|
||
|
* '#': {
|
||
|
* unmatchedroute: 'onUnmatchedRoute'
|
||
|
* }
|
||
|
* }
|
||
|
* },
|
||
|
*
|
||
|
* onUnmatchedRoute: function(hash) {
|
||
|
* console.log('Unmatched', hash);
|
||
|
* // Do something...
|
||
|
* }
|
||
|
* });
|
||
|
*
|
||
|
* There is also a complex means of defining a route where you can use a before action and even
|
||
|
* specify your own RegEx for the parameter:
|
||
|
*
|
||
|
* routes : {
|
||
|
* 'foo/bar' : {
|
||
|
* action : 'handleFoo',
|
||
|
* before : 'beforeHandleFoo'
|
||
|
* },
|
||
|
* 'user/:id' : {
|
||
|
* action : 'showUser',
|
||
|
* before : 'beforeShowUser',
|
||
|
* conditions : {
|
||
|
* ':id' : '([0-9]+)'
|
||
|
* }
|
||
|
* }
|
||
|
* }
|
||
|
*
|
||
|
* This will only match if the `id` parameter is a number.
|
||
|
*
|
||
|
* The before action allows you to cancel an action. Every before action will get passed an `action` argument with
|
||
|
* a `resume` and `stop` methods as the last argument of the method and you *MUST* execute either method:
|
||
|
*
|
||
|
* beforeHandleFoo : function(action) {
|
||
|
* //some logic here
|
||
|
*
|
||
|
* //this will allow the handleFoo action to be executed
|
||
|
* action.resume();
|
||
|
* },
|
||
|
* handleFoo : function() {
|
||
|
* //will get executed due to true being passed in callback in beforeHandleFoo
|
||
|
* },
|
||
|
* beforeShowUser : function(id, action) {
|
||
|
* //allows for async process like an Ajax
|
||
|
* Ext.Ajax.request({
|
||
|
* url : 'foo.php',
|
||
|
* success : function() {
|
||
|
* //will not allow the showUser method to be executed but will continue other queued actions.
|
||
|
* action.stop();
|
||
|
* },
|
||
|
* failure : function() {
|
||
|
* //will not allow the showUser method to be executed and will not allow other queued actions to be executed.
|
||
|
* action.stop(true);
|
||
|
* }
|
||
|
* });
|
||
|
* },
|
||
|
* showUser : function(id) {
|
||
|
* //will not get executed due to false being passed in callback in beforeShowUser
|
||
|
* }
|
||
|
*
|
||
|
* You *MUST* execute the `resume` or `stop` method on the `action` argument. Executing `action.resume();` will continue
|
||
|
* the action, `action.stop();` will not allow the action to resume but will allow other queued actions to resume,
|
||
|
* `action.stop(true);` will not allow the action and any other queued actions to resume.
|
||
|
*
|
||
|
* The default RegEx that will be used is `([%a-zA-Z0-9\\-\\_\\s,]+)` but you can specify any
|
||
|
* that may suit what you need to accomplish. An example of an advanced condition may be to make
|
||
|
* a parameter optional and case-insensitive:
|
||
|
*
|
||
|
* routes : {
|
||
|
* 'user:id' : {
|
||
|
* action : 'showUser',
|
||
|
* before : 'beforeShowUser',
|
||
|
* conditions : {
|
||
|
* ':id' : '(?:(?:\/){1}([%a-z0-9_,\s\-]+))?'
|
||
|
* }
|
||
|
* }
|
||
|
* }
|
||
|
*/
|
||
|
routes : null,
|
||
|
before : null
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Creates new Controller.
|
||
|
*
|
||
|
* @param {Object} [config] Configuration object.
|
||
|
*/
|
||
|
constructor: function(config) {
|
||
|
var me = this;
|
||
|
|
||
|
// In versions prior to 5.1, this constructor used to call the Ext.util.Observable
|
||
|
// constructor (which applied the config properties directly to the instance)
|
||
|
// AND it used to call initConfig as well. Since the constructor of
|
||
|
// Ext.mixin.Observable calls initConfig, but does not apply the properties to
|
||
|
// the instance, we do that here for backward compatibility.
|
||
|
Ext.apply(me, config);
|
||
|
// The control and listen properties are also methods so we need to delete them
|
||
|
// from the instance after applying the config object.
|
||
|
delete me.control;
|
||
|
delete me.listen;
|
||
|
|
||
|
me.eventbus = Ext.app.EventBus;
|
||
|
|
||
|
//need to have eventbus property set before we initialize the config
|
||
|
me.mixins.observable.constructor.call(me, config);
|
||
|
// Assuming we haven't set this in updateControl or updateListen, force it here
|
||
|
me.ensureId();
|
||
|
},
|
||
|
|
||
|
applyListen: function(listen) {
|
||
|
if (Ext.isObject(listen)) {
|
||
|
listen = Ext.clone(listen);
|
||
|
}
|
||
|
|
||
|
return listen;
|
||
|
},
|
||
|
|
||
|
applyControl: function(control) {
|
||
|
if (Ext.isObject(control)) {
|
||
|
control = Ext.clone(control);
|
||
|
}
|
||
|
|
||
|
return control;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @param {Object} control The object to pass to the {@link #method-control} method
|
||
|
* @private
|
||
|
*/
|
||
|
updateControl: function(control) {
|
||
|
this.ensureId();
|
||
|
if (control) {
|
||
|
this.control(control);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @param {Object} listen The object to pass to the {@link #method-listen} method
|
||
|
* @private
|
||
|
*/
|
||
|
updateListen: function(listen) {
|
||
|
this.ensureId();
|
||
|
if (listen) {
|
||
|
this.listen(listen);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @param {Object} routes The routes to connect to the {@link Ext.app.route.Router}
|
||
|
* @private
|
||
|
*/
|
||
|
updateRoutes : function(routes) {
|
||
|
if (routes) {
|
||
|
var me = this,
|
||
|
befores = me.getBefore() || {},
|
||
|
Router = Ext.app.route.Router,
|
||
|
url, config, method;
|
||
|
|
||
|
for (url in routes) {
|
||
|
config = routes[url];
|
||
|
|
||
|
if (Ext.isString(config)) {
|
||
|
config = {
|
||
|
action : config
|
||
|
};
|
||
|
}
|
||
|
|
||
|
method = config.action;
|
||
|
|
||
|
if (!config.before) {
|
||
|
config.before = befores[method];
|
||
|
}
|
||
|
//<debug>
|
||
|
else if (befores[method]) {
|
||
|
Ext.log.warn('You have a before method configured on a route ("' + url + '") and in the before object property also in the "' +
|
||
|
me.self.getName() + '" controller. Will use the before method in the route and disregard the one in the before property.');
|
||
|
}
|
||
|
//</debug>
|
||
|
|
||
|
//connect the route config to the Router
|
||
|
Router.connect(url, config, me);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
isActive: function() {
|
||
|
return true;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Adds listeners to components selected via {@link Ext.ComponentQuery}. Accepts an
|
||
|
* object containing component paths mapped to a hash of listener functions.
|
||
|
*
|
||
|
* In the following example the `updateUser` function is mapped to to the `click`
|
||
|
* event on a button component, which is a child of the `useredit` component.
|
||
|
*
|
||
|
* Ext.define('AM.controller.Users', {
|
||
|
* init: function() {
|
||
|
* this.control({
|
||
|
* 'useredit button[action=save]': {
|
||
|
* click: this.updateUser
|
||
|
* }
|
||
|
* });
|
||
|
* },
|
||
|
*
|
||
|
* updateUser: function(button) {
|
||
|
* console.log('clicked the Save button');
|
||
|
* }
|
||
|
* });
|
||
|
*
|
||
|
* Or alternatively one call `control` with two arguments:
|
||
|
*
|
||
|
* this.control('useredit button[action=save]', {
|
||
|
* click: this.updateUser
|
||
|
* });
|
||
|
*
|
||
|
* See {@link Ext.ComponentQuery} for more information on component selectors.
|
||
|
*
|
||
|
* @param {String/Object} selectors If a String, the second argument is used as the
|
||
|
* listeners, otherwise an object of selectors -> listeners is assumed
|
||
|
* @param {Object} [listeners] Config for listeners.
|
||
|
*/
|
||
|
control: function(selectors, listeners, controller) {
|
||
|
var me = this,
|
||
|
ctrl = controller,
|
||
|
obj;
|
||
|
|
||
|
if (Ext.isString(selectors)) {
|
||
|
obj = {};
|
||
|
obj[selectors] = listeners;
|
||
|
}
|
||
|
else {
|
||
|
obj = selectors;
|
||
|
ctrl = listeners;
|
||
|
}
|
||
|
|
||
|
me.eventbus.control(obj, ctrl || me);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Adds listeners to different event sources (also called "event domains"). The
|
||
|
* primary event domain is that of components, but there are also other event domains:
|
||
|
* {@link Ext.app.domain.Global Global} domain that intercepts events fired from
|
||
|
* {@link Ext.GlobalEvents} Observable instance, {@link Ext.app.domain.Controller Controller}
|
||
|
* domain can be used to listen to events fired by other Controllers,
|
||
|
* {@link Ext.app.domain.Store Store} domain gives access to Store events, and
|
||
|
* {@link Ext.app.domain.Direct Direct} domain can be used with Ext.Direct Providers
|
||
|
* to listen to their events.
|
||
|
*
|
||
|
* To listen to "bar" events fired by a controller with id="foo":
|
||
|
*
|
||
|
* Ext.define('AM.controller.Users', {
|
||
|
* init: function() {
|
||
|
* this.listen({
|
||
|
* controller: {
|
||
|
* '#foo': {
|
||
|
* bar: this.onFooBar
|
||
|
* }
|
||
|
* }
|
||
|
* });
|
||
|
* },
|
||
|
* ...
|
||
|
* });
|
||
|
*
|
||
|
* To listen to "bar" events fired by any controller, and "baz" events
|
||
|
* fired by Store with storeId="baz":
|
||
|
*
|
||
|
* Ext.define('AM.controller.Users', {
|
||
|
* init: function() {
|
||
|
* this.listen({
|
||
|
* controller: {
|
||
|
* '*': {
|
||
|
* bar: this.onAnyControllerBar
|
||
|
* }
|
||
|
* },
|
||
|
* store: {
|
||
|
* '#baz': {
|
||
|
* baz: this.onStoreBaz
|
||
|
* }
|
||
|
* }
|
||
|
* });
|
||
|
* },
|
||
|
* ...
|
||
|
* });
|
||
|
*
|
||
|
* To listen to "idle" events fired by {@link Ext.GlobalEvents} when other event
|
||
|
* processing is complete and Ext JS is about to return control to the browser:
|
||
|
*
|
||
|
* Ext.define('AM.controller.Users', {
|
||
|
* init: function() {
|
||
|
* this.listen({
|
||
|
* global: { // Global events are always fired
|
||
|
* idle: this.onIdle // from the same object, so there
|
||
|
* } // are no selectors
|
||
|
* });
|
||
|
* }
|
||
|
* });
|
||
|
*
|
||
|
* As this relates to components, the following example:
|
||
|
*
|
||
|
* Ext.define('AM.controller.Users', {
|
||
|
* init: function() {
|
||
|
* this.listen({
|
||
|
* component: {
|
||
|
* 'useredit button[action=save]': {
|
||
|
* click: this.updateUser
|
||
|
* }
|
||
|
* }
|
||
|
* });
|
||
|
* },
|
||
|
* ...
|
||
|
* });
|
||
|
*
|
||
|
* Is equivalent to:
|
||
|
*
|
||
|
* Ext.define('AM.controller.Users', {
|
||
|
* init: function() {
|
||
|
* this.control({
|
||
|
* 'useredit button[action=save]': {
|
||
|
* click: this.updateUser
|
||
|
* }
|
||
|
* });
|
||
|
* },
|
||
|
* ...
|
||
|
* });
|
||
|
*
|
||
|
* Of course, these can all be combined in a single call and used instead of
|
||
|
* `control`, like so:
|
||
|
*
|
||
|
* Ext.define('AM.controller.Users', {
|
||
|
* init: function() {
|
||
|
* this.listen({
|
||
|
* global: {
|
||
|
* idle: this.onIdle
|
||
|
* },
|
||
|
* controller: {
|
||
|
* '*': {
|
||
|
* foobar: this.onAnyFooBar
|
||
|
* },
|
||
|
* '#foo': {
|
||
|
* bar: this.onFooBar
|
||
|
* }
|
||
|
* },
|
||
|
* component: {
|
||
|
* 'useredit button[action=save]': {
|
||
|
* click: this.updateUser
|
||
|
* }
|
||
|
* },
|
||
|
* store: {
|
||
|
* '#qux': {
|
||
|
* load: this.onQuxLoad
|
||
|
* }
|
||
|
* }
|
||
|
* });
|
||
|
* },
|
||
|
* ...
|
||
|
* });
|
||
|
*
|
||
|
* @param {Object} to Config object containing domains, selectors and listeners.
|
||
|
* @param {Ext.app.Controller} [controller] The controller to add the listeners to. Defaults to the current controller.
|
||
|
*/
|
||
|
listen: function (to, controller) {
|
||
|
this.eventbus.listen(to, controller || this);
|
||
|
},
|
||
|
|
||
|
destroy: function() {
|
||
|
var me = this,
|
||
|
bus = me.eventbus;
|
||
|
|
||
|
Ext.app.route.Router.disconnectAll(me);
|
||
|
|
||
|
if (bus) {
|
||
|
bus.unlisten(me);
|
||
|
me.eventbus = null;
|
||
|
}
|
||
|
me.clearListeners();
|
||
|
me.callParent();
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Update the hash. By default, it will not execute the routes if the current token and the
|
||
|
* token passed are the same.
|
||
|
*
|
||
|
* @param {String/Ext.data.Model} token The token to redirect to. Can be either a String
|
||
|
* or a {@link Ext.data.Model Model} instance - if a Model instance is passed it will
|
||
|
* internally be converted into a String token by calling the Model's
|
||
|
* {@link Ext.data.Model#toUrl toUrl} function.
|
||
|
*
|
||
|
* @param {Boolean} force Force the update of the hash regardless of the current token.
|
||
|
*
|
||
|
* @return {Boolean} Will return `true` if the token was updated.
|
||
|
*/
|
||
|
redirectTo: function(token, force) {
|
||
|
if (token.isModel) {
|
||
|
token = token.toUrl();
|
||
|
}
|
||
|
if (!force) {
|
||
|
var currentToken = Ext.util.History.getToken();
|
||
|
|
||
|
if (currentToken === token) {
|
||
|
return false;
|
||
|
}
|
||
|
} else {
|
||
|
Ext.app.route.Router.onStateChange(token);
|
||
|
}
|
||
|
|
||
|
Ext.util.History.add(token);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
});
|