Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed ViewController cleanup issue reported w/Sencha Touch

Deft.mvc.ViewController::onViewDestroyed() is never called on Sencha Touch (due to the differing destruction lifecycle path). Consequently, the cleanup logic implemented there is not executed on that platform.
Moved the clean-up logic to the destroy() method. This will require any subclasses to call `this.callParent()`, but that should be fairly well understood as a standard practice when overriding destroy() method.
Added associated unit tests to help prevent future regression.

Fixes #45
  • Loading branch information...
commit a5cd77603e48eb36341e13d049c23299e56e67dc 1 parent a29fb9a
@johnyanarella johnyanarella authored
View
23 build/deft-debug.js
@@ -881,6 +881,13 @@ Ext.define('Deft.mvc.ViewController', {
*/
destroy: function() {
+ var id, selector;
+ for (id in this.registeredComponentReferences) {
+ this.removeComponentReference(id);
+ }
+ for (selector in this.registeredComponentSelectors) {
+ this.removeComponentSelector(selector);
+ }
return true;
},
/**
@@ -891,9 +898,6 @@ Ext.define('Deft.mvc.ViewController', {
var config, id, listeners, live, originalViewDestroyFunction, selector, self, _ref;
if (Ext.getVersion('extjs') != null) {
this.getView().on('beforedestroy', this.onViewBeforeDestroy, this);
- this.getView().on('destroy', this.onViewDestroy, this, {
- single: true
- });
} else {
self = this;
originalViewDestroyFunction = this.getView().destroy;
@@ -942,19 +946,6 @@ Ext.define('Deft.mvc.ViewController', {
return false;
},
/**
- @private
- */
-
- onViewDestroy: function() {
- var id, selector;
- for (id in this.registeredComponentReferences) {
- this.removeComponentReference(id);
- }
- for (selector in this.registeredComponentSelectors) {
- this.removeComponentSelector(selector);
- }
- },
- /**
Add a component accessor method the ViewController for the specified view-relative selector.
*/
View
2  build/deft.js
@@ -4,4 +4,4 @@ DeftJS 0.8.0pre
Copyright (c) 2012 [DeftJS Framework Contributors](http://deftjs.org)
Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License).
*/
-Ext.define("Deft.core.Class",{alternateClassName:["Deft.Class"],statics:{registerPreprocessor:function(b,d,a,c){if(Ext.getVersion("extjs")&&Ext.getVersion("core").isLessThan("4.1.0")){Ext.Class.registerPreprocessor(b,function(e,f,g){return d.call(this,e,f,f,g)}).setDefaultPreprocessorPosition(b,a,c)}else{Ext.Class.registerPreprocessor(b,function(f,g,e,h){return d.call(this,f,g,e,h)},[b],a,c)}},hookOnClassCreated:function(a,b){if(Ext.getVersion("extjs")&&Ext.getVersion("core").isLessThan("4.1.0")){Ext.Function.interceptBefore(a,"onClassCreated",b)}else{Ext.Function.interceptBefore(a,"onCreated",b)}},hookOnClassExtended:function(c,b){var a;if(Ext.getVersion("extjs")&&Ext.getVersion("core").isLessThan("4.1.0")){a=function(d,e){return b.call(this,d,e,e)}}else{a=b}if(c.onClassExtended!=null){Ext.Function.interceptBefore(c,"onClassExtended",a)}else{c.onClassExtended=a}}}});Ext.define("Deft.log.Logger",{alternateClassName:["Deft.Logger"],singleton:true,log:function(b,a){if(a==null){a="info"}},error:function(a){this.log(a,"error")},info:function(a){this.log(a,"info")},verbose:function(a){this.log(a,"verbose")},warn:function(a){this.log(a,"warn")},deprecate:function(a){this.log(a,"deprecate")}},function(){var a;if(Ext.getVersion("extjs")!=null){this.log=function(c,b){if(b==null){b="info"}if(b==="verbose"){b==="info"}if(b==="deprecate"){b="warn"}Ext.log({msg:c,level:b})}}else{if(Ext.isFunction((a=Ext.Logger)!=null?a.log:void 0)){this.log=Ext.bind(Ext.Logger.log,Ext.Logger)}}});Ext.define("Deft.util.Function",{alternateClassName:["Deft.Function"],statics:{spread:function(b,a){return function(c){if(!Ext.isArray(c)){Ext.Error.raise({msg:"Error spreading passed Array over target function arguments: passed a non-Array."})}return b.apply(a,c)}},memoize:function(d,c,a){var b;b={};return function(f){var e;e=Ext.isFunction(a)?a.apply(c,arguments):f;if(!(e in b)){b[e]=d.apply(c,arguments)}return b[e]}}}});Ext.define("Deft.event.LiveEventListener",{alternateClassName:["Deft.LiveEventListener"],constructor:function(c){var b,d,e,a;Ext.apply(this,c);this.components=[];d=Ext.ComponentQuery.query(this.selector,this.container);for(e=0,a=d.length;e<a;e++){b=d[e];this.components.push(b);b.on(this.eventName,this.fn,this.scope,this.options)}},destroy:function(){var b,d,a,c;c=this.components;for(d=0,a=c.length;d<a;d++){b=c[d];b.un(this.eventName,this.fn,this.scope)}this.components=null},register:function(a){if(this.matches(a)){this.components.push(a);a.on(this.eventName,this.fn,this.scope,this.options)}},unregister:function(b){var a;a=Ext.Array.indexOf(this.components,b);if(a!==-1){b.un(this.eventName,this.fn,this.scope);Ext.Array.erase(this.components,a,1)}},matches:function(a){if(this.selector===null&&this.container===a){return true}if(this.container===null&&Ext.Array.contains(Ext.ComponentQuery.query(this.selector),a)){return true}if(a.isDescendantOf(this.container)&&Ext.Array.contains(this.container.query(this.selector),a)){return true}return false}});Ext.define("Deft.event.LiveEventBus",{alternateClassName:["Deft.LiveEventBus"],requires:["Deft.event.LiveEventListener"],singleton:true,constructor:function(){this.listeners=[]},destroy:function(){var d,c,a,b;b=this.listeners;for(c=0,a=b.length;c<a;c++){d=b[c];d.destroy()}this.listeners=null},addListener:function(b,a,c,f,e,d){var g;g=Ext.create("Deft.event.LiveEventListener",{container:b,selector:a,eventName:c,fn:f,scope:e,options:d});this.listeners.push(g)},removeListener:function(b,a,c,e,d){var f;f=this.findListener(b,a,c,e,d);if(f!=null){Ext.Array.remove(this.listeners,f);f.destroy()}},on:function(b,a,c,f,e,d){return this.addListener(b,a,c,f,e,d)},un:function(b,a,c,e,d){return this.removeListener(b,a,c,e,d)},findListener:function(a,c,f,g,i){var b,d,h,e;e=this.listeners;for(d=0,h=e.length;d<h;d++){b=e[d];if(b.container===a&&b.selector===c&&b.eventName===f&&b.fn===g&&b.scope===i){return b}}return null},register:function(a){a.on("added",this.onComponentAdded,this);a.on("removed",this.onComponentRemoved,this)},unregister:function(a){a.un("added",this.onComponentAdded,this);a.un("removed",this.onComponentRemoved,this)},onComponentAdded:function(c,b,d){var g,f,a,e;e=this.listeners;for(f=0,a=e.length;f<a;f++){g=e[f];g.register(c)}},onComponentRemoved:function(c,b,d){var g,f,a,e;e=this.listeners;for(f=0,a=e.length;f<a;f++){g=e[f];g.unregister(c)}}},function(){if(Ext.getVersion("touch")!=null){Ext.define("Deft.Component",{override:"Ext.Component",setParent:function(c){var b,a;b=this.getParent();a=this.callParent(arguments);if(b===null&&c!==null){this.fireEvent("added",this,c)}else{if(b!==null&&c!==null){this.fireEvent("removed",this,b);this.fireEvent("added",this,c)}else{if(b!==null&&c===null){this.fireEvent("removed",this,b)}}}return a},isDescendantOf:function(a){var b;b=this.getParent();while(b!=null){if(b===a){return true}b=b.getParent()}return false}})}Ext.require("Ext.ComponentManager",function(){Ext.Function.interceptAfter(Ext.ComponentManager,"register",function(a){Deft.event.LiveEventBus.register(a)});Ext.Function.interceptAfter(Ext.ComponentManager,"unregister",function(a){Deft.event.LiveEventBus.unregister(a)})})});Ext.define("Deft.ioc.DependencyProvider",{requires:["Deft.log.Logger"],config:{identifier:null,className:null,parameters:null,fn:null,value:null,singleton:true,eager:false},constructor:function(b){var a;this.initConfig(b);if((b.value!=null)&&b.value.constructor===Object){this.setValue(b.value)}if(this.getEager()){if(this.getValue()!=null){Ext.Error.raise({msg:"Error while configuring '"+(this.getIdentifier())+"': a 'value' cannot be created eagerly."})}if(!this.getSingleton()){Ext.Error.raise({msg:"Error while configuring '"+(this.getIdentifier())+"': only singletons can be created eagerly."})}}if(this.getClassName()!=null){a=Ext.ClassManager.get(this.getClassName());if(!(a!=null)){Deft.Logger.warn("Synchronously loading '"+(this.getClassName())+"'; consider adding Ext.require('"+(this.getClassName())+"') above Ext.onReady.");Ext.syncRequire(this.getClassName());a=Ext.ClassManager.get(this.getClassName())}if(!(a!=null)){Ext.Error.raise({msg:"Error while configuring rule for '"+(this.getIdentifier())+"': unrecognized class name or alias: '"+(this.getClassName())+"'"})}}if(!this.getSingleton()){if(this.getClassName()!=null){if(Ext.ClassManager.get(this.getClassName()).singleton){Ext.Error.raise({msg:"Error while configuring rule for '"+(this.getIdentifier())+"': singleton classes cannot be configured for injection as a prototype. Consider removing 'singleton: true' from the class definition."})}}if(this.getValue()!=null){Ext.Error.raise({msg:"Error while configuring '"+(this.getIdentifier())+"': a 'value' can only be configured as a singleton."})}}else{if((this.getClassName()!=null)&&(this.getParameters()!=null)){if(Ext.ClassManager.get(this.getClassName()).singleton){Ext.Error.raise({msg:"Error while configuring rule for '"+(this.getIdentifier())+"': parameters cannot be applied to singleton classes. Consider removing 'singleton: true' from the class definition."})}}}return this},resolve:function(c){var a,b;Deft.Logger.log("Resolving '"+(this.getIdentifier())+"'.");if(this.getValue()!=null){return this.getValue()}a=null;if(this.getFn()!=null){Deft.Logger.log("Executing factory function.");a=this.getFn().call(null,c)}else{if(this.getClassName()!=null){if(Ext.ClassManager.get(this.getClassName()).singleton){Deft.Logger.log("Using existing singleton instance of '"+(this.getClassName())+"'.");a=Ext.ClassManager.get(this.getClassName())}else{Deft.Logger.log("Creating instance of '"+(this.getClassName())+"'.");b=this.getParameters()!=null?[this.getClassName()].concat(this.getParameters()):[this.getClassName()];a=Ext.create.apply(this,b)}}else{Ext.Error.raise({msg:"Error while configuring rule for '"+(this.getIdentifier())+"': no 'value', 'fn', or 'className' was specified."})}}if(this.getSingleton()){this.setValue(a)}return a}});Ext.define("Deft.ioc.Injector",{alternateClassName:["Deft.Injector"],requires:["Deft.log.Logger","Deft.ioc.DependencyProvider"],singleton:true,constructor:function(){this.providers={};return this},configure:function(a){Deft.Logger.log("Configuring injector.");Ext.Object.each(a,function(c,b){var d;Deft.Logger.log("Configuring dependency provider for '"+c+"'.");if(Ext.isString(b)){d=Ext.create("Deft.ioc.DependencyProvider",{identifier:c,className:b})}else{d=Ext.create("Deft.ioc.DependencyProvider",Ext.apply({identifier:c},b))}this.providers[c]=d},this);Ext.Object.each(this.providers,function(b,c){if(c.getEager()){Deft.Logger.log("Eagerly creating '"+(c.getIdentifier())+"'.");c.resolve()}},this)},canResolve:function(a){var b;b=this.providers[a];return b!=null},resolve:function(a,b){var c;c=this.providers[a];if(c!=null){return c.resolve(b)}else{Ext.Error.raise({msg:"Error while resolving value to inject: no dependency provider found for '"+a+"'."})}},inject:function(a,c,f){var e,b,h,g,d;if(f==null){f=true}e={};if(Ext.isString(a)){a=[a]}Ext.Object.each(a,function(l,m){var k,i,j;j=Ext.isArray(a)?m:l;k=m;i=this.resolve(k,c);if(j in c.config){Deft.Logger.log("Injecting '"+k+"' into '"+j+"' config.");e[j]=i}else{Deft.Logger.log("Injecting '"+k+"' into '"+j+"' property.");c[j]=i}},this);if(f){for(b in e){d=e[b];g="set"+Ext.String.capitalize(b);c[g].call(c,d)}}else{if((Ext.getVersion("extjs")!=null)&&c instanceof Ext.ClassManager.get("Ext.Component")){c.injectConfig=e}else{if(Ext.isFunction(c.initConfig)){h=c.initConfig;c.initConfig=function(j){var i;i=h.call(this,Ext.Object.merge({},j||{},e));return i}}}}return c}},function(){if(Ext.getVersion("extjs")!=null){if(Ext.getVersion("core").isLessThan("4.1.0")){Ext.require("Ext.Component",function(){Ext.Component.override({constructor:function(a){a=Ext.Object.merge({},a||{},this.injectConfig||{});delete this.injectConfig;return this.callOverridden([a])}})})}else{Ext.define("Deft.InjectableComponent",{override:"Ext.Component",constructor:function(a){a=Ext.Object.merge({},a||{},this.injectConfig||{});delete this.injectConfig;return this.callParent([a])}})}}});Ext.define("Deft.mixin.Injectable",{requires:["Deft.core.Class","Deft.ioc.Injector","Deft.log.Logger"],onClassMixedIn:function(a){Deft.Logger.deprecate("Deft.mixin.Injectable has been deprecated and can now be omitted - simply use the 'inject' class annotation on its own.")}},function(){var a;if(Ext.getVersion("extjs")&&Ext.getVersion("core").isLessThan("4.1.0")){a=function(){return function(){if(!this.$injected){Deft.Injector.inject(this.inject,this,false);this.$injected=true}return this.callOverridden(arguments)}}}else{a=function(){return function(){if(!this.$injected){Deft.Injector.inject(this.inject,this,false);this.$injected=true}return this.callParent(arguments)}}}Deft.Class.registerPreprocessor("inject",function(b,e,j,i){var g,f,c,h,d;if(Ext.isString(e.inject)){e.inject=[e.inject]}if(Ext.isArray(e.inject)){g={};d=e.inject;for(c=0,h=d.length;c<h;c++){f=d[c];g[f]=f}e.inject=g}Deft.Class.hookOnClassCreated(j,function(k){k.override({constructor:a()})});Deft.Class.hookOnClassExtended(e,function(m,n,l){var k;Deft.Class.hookOnClassCreated(l,function(o){o.override({constructor:a()})});if((k=n.inject)==null){n.inject={}}Ext.applyIf(n.inject,m.superclass.inject)})},"before","extend")});Ext.define("Deft.mvc.ComponentSelectorListener",{requires:["Deft.event.LiveEventBus"],constructor:function(c){var b,e,a,d;Ext.apply(this,c);if(this.componentSelector.live){Deft.LiveEventBus.addListener(this.componentSelector.view,this.componentSelector.selector,this.eventName,this.fn,this.scope,this.options)}else{d=this.componentSelector.components;for(e=0,a=d.length;e<a;e++){b=d[e];b.on(this.eventName,this.fn,this.scope,this.options)}}return this},destroy:function(){var b,d,a,c;if(this.componentSelector.live){Deft.LiveEventBus.removeListener(this.componentSelector.view,this.componentSelector.selector,this.eventName,this.fn,this.scope)}else{c=this.componentSelector.components;for(d=0,a=c.length;d<a;d++){b=c[d];b.un(this.eventName,this.fn,this.scope)}}}});Ext.define("Deft.mvc.ComponentSelector",{requires:["Deft.log.Logger","Deft.mvc.ComponentSelectorListener"],constructor:function(c){var a,e,g,b,d,f;Ext.apply(this,c);if(!this.live){this.components=this.selector!=null?Ext.ComponentQuery.query(this.selector,this.view):[this.view]}this.selectorListeners=[];if(Ext.isObject(this.listeners)){f=this.listeners;for(a in f){g=f[a];e=g;d=this.scope;b=null;if(Ext.isObject(g)){b=Ext.apply({},g);if(b.fn!=null){e=b.fn;delete b.fn}if(b.scope!=null){d=b.scope;delete b.scope}}if(Ext.isString(e)&&Ext.isFunction(d[e])){e=d[e]}if(!Ext.isFunction(e)){Ext.Error.raise({msg:"Error adding '"+a+"' listener: the specified handler '"+e+"' is not a Function or does not exist."})}this.addListener(a,e,d,b)}}return this},destroy:function(){var d,c,a,b;b=this.selectorListeners;for(c=0,a=b.length;c<a;c++){d=b[c];d.destroy()}this.selectorListeners=[]},addListener:function(a,d,c,b){var e;if(this.findListener(a,d,c)!=null){Ext.Error.raise({msg:"Error adding '"+a+"' listener: an existing listener for the specified function was already registered for '"+this.selector+"."})}Deft.Logger.log("Adding '"+a+"' listener to '"+this.selector+"'.");e=Ext.create("Deft.mvc.ComponentSelectorListener",{componentSelector:this,eventName:a,fn:d,scope:c,options:b});this.selectorListeners.push(e)},removeListener:function(a,c,b){var d;d=this.findListener(a,c,b);if(d!=null){Deft.Logger.log("Removing '"+a+"' listener from '"+this.selector+"'.");d.destroy();Ext.Array.remove(this.selectorListeners,d)}},findListener:function(b,d,c){var g,f,a,e;e=this.selectorListeners;for(f=0,a=e.length;f<a;f++){g=e[f];if(g.eventName===b&&g.fn===d&&g.scope===c){return g}}return null}});Ext.define("Deft.mvc.ViewController",{alternateClassName:["Deft.ViewController"],requires:["Deft.log.Logger","Deft.mvc.ComponentSelector"],config:{view:null},constructor:function(a){if(a==null){a={}}if(a.view){this.controlView(a.view)}return this.initConfig(a)},controlView:function(a){if(a instanceof Ext.ClassManager.get("Ext.Container")){this.setView(a);this.registeredComponentReferences={};this.registeredComponentSelectors={};if(Ext.getVersion("extjs")!=null){if(this.getView().rendered){this.onViewInitialize()}else{this.getView().on("afterrender",this.onViewInitialize,this,{single:true})}}else{if(this.getView().initialized){this.onViewInitialize()}else{this.getView().on("initialize",this.onViewInitialize,this,{single:true})}}}else{Ext.Error.raise({msg:"Error constructing ViewController: the configured 'view' is not an Ext.Container."})}},init:function(){},destroy:function(){return true},onViewInitialize:function(){var d,h,e,f,c,a,b,g;if(Ext.getVersion("extjs")!=null){this.getView().on("beforedestroy",this.onViewBeforeDestroy,this);this.getView().on("destroy",this.onViewDestroy,this,{single:true})}else{b=this;c=this.getView().destroy;this.getView().destroy=function(){if(b.destroy()){c.call(this)}}}g=this.control;for(h in g){d=g[h];a=null;if(h!=="view"){if(Ext.isString(d)){a=d}else{if(d.selector!=null){a=d.selector}else{a="#"+h}}}e=null;if(Ext.isObject(d.listeners)){e=d.listeners}else{if(!((d.selector!=null)||(d.live!=null))){e=d}}f=(d.live!=null)&&d.live;this.addComponentReference(h,a,f);this.addComponentSelector(a,e,f)}this.init()},onViewBeforeDestroy:function(){if(this.destroy()){this.getView().un("beforedestroy",this.onBeforeDestroy,this);return true}return false},onViewDestroy:function(){var b,a;for(b in this.registeredComponentReferences){this.removeComponentReference(b)}for(a in this.registeredComponentSelectors){this.removeComponentSelector(a)}},addComponentReference:function(e,a,c){var b,d;if(c==null){c=false}Deft.Logger.log("Adding '"+e+"' component reference for selector: '"+a+"'.");if(this.registeredComponentReferences[e]!=null){Ext.Error.raise({msg:"Error adding component reference: an existing component reference was already registered as '"+e+"'."})}if(e!=="view"){b="get"+Ext.String.capitalize(e);if(this[b]==null){if(c){this[b]=Ext.Function.pass(this.getViewComponent,[a],this)}else{d=this.getViewComponent(a);if(d==null){Ext.Error.raise({msg:"Error locating component: no component(s) found matching '"+a+"'."})}this[b]=function(){return d}}this[b].generated=true}}this.registeredComponentReferences[e]=true},removeComponentReference:function(b){var a;Deft.Logger.log("Removing '"+b+"' component reference.");if(this.registeredComponentReferences[b]==null){Ext.Error.raise({msg:"Error removing component reference: no component reference is registered as '"+b+"'."})}if(b!=="view"){a="get"+Ext.String.capitalize(b);if(this[a].generated){this[a]=null}}delete this.registeredComponentReferences[b]},getViewComponent:function(a){var b;if(a!=null){b=Ext.ComponentQuery.query(a,this.getView());if(b.length===0){return null}else{if(b.length===1){return b[0]}else{return b}}}else{return this.getView()}},addComponentSelector:function(a,b,c){var d,e;if(c==null){c=false}Deft.Logger.log("Adding component selector for: '"+a+"'.");e=this.getComponentSelector(a);if(e!=null){Ext.Error.raise({msg:"Error adding component selector: an existing component selector was already registered for '"+a+"'."})}d=Ext.create("Deft.mvc.ComponentSelector",{view:this.getView(),selector:a,listeners:b,scope:this,live:c});this.registeredComponentSelectors[a]=d},removeComponentSelector:function(a){var b;Deft.Logger.log("Removing component selector for '"+a+"'.");b=this.getComponentSelector(a);if(b==null){Ext.Error.raise({msg:"Error removing component selector: no component selector registered for '"+a+"'."})}b.destroy();delete this.registeredComponentSelectors[a]},getComponentSelector:function(a){return this.registeredComponentSelectors[a]}});Ext.define("Deft.mixin.Controllable",{requires:["Deft.core.Class","Deft.log.Logger"],onClassMixedIn:function(a){Deft.Logger.deprecate("Deft.mixin.Controllable has been deprecated and can now be omitted - simply use the 'controller' class annotation on its own.")}},function(){var a;if(Ext.getVersion("extjs")&&Ext.getVersion("core").isLessThan("4.1.0")){a=function(){return function(d){var b;if(d==null){d={}}if(this instanceof Ext.ClassManager.get("Ext.Container")&&!this.$controlled){try{b=Ext.create(this.controller,d.controllerConfig||this.controllerConfig||{})}catch(c){Deft.Logger.warn("Error initializing view controller: an error occurred while creating an instance of the specified controller: '"+this.controller+"'.");throw c}if(this.getController===void 0){this.getController=function(){return b}}this.$controlled=true;this.callOverridden(arguments);b.controlView(this);return this}return this.callOverridden(arguments)}}}else{a=function(){return function(d){var b;if(d==null){d={}}if(this instanceof Ext.ClassManager.get("Ext.Container")&&!this.$controlled){try{b=Ext.create(this.controller,d.controllerConfig||this.controllerConfig||{})}catch(c){Deft.Logger.warn("Error initializing view controller: an error occurred while creating an instance of the specified controller: '"+this.controller+"'.");throw c}if(this.getController===void 0){this.getController=function(){return b}}this.$controlled=true;this.callParent(arguments);b.controlView(this);return this}return this.callParent(arguments)}}}Deft.Class.registerPreprocessor("controller",function(d,e,b,f){var c;Deft.Class.hookOnClassCreated(b,function(g){g.override({constructor:a()})});Deft.Class.hookOnClassExtended(e,function(h,i,g){Deft.Class.hookOnClassCreated(g,function(j){j.override({constructor:a()})})});c=this;Ext.require([e.controller],function(){if(f!=null){f.call(c,d,e,b)}});return false},"before","extend")});Ext.define("Deft.promise.Deferred",{alternateClassName:["Deft.Deferred"],constructor:function(){this.state="pending";this.progress=void 0;this.value=void 0;this.progressCallbacks=[];this.successCallbacks=[];this.failureCallbacks=[];this.cancelCallbacks=[];this.promise=Ext.create("Deft.Promise",this);return this},then:function(h){var j,k,m,a,c,l,b,g,f,d,i,e;if(Ext.isObject(h)){b=h.success,a=h.failure,c=h.progress,k=h.cancel,l=h.scope}else{b=arguments[0],a=arguments[1],c=arguments[2],k=arguments[3],l=arguments[4]}e=[b,a,c,k];for(d=0,i=e.length;d<i;d++){j=e[d];if(!(Ext.isFunction(j)||j===null||j===void 0)){Ext.Error.raise({msg:"Error while configuring callback: a non-function specified."})}}m=Ext.create("Deft.promise.Deferred");g=function(o,n){return function(r){var p;if(Ext.isFunction(o)){try{p=o.call(l,r);if(p instanceof Ext.ClassManager.get("Deft.promise.Promise")||p instanceof Ext.ClassManager.get("Deft.promise.Deferred")){p.then(Ext.bind(m.resolve,m),Ext.bind(m.reject,m),Ext.bind(m.update,m),Ext.bind(m.cancel,m))}else{m.resolve(p)}}catch(q){m.reject(q)}}else{m[n](r)}}};this.register(g(b,"resolve"),this.successCallbacks,"resolved",this.value);this.register(g(a,"reject"),this.failureCallbacks,"rejected",this.value);this.register(g(k,"cancel"),this.cancelCallbacks,"cancelled",this.value);f=function(n){return function(p){var o;if(Ext.isFunction(n)){o=n.call(l,p);m.update(o)}else{m.update(p)}}};this.register(f(c),this.progressCallbacks,"pending",this.progress);return m.getPromise()},otherwise:function(c,a){var b;if(Ext.isObject(c)){b=c,c=b.fn,a=b.scope}return this.then({failure:c,scope:a})},always:function(c,a){var b;if(Ext.isObject(c)){b=c,c=b.fn,a=b.scope}return this.then({success:c,failure:c,cancel:c,scope:a})},update:function(a){if(this.state==="pending"){this.progress=a;this.notify(this.progressCallbacks,a)}else{if(this.state!=="cancelled"){Ext.Error.raise({msg:"Error: this Deferred has already been completed and cannot be modified."})}}},resolve:function(a){this.complete("resolved",a,this.successCallbacks)},reject:function(a){this.complete("rejected",a,this.failureCallbacks)},cancel:function(a){this.complete("cancelled",a,this.cancelCallbacks)},getPromise:function(){return this.promise},getState:function(){return this.state},register:function(d,a,c,b){if(Ext.isFunction(d)){if(this.state==="pending"){a.push(d);if(this.state===c&&b!==void 0){this.notify([d],b)}}else{if(this.state===c){this.notify([d],b)}}}},complete:function(c,b,a){if(this.state==="pending"){this.state=c;this.value=b;this.notify(a,b);this.releaseCallbacks()}else{if(this.state!=="cancelled"){Ext.Error.raise({msg:"Error: this Deferred has already been completed and cannot be modified."})}}},notify:function(b,d){var e,c,a;for(c=0,a=b.length;c<a;c++){e=b[c];e(d)}},releaseCallbacks:function(){this.progressCallbacks=null;this.successCallbacks=null;this.failureCallbacks=null;this.cancelCallbacks=null}});Ext.define("Deft.promise.Promise",{alternateClassName:["Deft.Promise"],statics:{when:function(a){var b;if(a instanceof Ext.ClassManager.get("Deft.promise.Promise")||a instanceof Ext.ClassManager.get("Deft.promise.Deferred")){return a.then()}else{if(Ext.isObject(a)&&Ext.isFunction(a.then)){b=Ext.create("Deft.promise.Deferred");a.then(function(c){b.resolve(c)},function(c){b.reject(c)});return b.then()}else{b=Ext.create("Deft.promise.Deferred");b.resolve(a);return b.then()}}},all:function(a){return this.when(a).then({success:function(n){var q,l,i,h,r,d,e,j,p,k,m,c,f,s,g,b,o;r=Ext.create("Deft.promise.Deferred");s=n.length;c=new Array(n);m=0;g=function(t){r.update(t)};f=function(t,u){c[t]=u;m++;if(m===s){i();r.resolve(c)}};k=function(t){i();r.reject(t)};l=function(t){i();r.cancel(t)};i=function(){return g=f=k=l=Ext.emptyFn};h=function(t){return function(u){return f(t,u)}};d=function(t){return k(t)};j=function(t){return g(t)};q=function(t){return l(t)};for(e=b=0,o=n.length;b<o;e=++b){p=n[e];if(e in n){this.when(p).then({success:h(e),failure:d,progress:j,cancel:q})}}return r.getPromise()},scope:this})},any:function(a){return this.when(a).then({success:function(h){var c,o,b,p,k,i,j,d,f,e,l,n,g,m;p=Ext.create("Deft.promise.Deferred");n=function(q){p.update(q)};e=function(q){b();p.resolve(q)};f=function(q){b();p.reject(q)};o=function(q){b();return p.cancel(q)};b=function(){return n=e=f=o=Ext.emptyFn};l=function(q){return e(q)};k=function(q){return f(q)};j=function(q){return n(q)};c=function(q){return o(q)};for(i=g=0,m=h.length;g<m;i=++g){d=h[i];if(i in h){this.when(d).then({success:l,failure:k,progress:j,cancel:c})}}return p.getPromise()},scope:this})},memoize:function(d,c,a){var b;b=Deft.util.Function.memoize(d,c,a);return Ext.bind(function(){return this.all(Ext.Array.toArray(arguments)).then(function(e){return b.apply(c,e)})},this)},map:function(b,a){return this.when(b).then({success:function(h){var e,c,f,g,d;f=new Array(h.length);for(e=g=0,d=h.length;g<d;e=++g){c=h[e];if(e in h){f[e]=this.when(c).then(a)}}return this.reduce(f,this.reduceIntoArray,f)},scope:this})},reduce:function(c,b,a){return this.when(c).then({success:function(e){var d,f;f=this.when;d=[function(h,i,g){return f(h).then(function(j){return f(i).then(function(k){return b(j,k,g,e)})})}];if(arguments.length===3){d.push(a)}return this.when(this.reduceArray.apply(e,d))},scope:this})},reduceArray:function(b,a){var e,g,d,f,c;d=0;g=Object(this);f=g.length>>>0;e=arguments;if(e.length<=1){while(true){if(d in g){c=g[d++];break}if(++d>=f){throw new TypeError()}}}else{c=e[1]}while(d<f){if(d in g){c=b(c,g[d],d,g)}d++}return c},reduceIntoArray:function(b,c,a){b[a]=c;return b}},constructor:function(a){this.deferred=a;return this},then:function(a){return this.deferred.then.apply(this.deferred,arguments)},otherwise:function(b,a){return this.deferred.otherwise.apply(this.deferred,arguments)},always:function(b,a){return this.deferred.always.apply(this.deferred,arguments)},cancel:function(a){return this.deferred.cancel(a)},getState:function(){return this.deferred.getState()}},function(){if(Array.prototype.reduce!=null){this.reduceArray=Array.prototype.reduce}});
View
16 spec/coffee/Deft/mvc/ViewController.coffee
@@ -1538,7 +1538,7 @@ describe( 'Deft.mvc.ViewController', ->
return
)
- it( 'should remove event listeners it attached to a view component referenced implicitly by item id when the associated view (and view controller) is destroyed', ->
+ it( 'should remove event listeners it attached to a view component referenced implicitly by itemId when the associated view (and view controller) is destroyed', ->
Ext.define( 'ExampleViewController',
extend: 'Deft.mvc.ViewController'
@@ -1560,6 +1560,8 @@ describe( 'Deft.mvc.ViewController', ->
component = view.query( '#example' )[ 0 ]
+ expect( viewController.getExample ).not.toBe( null )
+
expect( hasListener( component, 'exampleevent' ) ).toBe( true )
spyOn( viewController, 'destroy' ).andCallThrough()
@@ -1569,6 +1571,7 @@ describe( 'Deft.mvc.ViewController', ->
view.destroy()
expect( viewController.destroy ).toHaveBeenCalled()
+ expect( viewController.getExample ).toBe( null )
expect( isViewDestroyed ).toBe( true )
expect( hasListener( component, 'exampleevent' ) ).toBe( false )
@@ -1610,6 +1613,8 @@ describe( 'Deft.mvc.ViewController', ->
components = view.query( 'example' )
+ expect( viewController.getExample ).not.toBe( null )
+
for component in components
expect( hasListener( component, 'exampleevent' ) ).toBe( true )
@@ -1620,6 +1625,7 @@ describe( 'Deft.mvc.ViewController', ->
view.destroy()
expect( viewController.destroy ).toHaveBeenCalled()
+ expect( viewController.getExample ).toBe( null )
expect( isViewDestroyed ).toBe( true )
for component in components
@@ -1628,7 +1634,7 @@ describe( 'Deft.mvc.ViewController', ->
return
)
- it( 'should remove event listeners it attached to a dynamic view component referenced by a live selector implicitly by item id when the associated view (and view controller) is destroyed', ->
+ it( 'should remove event listeners it attached to a dynamic view component referenced by a live selector implicitly by itemId when the associated view (and view controller) is destroyed', ->
Ext.define( 'ExampleViewController',
extend: 'Deft.mvc.ViewController'
@@ -1656,6 +1662,8 @@ describe( 'Deft.mvc.ViewController', ->
}
)
+ expect( viewController.getDynamicExample ).not.toBe( null )
+
expect( hasListener( component, 'exampleevent' ) ).toBe( true )
spyOn( viewController, 'destroy' ).andCallThrough()
@@ -1665,6 +1673,7 @@ describe( 'Deft.mvc.ViewController', ->
view.destroy()
expect( viewController.destroy ).toHaveBeenCalled()
+ expect( viewController.getDynamicExample ).toBe( null )
expect( isViewDestroyed ).toBe( true )
expect( hasListener( component, 'exampleevent' ) ).toBe( false )
@@ -1708,6 +1717,8 @@ describe( 'Deft.mvc.ViewController', ->
]
)
components = view.query( 'example' )
+
+ expect( viewController.getDynamicExample ).not.toBe( null )
expect( viewController.getDynamicExample() ).toEqual( components )
expect( viewController.getDynamicExample().length ).toEqual( 4 )
@@ -1721,6 +1732,7 @@ describe( 'Deft.mvc.ViewController', ->
view.destroy()
expect( viewController.destroy ).toHaveBeenCalled()
+ expect( viewController.getDynamicExample ).toBe( null )
expect( isViewDestroyed ).toBe( true )
for component in components
View
12 spec/js/Deft/mvc/ViewController.js
@@ -1286,7 +1286,7 @@ describe('Deft.mvc.ViewController', function() {
expect(isViewDestroyed).toBe(true);
expect(hasListener(view, 'exampleevent')).toBe(false);
});
- it('should remove event listeners it attached to a view component referenced implicitly by item id when the associated view (and view controller) is destroyed', function() {
+ it('should remove event listeners it attached to a view component referenced implicitly by itemId when the associated view (and view controller) is destroyed', function() {
var component, isViewDestroyed, view, viewController;
Ext.define('ExampleViewController', {
extend: 'Deft.mvc.ViewController',
@@ -1305,6 +1305,7 @@ describe('Deft.mvc.ViewController', function() {
view: view
});
component = view.query('#example')[0];
+ expect(viewController.getExample).not.toBe(null);
expect(hasListener(component, 'exampleevent')).toBe(true);
spyOn(viewController, 'destroy').andCallThrough();
isViewDestroyed = false;
@@ -1313,6 +1314,7 @@ describe('Deft.mvc.ViewController', function() {
});
view.destroy();
expect(viewController.destroy).toHaveBeenCalled();
+ expect(viewController.getExample).toBe(null);
expect(isViewDestroyed).toBe(true);
expect(hasListener(component, 'exampleevent')).toBe(false);
});
@@ -1345,6 +1347,7 @@ describe('Deft.mvc.ViewController', function() {
view: view
});
components = view.query('example');
+ expect(viewController.getExample).not.toBe(null);
for (_i = 0, _len = components.length; _i < _len; _i++) {
component = components[_i];
expect(hasListener(component, 'exampleevent')).toBe(true);
@@ -1356,13 +1359,14 @@ describe('Deft.mvc.ViewController', function() {
});
view.destroy();
expect(viewController.destroy).toHaveBeenCalled();
+ expect(viewController.getExample).toBe(null);
expect(isViewDestroyed).toBe(true);
for (_j = 0, _len1 = components.length; _j < _len1; _j++) {
component = components[_j];
expect(hasListener(component, 'exampleevent')).toBe(false);
}
});
- it('should remove event listeners it attached to a dynamic view component referenced by a live selector implicitly by item id when the associated view (and view controller) is destroyed', function() {
+ it('should remove event listeners it attached to a dynamic view component referenced by a live selector implicitly by itemId when the associated view (and view controller) is destroyed', function() {
var component, isViewDestroyed, view, viewController;
Ext.define('ExampleViewController', {
extend: 'Deft.mvc.ViewController',
@@ -1385,6 +1389,7 @@ describe('Deft.mvc.ViewController', function() {
xtype: 'example',
itemId: 'dynamicExample'
});
+ expect(viewController.getDynamicExample).not.toBe(null);
expect(hasListener(component, 'exampleevent')).toBe(true);
spyOn(viewController, 'destroy').andCallThrough();
isViewDestroyed = false;
@@ -1393,6 +1398,7 @@ describe('Deft.mvc.ViewController', function() {
});
view.destroy();
expect(viewController.destroy).toHaveBeenCalled();
+ expect(viewController.getDynamicExample).toBe(null);
expect(isViewDestroyed).toBe(true);
expect(hasListener(component, 'exampleevent')).toBe(false);
});
@@ -1425,6 +1431,7 @@ describe('Deft.mvc.ViewController', function() {
}
]);
components = view.query('example');
+ expect(viewController.getDynamicExample).not.toBe(null);
expect(viewController.getDynamicExample()).toEqual(components);
expect(viewController.getDynamicExample().length).toEqual(4);
for (_i = 0, _len = components.length; _i < _len; _i++) {
@@ -1438,6 +1445,7 @@ describe('Deft.mvc.ViewController', function() {
});
view.destroy();
expect(viewController.destroy).toHaveBeenCalled();
+ expect(viewController.getDynamicExample).toBe(null);
expect(isViewDestroyed).toBe(true);
for (_j = 0, _len1 = components.length; _j < _len1; _j++) {
component = components[_j];
View
15 src/coffee/Deft/mvc/ViewController.coffee
@@ -61,6 +61,10 @@ Ext.define( 'Deft.mvc.ViewController',
Destroy the ViewController
###
destroy: ->
+ for id of @registeredComponentReferences
+ @removeComponentReference( id )
+ for selector of @registeredComponentSelectors
+ @removeComponentSelector( selector )
return true
###*
@@ -70,7 +74,6 @@ Ext.define( 'Deft.mvc.ViewController',
if Ext.getVersion( 'extjs' )?
# Ext JS
@getView().on( 'beforedestroy', @onViewBeforeDestroy, @ )
- @getView().on( 'destroy', @onViewDestroy, @, single: true )
else
# Sencha Touch
self = this
@@ -111,16 +114,6 @@ Ext.define( 'Deft.mvc.ViewController',
return false
###*
- @private
- ###
- onViewDestroy: ->
- for id of @registeredComponentReferences
- @removeComponentReference( id )
- for selector of @registeredComponentSelectors
- @removeComponentSelector( selector )
- return
-
- ###*
Add a component accessor method the ViewController for the specified view-relative selector.
###
addComponentReference: ( id, selector, live = false ) ->
View
23 src/js/Deft/mvc/ViewController.js
@@ -71,6 +71,13 @@ Ext.define('Deft.mvc.ViewController', {
*/
destroy: function() {
+ var id, selector;
+ for (id in this.registeredComponentReferences) {
+ this.removeComponentReference(id);
+ }
+ for (selector in this.registeredComponentSelectors) {
+ this.removeComponentSelector(selector);
+ }
return true;
},
/**
@@ -81,9 +88,6 @@ Ext.define('Deft.mvc.ViewController', {
var config, id, listeners, live, originalViewDestroyFunction, selector, self, _ref;
if (Ext.getVersion('extjs') != null) {
this.getView().on('beforedestroy', this.onViewBeforeDestroy, this);
- this.getView().on('destroy', this.onViewDestroy, this, {
- single: true
- });
} else {
self = this;
originalViewDestroyFunction = this.getView().destroy;
@@ -132,19 +136,6 @@ Ext.define('Deft.mvc.ViewController', {
return false;
},
/**
- @private
- */
-
- onViewDestroy: function() {
- var id, selector;
- for (id in this.registeredComponentReferences) {
- this.removeComponentReference(id);
- }
- for (selector in this.registeredComponentSelectors) {
- this.removeComponentSelector(selector);
- }
- },
- /**
Add a component accessor method the ViewController for the specified view-relative selector.
*/
Please sign in to comment.
Something went wrong with that request. Please try again.