forked from extmvc/extmvc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathext-mvc-all-min.js
8 lines (8 loc) · 64.8 KB
/
ext-mvc-all-min.js
1
2
3
4
5
6
7
8
ExtMVC=Ext.extend(Ext.util.Observable,{version:"0.7a",constructor:function(){ExtMVC.superclass.constructor.apply(this,arguments)},dispatch:function(){var A=this.dispatcher;return A.dispatch.apply(A,arguments)},setApplication:function(A){this.app=A;this.name=A.name;ExtMVC.model.modelNamespace=window[A.name].models},fields:{},registerFields:function(B,A){this.fields[B]=A},getFields:function(A){return this.fields[A]},registerModel:function(B,A){this.registerClass("model",arguments)},registerController:function(B,A){this.registerClass("controller",arguments)},registerView:function(C,B,A){this.registerClass("view",arguments)},registerClass:function(C,A){var B=this.getClassManager(C);B.register.apply(B,A)},classManagers:{},initializeClassManagers:function(){this.registerClassManager("model",new ExtMVC.lib.ModelClassManager());this.registerClassManager("view",new ExtMVC.lib.ViewClassManager());this.registerClassManager("controller",new ExtMVC.lib.ControllerClassManager())},getClassManager:function(A){return this.classManagers[A]},registerClassManager:function(A,B){this.classManagers[A]=B},getController:function(A){return this.getClassManager("controller").getInstance(A)},getModel:function(A){return this.getClassManager("model").getConstructor(A)},buildModel:function(A,B){return new (this.getModel(A))(B)},getView:function getView(B,A){return this.getClassManager("view").getConstructor(B,A)},buildView:function buildView(D,B,A){var C=this.getView(D,B);return new (C)(A)},loadOnDemand:function(A,C,B){Ext.Ajax.request({url:A,scope:B||this,success:function(D){var E=Ext.decode(D.responseText);Ext.each(E.controllers||[],function(F){this.registerController(F.name,F)},this);Ext.each(E.models||[],function(F){this.registerModel(F.name,F)},this);Ext.each(E.views||[],function(F){this.registerView(F.namespace,F.name,F)},this);if(Ext.isFunction(C)){C.call(B,E)}}})}});ExtMVC=new ExtMVC();Ext.onReady(function(){ExtMVC.dispatcher=new ExtMVC.lib.Dispatcher()});Ext.ns("ExtMVC.router","ExtMVC.plugin","ExtMVC.controller","ExtMVC.view","ExtMVC.view.scaffold","ExtMVC.lib","ExtMVC.test");ExtMVC.App=Ext.extend(Ext.util.Observable,{constructor:function(A){ExtMVC.App.superclass.constructor.apply(this,arguments);Ext.apply(this,A||{});window[this.name]=this;this.initializeNamespaces();this.on("launched",function(){if(this.usesHistory){if(this.dispatchHistoryOnLoad===true){Ext.History.init(function(C){var B=document.location.hash.replace("#","");var D=this.router.recognise(B);if(D){this.dispatch(D)}},this)}else{Ext.History.init()}}},this)},onReady:function(){if(this.fireEvent("before-launch",this)){this.initializeRouter();this.initializeEvents();if(this.usesHistory===true){this.initializeHistory()}this.launch()}},name:"MyApp",usesHistory:false,dispatchHistoryOnLoad:true,launch:function(){this.fireEvent("launched",this)},params:{},dispatch:function dispatch(B,C,A){var B=B||{};Ext.applyIf(B,{action:"index"});this.params=B;var E=ExtMVC.getController(B.controller);if(E!=undefined){var D=E[B.action];if(typeof D=="function"){D.apply(C||E,A||[])}else{throw new Error(String.format("Action '{0}' not found on Controller '{1}'",B.action,B.controller))}}},initializeRouter:function(){if(this.router==undefined){this.router=new ExtMVC.router.Router();ExtMVC.router.Router.defineRoutes(this.router)}},initializeNamespaces:function initializeNamespaces(A){var A=A||this.name;if(A){Ext.ns(A,A+".controllers",A+".models",A+".views")}},initializeHistory:function initializeHistory(){this.historyForm=Ext.getBody().createChild({tag:"form",action:"#",cls:"x-hidden",id:"history-form",children:[{tag:"div",children:[{tag:"input",id:"x-history-field",type:"hidden"},{tag:"iframe",id:"x-history-frame"}]}]});Ext.History.on("change",this.onHistoryChange,this)},onHistoryChange:function onHistoryChange(B){var A=this.router.recognise(B);if(A){this.dispatch(A,null,[{url:B}])}},initializeEvents:function initializeEvents(){this.addEvents("before-launch","launched")}});ExtMVC.App.define=function(A){ExtMVC.app=new ExtMVC.App(A)};ExtMVC.lib.ClassManager=Ext.extend(Ext.util.Observable,{autoDefine:true,constructor:function constructor(A){A=A||{};Ext.applyIf(A,{registeredClasses:{},constructors:{}});Ext.apply(this,A);this.addEvents("class-registered","class-defined")},register:function register(B,A){this.registeredClasses[B]=A;this.fireEvent("class-registered",B,A);if(this.autoDefine===true){this.define(B)}},getRegistered:function getRegistered(A){return this.registeredClasses[A]},define:function define(B){console.log("defining");console.log(B);var C=this.getRegistered(B);var A=Ext.extend(this.getConstructor(C.extend),C);this.constructors[B]=A;this.fireEvent("class-defined",B,A);return A},getConstructor:function getConstructor(A){return this.constructors[A]||this.define(A)}});Array.prototype.toSentence=function(A){A=A||"and";var C="";if(this.length<=1){C=this[0]}else{var B=this.slice(0,this.length-1);C=String.format("{0} {1} {2}",B.join(", "),A,this[this.length-1])}return C};ExtMVC.lib.Booter=Ext.extend(Ext.util.Observable,{defaultBootParams:{environment:"production"},constructor:function(A){A=A||{};Ext.applyIf(A,this.parseLocationParams());Ext.apply(this,A,this.defaultBootParams);ExtMVC.lib.Booter.superclass.constructor.apply(this,arguments);this.initEvents();this.initListeners()},initListeners:function(){this.on("environment-loaded",this.loadApplicationFiles,this);this.on({scope:this,"environment-loaded":this.loadApplicationFiles,"application-files-loaded":this.launchApp,"boot-complete":this.onBootComplete})},initEvents:function(){this.addEvents("before-boot","boot-complete","environment-loaded","application-files-loaded","application-launched")},boot:function(){this.fireEvent("before-boot");if(this.useLoadingMask){this.addLoadingMask()}this.loadEnvironment()},onBootComplete:function(){},loadEnvironment:function(){Ext.Ajax.request({url:"config/environment.json",scope:this,success:function(A,B){var C=this.environment;this.environment=new ExtMVC.Environment(Ext.decode(A.responseText));Ext.Ajax.request({url:String.format("config/environments/{0}.json",C),success:function(D,E){this.environment.update(Ext.decode(D.responseText));this.fireEvent("environment-loaded",this.environment)},scope:this})},failure:function(){Ext.Msg.alert("Could not load environment","The environment could not be found")}})},loadApplicationFiles:function(G){this.loadStylesheets(G);if(Ext.isArray(G.scripts)){if(G.scripts.length==0){this.fireEvent("application-files-loaded")}else{this.loadFiles(G.scripts,false,function(){this.fireEvent("application-files-loaded")},this)}return}var A=["overrides","config","plugins","models","controllers","views"],B=[],I=[],F=[],D=[],E=[];Ext.each(G.config,function(J){B.push(String.format("../{0}.js",J))},this);Ext.each(G.plugins,function(J){I.push(String.format("{0}/{1}/{2}-all.js",G.pluginsDir,J,J))},this);Ext.each(G.overrides,function(J){I.push(String.format("{0}/{1}.js",G.overridesDir,J))},this);Ext.each(G.models,function(J){F.push(String.format("{0}/models/{1}.js",G.appDir,J))},this);Ext.each(G.controllers,function(J){D.push(String.format("{0}/controllers/{1}Controller.js",G.appDir,J))},this);Ext.each(G.views,function(J){Ext.iterate(J,function(L,K){Ext.each(K,function(M){E.push(String.format("{0}/views/{1}/{2}.js",G.appDir,L,M))},this)},this)},this);var H=this;var C=function(){H.fireEvent("application-files-loaded")};this.loadFiles(B,false,function(){this.loadFiles(I,false,function(){this.loadFiles(F,false,function(){this.loadFiles(D,true,function(){this.loadFiles(E,true,function(){C()})})})})})},launchApp:function(){ExtMVC.app.onReady();if(this.useLoadingMask){this.removeLoadingMask()}this.fireEvent("application-launched");this.fireEvent("boot-complete")},useLoadingMask:false,addLoadingMask:function(){var A=Ext.getBody();A.createChild({id:"loading-mask"});A.createChild({id:"loading",cn:[{cls:"loading-indicator",html:this.getLoadingMaskMessage()}]})},getLoadingMaskMessage:function(){return"Loading..."},loadingMaskFadeDelay:250,removeLoadingMask:function(){(function(){Ext.get("loading").remove();Ext.get("loading-mask").fadeOut({remove:true})}).defer(this.loadingMaskFadeDelay)},parseLocationParams:function(){var A=window.location.search.split("?")[1],B={};if(A!=undefined){Ext.each(A.split("&"),function(C){var F=C.split("="),D=F[0],E=F[1];B[D]=E},this)}return B},loadStylesheets:function(B){var A=Ext.getBody();Ext.each(B.stylesheets,function(C){A.createChild({tag:"link",rel:"stylesheet",type:"text/css",href:String.format("stylesheets/{0}.css",C)})},this)},buildScriptTag:function(B,C){var A=document.createElement("script");A.type="text/javascript";A.src=B;if(A.readyState){A.onreadystatechange=function(){if(A.readyState=="loaded"||A.readyState=="complete"){A.onreadystatechange=null;C()}}}else{A.onload=C}return A},loadFiles:function(I,C,H,J){var J=J||this,F=document.getElementsByTagName("head")[0],B=document.createDocumentFragment(),A=I.length,G=0,E=this;if(I.length==0){H.call(J);return}var K=function(L){F.appendChild(E.buildScriptTag(I[L],D))};var D=function(){G++;if(A==G&&Ext.isFunction(H)){H.call(J)}else{if(C===true){K(G)}}};if(C===true){K.call(this,0)}else{Ext.each(I,function(M,L){B.appendChild(this.buildScriptTag(M,D))},this);F.appendChild(B)}}});Ext.onReady(function(){ExtMVC.booter=new ExtMVC.lib.Booter();ExtMVC.booter.boot()});ExtMVC.lib.ControllerClassManager=Ext.extend(ExtMVC.lib.ClassManager,{constructor:function(A){A=A||{};Ext.applyIf(A,{instances:{},autoInstantiate:true});ExtMVC.lib.ControllerClassManager.superclass.constructor.call(this,A);this.addEvents("class-instantiated")},define:function(B){var C=this.getRegistered(B);if(C==undefined){throw new Ext.Error(String.format("The {0} controller could not be found",B))}var D=B=="controller"?Ext.util.Observable:this.getConstructor(C.extend||"application");var A=Ext.extend(D,C);this.constructors[B]=A;if(this.autoInstantiate===true){this.instantiate(B)}this.fireEvent("class-defined",B,A);return A},instantiate:function(C,B){var A=this.instances[C];if(A==undefined){A=new (this.getConstructor(C))(B);A.name=C;this.instances[C]=A;this.fireEvent("class-instantiated",C,A)}return A},getInstance:function(A){return this.instances[A]||this.instantiate(A)}});ExtMVC.registerClassManager("controller",new ExtMVC.lib.ControllerClassManager());ExtMVC.lib.Dependencies=Ext.extend(Ext.util.Observable,{constructor:function(){this.dependencies={};ExtMVC.lib.Dependencies.superclass.constructor.apply(this,arguments)},get:function(A){return this.dependencies[A]||[]},add:function(D,C,B){var A=this.dependencies[D]||[];A.push({name:C,config:B});this.dependencies[D]=A}});ExtMVC.lib.Dispatcher=Ext.extend(Ext.util.MixedCollection,{constructor:function(A){ExtMVC.lib.Dispatcher.superclass.constructor.apply(this,arguments);Ext.apply(this,A||{},{matchers:[],matcherOrder:[]});this.addEvents("dispatch");this.registerDefaultDispatchMatchers()},dispatch:function(){var C=this.getDispatchMatcher.apply(this,arguments),B=C.getDispatchConfig.apply(C,arguments);if(this.fireEvent("dispatch",arguments,C,B)!==false){var A=ExtMVC.getController(B.controller);if(A==undefined){throw new Ext.Error(String.format("The controller you are trying to dispatch to ({0}) does not exist",B.controller))}if(A[B.action]==undefined){throw new Ext.Error(String.format("The action {0} does not exist on the {1} controller",B.action,B.controller))}return A[B.action].apply(A,B.arguments)}},registerDispatchMatcher:function(A){this.add(A);this.matcherOrder.push(A.name)},registerDefaultDispatchMatchers:function(){this.registerDispatchMatcher(new ExtMVC.lib.DefaultDispatchMatcher());this.registerDispatchMatcher(new ExtMVC.lib.ObjectDispatchMatcher())},getDispatchMatcher:function(){var A=arguments,B;Ext.each(this.matcherOrder,function(C){var D=this.get(C);if(D.matches.apply(D,A)){B=D;return false}},this);if(B==undefined){throw new Ext.Error("Could not find a suitable Dispatch Matcher for the dispatch arguments provided",A)}else{return B}},getKey:function(A){return A.name}});ExtMVC.lib.DispatchMatcher=Ext.extend(Object,{constructor:function(A){Ext.applyIf(this,A||{});ExtMVC.lib.DispatchMatcher.superclass.constructor.apply(this,arguments)},matches:function(){throw new Ext.Error("DispatchMatcher subclass must implement this method")},getDispatchConfig:function(){throw new Ext.Error("DispatchMatcher subclass must implement this method")}});ExtMVC.lib.DefaultDispatchMatcher=Ext.extend(ExtMVC.lib.DispatchMatcher,{name:"default",matches:function(A,C,B){return Ext.isString(A)&&Ext.isString(C)&&Ext.isArray(B||[])},getDispatchConfig:function(){return{controller:arguments[0],action:arguments[1],arguments:arguments[2]||[]}}});ExtMVC.lib.ObjectDispatchMatcher=Ext.extend(ExtMVC.lib.DispatchMatcher,{name:"object",matches:function(){var A=arguments[0];Ext.applyIf(A,{action:"index"});return arguments.length==1&&A.controller!=undefined&&A.action!=undefined},getDispatchConfig:function(){return arguments[0]}});ExtMVC.lib.RouterDispatchManager=Ext.extend(ExtMVC.lib.DispatchMatcher,{name:"router"});ExtMVC.Environment=Ext.extend(Ext.util.Observable,{constructor:function(A){A=A||{};Ext.apply(this,A,{pluginsDir:"../vendor/plugins",libDir:"../lib",configDir:"../config",overridesDir:"../config/overrides",appDir:"../app",vendor:["mvc"],mvcFilename:"ext-mvc-all-min",config:["app/App","config/routes"],stylesheets:["ext-all"]});ExtMVC.Environment.superclass.constructor.apply(this,arguments)},update:function(A){Ext.apply(this,A)}});ExtMVC.Inflector={Inflections:{plural:[[(/(quiz)$/i),"$1zes"],[(/^(ox)$/i),"$1en"],[(/([m|l])ouse$/i),"$1ice"],[(/(matr|vert|ind)ix|ex$/i),"$1ices"],[(/(x|ch|ss|sh)$/i),"$1es"],[(/([^aeiouy]|qu)y$/i),"$1ies"],[(/(hive)$/i),"$1s"],[(/(?:([^f])fe|([lr])f)$/i),"$1$2ves"],[(/sis$/i),"ses"],[(/([ti])um$/i),"$1a"],[(/(buffal|tomat)o$/i),"$1oes"],[(/(bu)s$/i),"$1ses"],[(/(alias|status)$/i),"$1es"],[(/(octop|vir)us$/i),"$1i"],[(/(ax|test)is$/i),"$1es"],[(/s$/i),"s"],[(/$/),"s"]],singular:[[(/(quiz)zes$/i),"$1"],[(/(matr)ices$/i),"$1ix"],[(/(vert|ind)ices$/i),"$1ex"],[(/^(ox)en/i),"$1"],[(/(alias|status)es$/i),"$1"],[(/(octop|vir)i$/i),"$1us"],[(/(cris|ax|test)es$/i),"$1is"],[(/(shoe)s$/i),"$1"],[(/(o)es$/i),"$1"],[(/(bus)es$/i),"$1"],[(/([m|l])ice$/i),"$1ouse"],[(/(x|ch|ss|sh)es$/i),"$1"],[(/(m)ovies$/i),"$1ovie"],[(/(s)eries$/i),"$1eries"],[(/([^aeiouy]|qu)ies$/i),"$1y"],[(/([lr])ves$/i),"$1f"],[(/(tive)s$/i),"$1"],[(/(hive)s$/i),"$1"],[(/([^f])ves$/i),"$1fe"],[(/(^analy)ses$/i),"$1sis"],[(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i),"$1$2sis"],[(/([ti])a$/i),"$1um"],[(/(n)ews$/i),"$1ews"],[(/s$/i),""]],irregular:[["move","moves"],["sex","sexes"],["child","children"],["man","men"],["person","people"]],uncountable:["sheep","fish","series","species","money","rice","information","equipment"]},ordinalize:function(A){if(11<=parseInt(A,10)%100&&parseInt(A,10)%100<=13){return A+"th"}else{switch(parseInt(A,10)%10){case 1:return A+"st";case 2:return A+"nd";case 3:return A+"rd";default:return A+"th"}}},pluralize:function(C){var E=ExtMVC.Inflector.uncountableOrIrregular(C);if(E){return E}for(var A=0;A<ExtMVC.Inflector.Inflections.plural.length;A++){var B=ExtMVC.Inflector.Inflections.plural[A][0];var D=ExtMVC.Inflector.Inflections.plural[A][1];if(B.test(C)){return C.replace(B,D)}}return C},singularize:function(C){var E=ExtMVC.Inflector.uncountableOrIrregular(C);if(E){return E}for(var A=0;A<ExtMVC.Inflector.Inflections.singular.length;A++){var B=ExtMVC.Inflector.Inflections.singular[A][0];var D=ExtMVC.Inflector.Inflections.singular[A][1];if(B.test(C)){return C.replace(B,D)}}return C},uncountableOrIrregular:function(E){for(var C=0;C<ExtMVC.Inflector.Inflections.uncountable.length;C++){var B=ExtMVC.Inflector.Inflections.uncountable[C];if(E.toLowerCase==B){return B}}for(var C=0;C<ExtMVC.Inflector.Inflections.irregular.length;C++){var D=ExtMVC.Inflector.Inflections.irregular[C][0];var A=ExtMVC.Inflector.Inflections.irregular[C][1];if((E.toLowerCase==D)||(E==A)){return A}}return false}};ExtMVC.lib.ModelClassManager=Ext.extend(ExtMVC.lib.ClassManager,{define:function(A){var B=this.getRegistered(A);if(B==undefined){throw new Ext.Error(String.format("The {0} model has not been registered yet",A))}return this.constructors[A]=ExtMVC.model.define(A,B)}});ExtMVC.registerClassManager("model",new ExtMVC.lib.ModelClassManager());ExtMVC.router.Route=function(C,A){this.mappingString=C;this.options=A||{};this.paramMatchingRegex=new RegExp(/:([0-9A-Za-z\_]*)/g);this.paramsInMatchString=this.mappingString.match(this.paramMatchingRegex)||[];this.paramsInStringWithOptions=[];this.conditions=this.options.conditions||{};if(this.options.conditions){delete this.options.conditions}for(var B=0;B<this.paramsInMatchString.length;B++){this.paramsInStringWithOptions.push(this.paramsInMatchString[B])}for(var D in A){this.paramsInStringWithOptions.push(":"+D)}this.matcherRegex=this.convertToUsableRegex(C)};ExtMVC.router.Route.prototype={recognises:function(A){return this.matcherRegex.test(A)},matchesFor:function(B){if(!this.recognises(B)){return false}var E={};var D=this.paramsInMatchString;var A=B.match(this.matcherRegex);A.shift();for(var C=D.length-1;C>=0;C--){E[D[C].replace(":","")]=A[C]}for(option in this.options){E[option]=this.options[option]}return E},urlForNamed:function(A){var A=A||{};return this.urlFor(Ext.applyIf(A,this.options))},urlFor:function(C){var B=this.mappingString;for(var F in C){if(C[F]&&this.options[F]&&C[F]!=this.options[F]){return false}}var E=[];for(var F in C){E.push(":"+F)}E=E.sort();var A=this.paramsInStringWithOptions.sort();if(A.length!=E.length){return false}for(var D=0;D<E.length;D++){if(E[D]!=A[D]){return false}}for(var F in C){B=B.replace(":"+F,C[F])}return B},convertToUsableRegex:function(A){var E=this.paramsInMatchString;for(var B=E.length-1;B>=0;B--){var C=this.conditions[E[B]];var D=String.format("({0})",C||"[a-zA-Z0-9_,]+");A=A.replace(new RegExp(E[B]),D)}return new RegExp("^"+A+"$")}};ExtMVC.router.Router=function(){};ExtMVC.router.Router.prototype={mappings:[],namedRoutes:{},connect:function(B,C){var A=new ExtMVC.router.Route(B,C);this.mappings.push(A);return A},name:function(A,B,C){this.namedRoutes[A]=this.connect(B,C)},root:function(A){var A=A||{};this.connect("",Ext.applyIf(A,{action:"index"}))},resources:function(A,I){if(arguments[1]&&typeof(arguments[1])=="string"){var H=arguments[arguments.length-1];var B=(typeof(H)=="object")?H:{};for(var C=0;C<arguments.length;C++){if(!(H===arguments[C]&&typeof(H)=="object")){this.resources(arguments[C],B)}}return}var G=String.format("{0}_path",A.pluralize());var E=String.format("new_{0}_path",A.singularize());var F=String.format("{0}_path",A.singularize());var D=String.format("edit_{0}_path",A.singularize());this.name(G,A,Ext.apply({},{controller:A,action:"index"}));this.name(E,A+"/new",Ext.apply({},{controller:A,action:"new"}));this.name(F,A+"/:id",Ext.apply({},{controller:A,action:"show",conditions:{":id":"[0-9]+"}}));this.name(D,A+"/:id/edit",Ext.apply({},{controller:A,action:"edit",conditions:{":id":"[0-9]+"}}))},redirectTo:function(){var A=this.urlFor.apply(this,arguments);if(A){Ext.History.add(A);return true}else{return false}},linkTo:function(B,A){var A=A||{};var C=this.urlFor(B);if(C){return Ext.applyIf(A,{url:C,cls:[B.controller,B.action,B.id].join("-").replace("--","-").replace(/-$/,""),text:this.constructDefaultLinkToName(B,A),handler:function(){Ext.History.add(C)}})}else{throw new Error("No match for that url specification")}},constructDefaultLinkToName:function(B,A){if(!B||!B.controller||!B.action){return""}var A=A||{};Ext.applyIf(A,{singularName:B.controller.singularize()});var C=B.action.titleize();if(C=="Index"){return"Show "+B.controller.titleize()}else{return C+" "+A.singularName.titleize()}},recognise:function(C){for(var D=0;D<this.mappings.length;D++){var A=this.mappings[D];var B=A.matchesFor(C);if(B){return B}}return false},urlFor:function(D,B){var A;if(typeof(D)=="string"){if(A=this.namedRoutes[D]){var B=B||{};if(typeof(B)=="number"){B={id:B}}if(B.data&&B.data.id){B={id:B.data.id}}return A.urlForNamed(B)}}else{for(var E=0;E<this.mappings.length;E++){A=this.mappings[E];var C=A.urlFor(D);if(C){return C}}}return false},route:function(A){document.location.hash=A},handleRoute:function(A){return this.route.createDelegate(this,[A])},withOptions:function(B,A){var B=B||{};var D=this;var C={};C.prototype=this;Ext.apply(C,{connect:function(E,F){var F=F||{};Ext.applyIf(F,B);D.connect.call(D,E,F)},name:function(E,F,G){var G=G||{};Ext.applyIf(G,B);D.name.call(D,E,F,G)}});A.call(this,C)}};ExtMVC.router.Router.defineRoutes=function(A){A.connect(":controller/:action");A.connect(":controller/:action/:id")};String.prototype.capitalize=function(){return this.charAt(0).toUpperCase()+this.substr(1).toLowerCase()};String.prototype.titleize=function(){return this.replace(/\w\S*/g,function(A){return A.charAt(0).toUpperCase()+A.substr(1).toLowerCase()})};String.prototype.camelize=function(){return this.replace(/_/g," ").titleize().replace(/ /g,"")};String.prototype.underscore=function(){return this.replace(/([A-Z])/g,"_$1").toLowerCase().replace(/ /g,"_").replace(/^_/,"")};String.prototype.singularize=function(){return ExtMVC.Inflector.singularize(this)};String.prototype.pluralize=function(){return ExtMVC.Inflector.pluralize(this)};String.prototype.humanize=function(){return this.underscore().replace(/_/g," ")};String.prototype.escapeHTML=function(){return this.replace(/&/g,"&").replace(/>/g,">").replace(/</g,"<").replace(/"/g,""")};String.prototype.toCurrency=function(H){if(typeof(H)=="undefined"){var H="$"}var B=this.split(".")[0],F=this.split(".")[1];var A=Math.floor(B.length/3);var E=B.length%3,G=E;var C=E==0?[]:[B.substr(0,E)];for(var D=0;D<A;D++){C.push(B.substr(E+(D*3),3))}B=H+C.join(",");return F?String.format("{0}.{1}",B,F):B};ExtMVC.lib.ViewClassManager=Ext.extend(ExtMVC.lib.ClassManager,{autoDefine:false,define:function define(B){var E=this.getRegistered(B);if(E==undefined){this.throwViewNotFoundError(B)}var F=E.xtype||"panel";delete E.xtype;var C=this.getConstructorForXType(F);var A=Ext.extend(C,E);if(A==undefined){throw new Error(String.format("The {0} view could not be created because the xtype you supplied ('{1}') could not be found",B,E.xtype))}var D=E.registerXType;if(D){Ext.reg(D,A);this.xtypeLookup[D]=A}this.constructors[B]=A;this.fireEvent("class-defined",B,A);return A},register:function register(C,B,A){var D=this.buildName(C,B);ExtMVC.lib.ViewClassManager.superclass.register.call(this,D,A)},getConstructor:function getConstructor(B,A){var C=this.buildName(B,A);return ExtMVC.lib.ViewClassManager.superclass.getConstructor.call(this,C)},getConstructorForXType:function getConstructorForXType(D){var B=this.xtypeLookup[D];if(B==undefined){for(var A in this.registeredClasses){var C=this.registeredClasses[A];if(C.registerXType==D){B=this.getConstructor(A.split("-")[0],A.split("-")[1])}}}return B},buildName:function buildName(B,A){return String.format("{0}-{1}",B,A)},xtypeLookup:{box:Ext.BoxComponent,button:Ext.Button,buttongroup:Ext.ButtonGroup,colorpalette:Ext.ColorPalette,component:Ext.Component,container:Ext.Container,cycle:Ext.CycleButton,dataview:Ext.DataView,datepicker:Ext.DatePicker,editor:Ext.Editor,editorgrid:Ext.grid.EditorGridPanel,flash:Ext.FlashComponent,grid:Ext.grid.GridPanel,listview:Ext.ListView,panel:Ext.Panel,progress:Ext.ProgressBar,propertygrid:Ext.grid.PropertyGrid,slider:Ext.Slider,spacer:Ext.Spacer,splitbutton:Ext.SplitButton,tabpanel:Ext.TabPanel,treepanel:Ext.tree.TreePanel,viewport:Ext.ViewPort,window:Ext.Window,paging:Ext.PagingToolbar,toolbar:Ext.Toolbar,tbbutton:Ext.Toolbar.Button,tbfill:Ext.Toolbar.Fill,tbitem:Ext.Toolbar.Item,tbseparator:Ext.Toolbar.Separator,tbspacer:Ext.Toolbar.Spacer,tbsplit:Ext.Toolbar.SplitButton,tbtext:Ext.Toolbar.TextItem,menu:Ext.menu.Menu,colormenu:Ext.menu.ColorMenu,datemenu:Ext.menu.DateMenu,menubaseitem:Ext.menu.BaseItem,menucheckitem:Ext.menu.CheckItem,menuitem:Ext.menu.Item,menuseparator:Ext.menu.Separator,menutextitem:Ext.menu.TextItem,form:Ext.FormPanel,checkbox:Ext.form.Checkbox,checkboxgroup:Ext.form.CheckboxGroup,combo:Ext.form.ComboBox,datefield:Ext.form.DateField,displayfield:Ext.form.DisplayField,field:Ext.form.Field,fieldset:Ext.form.FieldSet,hidden:Ext.form.Hidden,htmleditor:Ext.form.HtmlEditor,label:Ext.form.Label,numberfield:Ext.form.NumberField,radio:Ext.form.Radio,radiogroup:Ext.form.RadioGroup,textarea:Ext.form.TextArea,textfield:Ext.form.TextField,timefield:Ext.form.TimeField,trigger:Ext.form.TriggerField,chart:Ext.chart.Chart,barchart:Ext.chart.BarChart,cartesianchart:Ext.chart.CartesianChart,columnchart:Ext.chart.ColumnChart,linechart:Ext.chart.LineChart,piechart:Ext.chart.PieChart,arraystore:Ext.data.ArrayStore,directstore:Ext.data.DirectStore,groupingstore:Ext.data.GroupingStore,jsonstore:Ext.data.JsonStore,simplestore:Ext.data.SimpleStore,store:Ext.data.Store,xmlstore:Ext.data.XmlStore},throwViewNotFoundError:function(B){var A=B.split("-")[0],C=B.split("-")[1];var D=String.format('The {0} view could not be found, please check that your app/views/{1} directory contains a file called {2}, that the file contains "{3}" and that config/environment.json includes this file',B,A,C,String.format("Ext.registerView('{0}', '{1}')",A,C));throw new Error(D)}});ExtMVC.registerClassManager("view",new ExtMVC.lib.ViewClassManager());Ext.override(Ext.Component,{getXTypes:function(){var A=this.constructor;if(!A.xtypes){var D=[],B=this;while(B){var C=B.constructor.xtype;if(C!=undefined){D.unshift(C)}B=B.constructor.superclass}A.xtypeChain=D;A.xtypes=D.join("/")}return A.xtypes}});ExtMVC.registerController("controller",{constructor:function(A){Ext.util.Observable.prototype.constructor.apply(this,arguments);Ext.apply(this,{renderStrategies:{}},A||{});this.registerDefaultRenderStrategies();this.initEvents();this.initListeners()},registerRenderStrategy:function(B,A){this.renderStrategies[B]=A},getRenderStrategy:function(A){var C=A.getXTypes().split("/");for(var B=C.length-1;B>=0;B--){var D=this.renderStrategies[C[B]];if(D!=undefined){return D}}throw new Ext.Error("No render strategy could be found for the container you specified")},registerDefaultRenderStrategies:function(){this.registerRenderStrategy("panel",this.panelRenderStrategy);this.registerRenderStrategy("tabpanel",this.tabPanelRenderStrategy)},initEvents:function(){},initListeners:function(){},showNotice:function(A){},addTo:null,render:function render(){switch(arguments.length){case 1:case 2:var C=this.name,D=arguments[0],B=arguments[1]||{};break;case 3:var C=arguments[0],D=arguments[1],B=arguments[2]||{};break}Ext.applyIf(B,{autoAdd:true,addTo:ExtMVC.app.main});var A=new (this.getView(C,D))(B);if(B.autoAdd===true){if(A.isXType("window")){A.show()}else{this.getRenderStrategy(B.addTo)(B.addTo,A)}}return A},getView:function(B,A){return ExtMVC.getView(B,A)},tabPanelRenderStrategy:function(B,A){var C=B.getItem(A.id);if(C==undefined){B.add(A);B.doLayout();B.activate(A)}else{B.setActiveTab(A.id);A.destroy()}},panelRenderStrategy:function(B,A){B.removeAll();B.add(A);B.doLayout()}});ExtMVC.registerController("crud",{extend:"controller",model:null,create:function create(C,B){var A=new this.model(C);A.save({scope:this,success:this.onCreateSuccess,failure:this.onCreateFailure})},read:function read(A){this.model.findById(A,{scope:this,success:function(B){this.fireEvent("read",B)},failure:function(){this.fireEvent("read-failed",A)}})},update:function update(A,C){for(var B in C){A.set(B,C[B])}A.save({scope:this,success:function(D){this.onUpdateSuccess(D,C)},failure:function(){this.onUpdateFailure(A,C)}})},destroy:function destroy(A){if(A.destroy==undefined){var B={};B[this.model.prototype.primaryKey]=parseInt(A,10);var A=new (this.model)(B)}A.destroy({scope:this,success:this.onDestroySuccess,failure:this.onDestroyFailure})},index:function index(B){B=B||{};Ext.applyIf(B,{model:this.model,controller:this,listeners:this.getIndexViewListeners(),viewsPackage:this.viewsPackage});var A=this.render("index",B);this.fireEvent("index");return A},build:function build(){var A=this.render("new",{model:this.model,controller:this,listeners:this.getBuildViewListeners()});this.onBuild(A);return A},edit:function edit(A,B){B=B||{};if(A instanceof Ext.data.Record){Ext.applyIf(B,{model:this.model,controller:this,listeners:this.getEditViewListeners(),id:String.format("{0}_edit_{1}",this.name,A.get(A.primaryKey))});var D=this.render("edit",B);D.loadRecord(A);this.onEdit(D,A);this.fireEvent("edit",A);return D}else{var C=A;this.model.find(parseInt(C,10),{scope:this,success:function(E){this.edit(E)}})}},getIndexViewListeners:function getIndexViewListeners(){return{scope:this,"delete":this.destroy,"new":this.build,edit:this.edit}},getEditViewListeners:function getEditViewListeners(){return{scope:this,cancel:this.index,save:this.update}},getBuildViewListeners:function getBuildViewListeners(){return{scope:this,cancel:this.index,save:this.create}},showCreatedNotice:function(){this.showNotice(String.format("{0} successfully created",this.model.prototype.singularHumanName))},showUpdatedNotice:function(){this.showNotice(String.format("{0} successfully updated",this.model.prototype.singularHumanName))},showDestroyedNotice:function(){this.showNotice(String.format("{0} successfully deleted",this.model.prototype.singularHumanName))},onCreateSuccess:function(A){if(this.fireEvent("create",A)!==false){this.showCreatedNotice();this.index()}},onCreateFailure:function(A){this.fireEvent("create-failed",A)},onUpdateSuccess:function(A,B){if(this.fireEvent("update",A,B)!==false){this.showUpdatedNotice();this.index()}},onUpdateFailure:function(A,B){this.fireEvent("update-failed",A,B)},onDestroySuccess:function(A){this.fireEvent("delete",A);this.showDestroyedNotice()},onDestroyFailure:function(A){this.fireEvent("delete-failed",A)},onBuild:function(A){},onEdit:function(A){},initEvents:function(){this.addEvents("create","create-failed","read","read-failed","update","update-failed","delete","delete-failed","index","edit")},getView:function getView(C,B){var A;try{A=ExtMVC.getController("controller").getView.apply(this,arguments)}catch(D){A=this.scaffoldViewName(B)}return A},scaffoldViewName:function scaffoldViewName(A){return ExtMVC.getView("scaffold",A)}});ExtMVC.model={pendingCreation:{},getModelsPendingDefinitionOf:function(A){return this.pendingCreation[A]||[]},setModelPendingDefinitionOf:function(B,D,C){var A=this.pendingCreation[B]||[];A.push({name:D,config:C});this.pendingCreation[B]=A},strictMode:false,modelNamespace:function(){Ext.ns("ExtMVC.modelsTemp");return ExtMVC.modelsTemp}(),define:function(A,B){var D=true,B=B||{};if(typeof B.extend!="undefined"){var C=this.modelNamespace[B.extend];if(typeof C=="undefined"){D=false;this.setModelPendingDefinitionOf(B.extend,A,B)}}if(D){return this.create.apply(this,arguments)}},create:function(B,E){E=E||{};if(this.isAlreadyDefined(B)){if(this.strictMode){throw new Error(B+" is already defined")}return false}var F=this.modelNamespace[E.extend];var A=this.buildFields(E.fields,F);delete E.fields;var D=this.modelNamespace[B]=Ext.data.Record.create(A);var G=E.classMethods||{};delete E.classMethods;Ext.apply(D.prototype,E);if(typeof F!="undefined"){Ext.applyIf(G,F);Ext.applyIf(D.prototype,F.prototype)}D.prototype.modelName=B;this.setupNames(D);for(var C in G){if(C!="prototype"){D[C]=G[C]}}this.initializePlugins(D);this.afterCreate(B);return D},afterCreate:function(A){var B=this.getModelsPendingDefinitionOf(A);if(B){Ext.each(B,function(C){this.create(C.name,C.config)},this)}},isAlreadyDefined:function(A){if(typeof this.modelNamespace[A]!="undefined"){return true}var C=false;for(superclass in this.pendingCreation){var B=this.pendingCreation[superclass];Ext.each(B,function(D){if(D.name==A){C=true}},this)}return C},buildFields:function(B,C){B=B||[];var A=new Ext.util.MixedCollection(false,function(D){return D.name});A.addAll(B);if(typeof C!="undefined"){C.prototype.fields.each(function(D){if(typeof A.get(D.name)=="undefined"){A.add(D)}})}return A.items},setupNames:function(A){var C=A.prototype,B=ExtMVC.Inflector;Ext.applyIf(A.prototype,{tableName:B.pluralize(C.modelName.underscore()),foreignKeyName:B.singularize(C.modelName.underscore())+"_id",singularHumanName:C.modelName.humanize().titleize(),pluralHumanName:B.pluralize(C.modelName.humanize().titleize())})},plugins:[],addPlugin:function(A){this.plugins.push(A)},initializePlugins:function(A){Ext.each(this.plugins,function(B){B.initialize(A)},this)}};Ext.ns("ExtMVC.model.plugin");ExtMVC.model.Base=function(){};ExtMVC.model.Base.prototype={primaryKey:"id",newRecord:function(){var A=this.get(this.primaryKey);return typeof A=="undefined"||A==""},MVCModelId:function(){return String.format("{0}-{1}",this.tableName,this.get(this.primaryKey))},getReader:function(){if(!this.reader){this.reader=new Ext.data.JsonReader({totalProperty:"results",root:this.tableName},this.constructor)}return this.reader},initialize:Ext.emptyFn};Ext.apply(Ext.data.Record.prototype,new ExtMVC.model.Base());ExtMVC.model.plugin.adapter={initialize:function(B){var A=new this.RESTJSONAdapter();Ext.override(Ext.data.Record,A.instanceMethods());Ext.apply(B,A.classMethods())}};ExtMVC.model.addPlugin(ExtMVC.model.plugin.adapter);ExtMVC.model.plugin.adapter.Abstract=function(A){};ExtMVC.model.plugin.adapter.Abstract.prototype={doSave:Ext.emptyFn,doFind:Ext.emptyFn,doDestroy:Ext.emptyFn,instanceMethods:function(){return{adapter:this,save:function(A){A=A||{};if(A.skipValidation===true||this.isValid()){return this.adapter.doSave(this,A)}else{if(typeof A.failure=="function"){return A.failure.call(A.scope||this,this)}}},destroy:function(A){return this.adapter.doDestroy(this,A)},update:function(B,A){this.setValues(B);this.save(A)},loaded:function(){}}},classMethods:function(){return{adapter:this,create:function(C,B){var A=new this(C);A.save(B);return A},build:function(A){return new this(A)},find:function(B,A){if(typeof(B)=="number"||typeof(B)=="string"){B={primaryKey:B}}return this.adapter.doFind(B,A,this)},destroy:function(B,A){return this.adapter.doDestroy(B,A,this)}}},hasManyAssociationMethods:function(){return{adapter:this,create:function(C,B){var A=new this.associatedClass(C)},build:function(B,A){},find:function(A){},loaded:function(){},destroy:function(A){}}},belongsToAssociationMethods:function(){return{adapter:this,find:function(A){},loaded:function(){},destroy:function(A){}}}};ExtMVC.model.plugin.adapter.MemoryAdapter=Ext.extend(ExtMVC.model.plugin.adapter.Abstract,{store:{},primaryKeys:{},doSave:function(A,B){if(typeof A=="undefined"){throw new Error("No instance provided to REST Adapter save")}B=B||{};var C=A.get(A.primaryKey);if(typeof C=="undefined"){C=this.primaryKeyFor(A);A.set(A.primaryKey,C)}this.store[A.tableName]=this.store[A.tableName]||{};this.store[A.tableName][C.toString()]=A.data},doFind:function(G,C,D){G=G||{};C=C||{};var B=function(I,H){if(typeof I=="function"){I.apply(C.scope,H)}};var F=this.store[D.prototype.tableName]||{};if(typeof G.primaryKey=="undefined"){var A=[];for(primaryKey in F){A.push((F[primaryKey]))}console.log(A);return new Ext.data.Store({autoLoad:true,data:{rows:A},fields:D.prototype.fields.items,reader:new Ext.data.JsonReader({root:"rows"},D)})}else{var E=F[G.primaryKey.toString()];if(typeof E=="undefined"){B(C.failure)}else{B(C.success,[new D(E)])}}},doDestroy:function(A,B){if(typeof A=="undefined"){throw new Error("No instance provided to REST Adapter save")}B=B||{};Ext.Ajax.request(Ext.applyIf(B,{method:this.destroyMethod,url:this.instanceUrl(A)}))},primaryKeyFor:function(A){this.primaryKeys[A.tableName]=this.primaryKeys[A.tableName]||1;return this.primaryKeys[A.tableName]++}});ExtMVC.model.plugin.adapter.RESTAdapter=Ext.extend(ExtMVC.model.plugin.adapter.Abstract,{createMethod:"POST",readMethod:"GET",updateMethod:"PUT",destroyMethod:"DELETE",proxyType:Ext.data.HttpProxy,doSave:function(B,D){if(typeof B=="undefined"){throw new Error("No instance provided to REST Adapter save")}D=D||{};var A=D.success||Ext.emptyFn,C=D.failure||Ext.emptyFn;delete D.success;delete D.failure;Ext.Ajax.request(Ext.apply({url:this.instanceUrl(B),method:B.newRecord()?this.createMethod:this.updateMethod,params:this.buildPostData(B),success:function(E,F,G){var G=G||this;return function(H,I){var L=E.modelName.underscore(),K=Ext.decode(H.responseText)[L];for(var J in K){E.set(J,K[J])}F.call(G,E)}}(B,A,D.scope),failure:function(E,F,G){var G=D.scope||this;return function(H,I){C.call(G,E)}}(B,C,D.scope)},D))},afterSave:function(){},doFind:function(E,B,C){E=E||{};B=B||{};var F=(E.primaryKey!==undefined),A=B.url||this.findUrl(E,C);Ext.applyIf(B,{conditions:E,scope:this});var D=F?this.doSingleFind:this.doCollectionFind;return D.call(this,A,B,C)},doDestroy:function(B,C,D){var C=C||{};if(typeof B=="undefined"){throw new Error("No instance provided to REST Adapter destroy")}if(!(B instanceof Ext.data.Record)){var E=parseInt(B,10);B=new D();B.set(D.prototype.primaryKey,E)}var A=C.success||Ext.emptyFn;delete C.success;return Ext.Ajax.request(Ext.applyIf(C,{method:this.destroyMethod,url:this.instanceUrl(B),success:function(){A.call(C.scope||this,B)}}))},doSingleFind:function(D,C,F){var H=C.callback,A=C.success,G=C.failure;delete C.callback;delete C.success;delete C.failure;var E=this.decodeSingleLoadResponse;var B=function(J,I){if(typeof J=="function"){J.apply(C.scope,I)}};Ext.Ajax.request(Ext.apply(C,{callback:function(K,L,J){if(L===true){var I=new F(E(J.responseText,F));B(A,[I,K,J])}else{B(G,arguments)}B(H,arguments)}},this.buildProxyConfig(D)))},storeConfig:{autoLoad:true,remoteSort:false},doCollectionFind:function(B,A,C){Ext.applyIf(A,this.storeConfig);if(A.conditions!=undefined){Ext.applyIf(A,{baseParams:A.conditions})}return new Ext.data.Store(Ext.applyIf(A,{reader:C.prototype.getReader(),proxy:new this.proxyType(this.buildProxyConfig(B))}))},instanceUrl:function(A){if(A.newRecord()){return String.format("/{0}",A.tableName)}else{return String.format("/{0}/{1}",A.tableName,A.get(A.primaryKey))}},collectionUrl:function(A){return String.format("/{0}",A.prototype.tableName)},buildProxyConfig:function(A){return{url:A,method:this.readMethod}},buildPostData:function(A){var C={},B=A.modelName.underscore();for(key in A.data){C[B+"["+key+"]"]=A.data[key]}return C},decodeSingleLoadResponse:function(C,A){var B=A.prototype.tableName;return Ext.decode(C)[B]},findUrl:function(C,B){if(typeof(C)=="object"&&C.primaryKey){var A=new B({});A.set(A.primaryKey,C.primaryKey);delete C.primaryKey;return this.instanceUrl(A)}else{return this.collectionUrl(B)}}});ExtMVC.model.plugin.adapter.RESTJSONAdapter=Ext.extend(ExtMVC.model.plugin.adapter.RESTAdapter,{doSave:function(A,B){if(typeof A=="undefined"){throw new Error("No instance provided to REST Adapter save")}Ext.applyIf(B||{},{jsonData:A.data,params:{},headers:{"Content-Type":"application/json"}});ExtMVC.model.plugin.adapter.RESTJSONAdapter.superclass.doSave.apply(this,arguments)},doDestroy:function(A,B,C){B=B||{};Ext.applyIf(B,{headers:{"Content-Type":"application/json"}});ExtMVC.model.plugin.adapter.RESTJSONAdapter.superclass.doDestroy.call(this,A,B,C)},decodeSingleLoadResponse:function(C,A){var B=ExtMVC.Inflector.singularize(A.prototype.tableName);return Ext.decode(C)[B]},buildProxyConfig:function(A){var B=ExtMVC.model.plugin.adapter.RESTJSONAdapter.superclass.buildProxyConfig.apply(this,arguments);return Ext.apply(B,{headers:{"Content-Type":"application/json"}})}});Ext.ns("ExtMVC.model.plugin.validation");ExtMVC.model.plugin.validation.AbstractValidation=function(A,C,B){this.ownerClass=A;this.field=C;Ext.apply(this,B)};ExtMVC.model.plugin.validation.AbstractValidation.prototype={getValue:function(A){return A.get(this.field)},isValid:function(A){return true}};ExtMVC.model.plugin.validation.ValidatesPresenceOf=Ext.extend(ExtMVC.model.plugin.validation.AbstractValidation,{message:"must be present",isValid:function(A){var C=this.getValue(A),B=false;switch(typeof C){case"object":if(C!=null){B=true}break;case"string":if(C.length!=0){B=true}break}return B}});ExtMVC.model.plugin.validation.ValidatesLengthOf=Ext.extend(ExtMVC.model.plugin.validation.AbstractValidation,{tooShortMessage:"is too short",tooLongMessage:"is too long",message:"",isValid:function(A){var B=this.getValue(A);if(typeof B=="undefined"){return true}if(this.minimum&&B.length<this.minimum){this.message=this.tooShortMessage;return false}if(this.maximum&B.length>this.maximum){this.message=this.tooLongMessage;return false}return true}});ExtMVC.model.plugin.validation.ValidatesNumericalityOf=Ext.extend(ExtMVC.model.plugin.validation.AbstractValidation,{message:"must be a number",isValid:function(A){return"number"==typeof this.getValue(A)}});ExtMVC.model.plugin.validation.ValidatesInclusionOf=Ext.extend(ExtMVC.model.plugin.validation.AbstractValidation,{constructor:function(A,C,B){B=B||{};Ext.applyIf(B,{allowed:[]});ExtMVC.model.plugin.validation.ValidatesInclusionOf.superclass.constructor.call(this,A,C,B);Ext.applyIf(this,{message:"must be one of "+this.allowed.toSentence("or")})},isValid:function(A){var C=this.getValue(A);for(var B=0;B<this.allowed.length;B++){if(this.allowed[B]==C){return true}}return false}});ExtMVC.model.plugin.validation.ValidatesExclusionOf=Ext.extend(ExtMVC.model.plugin.validation.AbstractValidation,{constructor:function(A,C,B){B=B||{};Ext.applyIf(B,{disallowed:[]});ExtMVC.model.plugin.validation.ValidatesExclusionOf.superclass.constructor.call(this,A,C,B);Ext.applyIf(this,{message:"must not be "+this.disallowed.toSentence("or")})},isValid:function(A){var D=this.getValue(A),C=true;for(var B=0;B<this.disallowed.length;B++){if(this.disallowed[B]==D){C=false}}return C}});ExtMVC.model.plugin.validation.ValidatesFormatOf=Ext.extend(ExtMVC.model.plugin.validation.AbstractValidation,{message:"is invalid",isValid:function(A){return this.regex.test(this.getValue(A))}});ExtMVC.model.plugin.validation.Errors=function(){this.all={}};ExtMVC.model.plugin.validation.Errors.prototype={forForm:function(){var A={};for(key in this.all){A[key]=this.forField(key,true)}return A},multipleErrorConnector:"and",clear:function(){this.all={}},add:function(B,A){this.all[B]=this.all[B]||[];this.all[B].push(A)},forField:function(C,B){B=B||false;var A=this.all[C]||[];return B?A.toSentence(this.multipleErrorConnector):A},isValid:function(A){for(key in this.all){return false}return true},readServerErrors:function(A,C){var A=A||{};if(C!==true){this.clearErrors()}if(typeof(A)=="string"){A=Ext.decode(A)}var D=A.errors;if(D){for(var B=0;B<D.length;B++){this.all.push(D[B])}}}};Ext.apply(Ext.data.Record.prototype,{isValid:function(){if(this.validations){if(!this.errors){this.errors=new ExtMVC.model.plugin.validations.Errors()}this.errors.clear();Ext.each(this.validations,function(A){if(!A.isValid(this)){this.errors.add(A.field,A.message)}},this)}return this.errors.isValid()}});(function(){var D=Ext.data.Record.prototype,A=Ext.data.Record,C={};for(var B in Ext.data.Record){C[B]=Ext.data.Record[B]}Ext.data.Record=function(E,F){A.apply(this,arguments);this.errors=new ExtMVC.model.plugin.validation.Errors()};for(var B in C){Ext.data.Record[B]=C[B]}})();ExtMVC.model.plugin.validation.Plugin={initialize:function(A){this.model=A;Ext.apply(A.prototype,{validations:this.parseValidations()})},parseValidations:function(){var C=[];for(var B in ExtMVC.model.plugin.validation){if(/^validate/.test(B.toLowerCase())){for(var D in this.model.prototype){if(D.toLowerCase()==B.toLowerCase()){var E=ExtMVC.model.plugin.validation[B],A=this.model.prototype[D];if(!Ext.isArray(A)){A=[A]}Ext.each(A,function(F){C.push(this.buildValidation(E,F))},this)}}}}return C},buildValidation:function(A,C){var D,B={};if(typeof C=="string"){D=C}else{D=C.field;delete C.field;B=C}return new A(this.model,D,B)}};ExtMVC.model.addPlugin(ExtMVC.model.plugin.validation.Plugin);ExtMVC.registerView("extmvc","formwindow",{xtype:"window",registerXType:"formwindow",modal:true,height:230,width:400,initComponent:function(){this.form=this.buildForm();Ext.apply(this,{items:[this.form],layout:"fit",closeAction:"hide",maskOnSave:true,saveMaskMessage:"Saving...",hasSaveButton:true,hasCancelButton:true});if(!Ext.isArray(this.buttons)){Ext.apply(this,{buttons:this.buildButtons()})}Ext.Window.prototype.initComponent.apply(this,arguments);this.initListeners()},initListeners:function(){if(this.controller){this.controller.on({scope:this,"create-failed":this.showErrorsFromInstance,"update-failed":this.showErrorsFromInstance})}},showErrorsFromInstance:function(A){this.form.getForm().markInvalid(A.errors.forForm())},buildButtons:function(){var A=[];if(this.hasSaveButton===true){A.push(this.buildSaveButton())}if(this.hasCancelButton===true){A.push(this.buildCancelButton())}return A},buildSaveButton:function(){return{text:"Save",iconCls:"save",scope:this,handler:this.onSave}},buildCancelButton:function(){return{text:"Cancel",scope:this,iconCls:"cancel",handler:this.onCancel}},buildForm:function(){return new Ext.form.FormPanel({})},loadRecord:function(A){this.instance=A;this.form.form.loadRecord(A)},onSave:function(){if(this.maskOnSave===true){this.el.mask(this.saveMaskMessage)}if(this.instance==undefined||this.instance.newRecord()){this.fireEvent("save",this.getFormValues(),this)}else{this.fireEvent("save",this.instance,this.getFormValues(),this)}},onCancel:function(){this.close()},getFormValues:function(){var B=this.form.getForm(),A={};B.items.each(function(D){var C=(typeof D.getSubmitValue=="function")?"getSubmitValue":"getValue";A[D.getName()]=D[C]()},this);return A}});ExtMVC.view.HasManyEditorGridPanel=Ext.extend(Ext.grid.EditorGridPanel,{initComponent:function(){Ext.applyIf(this,{autoScroll:true,store:this.association.findAll(),viewConfig:{forceFit:true}});if(this.hasTopToolbar){this.addTopToolbar()}ExtMVC.view.HasManyEditorGridPanel.superclass.initComponent.apply(this,arguments);this.on("afteredit",function(A){A.record.save({success:function(){A.record.commit()}})},this);this.getSelectionModel().on("selectionchange",function(A,B){if(this.deleteButton){this.deleteButton.enable()}},this)},hasTopToolbar:true,hasNewButton:true,hasDeleteButton:true,addTopToolbar:function(B){var A=[];if(this.hasNewButton){this.newButton=new Ext.Toolbar.Button({iconCls:"add",text:"Add",scope:this,handler:this.onAdd});A.push(this.newButton);A.push("-")}if(this.hasDeleteButton){this.deleteButton=new Ext.Toolbar.Button({text:"Remove selected",disabled:true,iconCls:"delete",scope:this,handler:this.onDelete});A.push(this.deleteButton)}Ext.applyIf(this,{tbar:A})},windowConfig:{},onAdd:function(A){if(!this.addWindow){this.addWindow=new Ext.Window(Ext.applyIf(this.windowConfig,{title:"New",layout:"fit",modal:true,height:300,width:400,items:[this.form],closeAction:"hide",buttons:[{text:"Save",iconCls:"save",scope:this,handler:this.onSaveNew},{text:"Cancel",iconCls:"cancel",scope:this,handler:this.onCancelNew}]}))}this.addWindow.show()},onDelete:function(B){var A=this.getSelectionModel().selection.record;if(A){A.destroy({scope:this,success:function(){this.store.reload()},failure:function(){Ext.Msg.alert("Delete failed","Something went wrong while trying to delete - please try again");this.store.reload()}})}this.deleteButton.disable()},onSaveNew:function(){this.association.create(this.form.getForm().getValues(),{scope:this,success:function(B,A){this.store.reload();this.addWindow.hide()},failure:function(B,A){this.form.getForm().clearInvalid();this.form.getForm().markInvalid(B.errors.forForm())}})},onCancelNew:function(A){this.addWindow.hide()}});Ext.reg("hasmany_editorgrid",ExtMVC.view.HasManyEditorGridPanel);ExtMVC.registerView("scaffold","form",{xtype:"form",registerXType:"scaffold_form",autoScroll:true,constructor:function(A){var A=A||{};this.model=A.model;if(this.model==undefined){throw new Ext.Error(String.format("No model supplied to scaffold Form {0}",A.title),A)}Ext.form.FormPanel.prototype.constructor.call(this,A)},initComponent:function(){Ext.applyIf(this,{items:this.buildItems(),monitorPoll:500,keys:[{key:Ext.EventObject.ESC,scope:this,handler:this.onCancel},{key:"s",ctrl:true,scope:this,stopEvent:true,handler:this.onSave}],hasSaveButton:true,hasCancelButton:true});if(!Ext.isArray(this.buttons)&&this.buttons!==false){Ext.apply(this,{buttons:this.buildButtons()})}Ext.form.FormPanel.prototype.initComponent.apply(this,arguments);this.initEvents();this.initListeners()},initListeners:function(){if(this.controller){this.controller.on({scope:this,"create-failed":this.showErrorsFromInstance,"update-failed":this.showErrorsFromInstance})}},showErrorsFromInstance:function(A){this.getForm().markInvalid(A.errors.forForm())},initEvents:function(){this.addEvents("save","cancel");if(this.monitorValid){this.startMonitoring()}},formItemConfig:{anchor:"-40",xtype:"textfield"},ignoreFields:["id","created_at","updated_at"],buildButtons:function(){var A=[];if(this.hasSaveButton===true){A.push(this.buildSaveButton())}if(this.hasCancelButton===true){A.push(this.buildCancelButton())}return A},buildSaveButton:function(){return{text:"Save",scope:this,iconCls:"save",handler:this.onSave,formBind:(this.monitorValid)?true:false}},buildCancelButton:function(){return{text:"Cancel",scope:this,iconCls:"cancel",handler:this.onCancel}},buildItems:function(){items=[];if(this.viewsPackage&&this.viewsPackage.FormFields){items=this.viewsPackage.FormFields}else{var B=this.model,D=B.prototype,A=D.fields;A.each(function(E){if(this.ignoreFields.indexOf(E.name)==-1){items.push(Ext.applyIf({name:E.name,fieldLabel:(E.name.replace(/_/g," ")).capitalize()}))}},this)}for(var C=0;C<items.length;C++){if(items[C].layout===undefined){Ext.applyIf(items[C],this.formItemConfig)}}return items},onSave:function(){this.fireEvent("save",this.getFormValues(),this)},getFormValues:function(){var B=this.getForm(),A={};B.items.each(function(D){var C=(typeof D.getSubmitValue=="function")?"getSubmitValue":"getValue";A[D.getName()]=D[C]()},this);return A},onCancel:function(){this.fireEvent("cancel",this.instance,this)}});ExtMVC.registerView("scaffold","edit",{xtype:"scaffold_form",registerXType:"scaffold_edit",initComponent:function(){Ext.applyIf(this,{title:"Edit "+this.model.prototype.singularHumanName});ExtMVC.getView("scaffold","form").prototype.initComponent.apply(this,arguments)},loadRecord:function(A){this.instance=A;this.getForm().loadRecord(A)},onSave:function(){this.fireEvent("save",this.instance,this.getFormValues(),this)}});ExtMVC.registerView("scaffold","index",{xtype:"grid",registerXType:"scaffold_grid",constructor:function(A){A=A||{};this.model=A.model;if(this.model==undefined){throw new Error("No model supplied to scaffold Index view")}this.controller=this.controller||A.controller;if(A.columns==undefined&&A.colModel==undefined&&A.cm==undefined){A.columns=this.buildColumns(this.model)}A.store=A.store||this.model.find();Ext.applyIf(A,{viewConfig:{forceFit:true},id:String.format("{0}_index",this.model.prototype.tableName),loadMask:true,dblClickToEdit:true});Ext.grid.GridPanel.prototype.constructor.call(this,A);this.initListeners()},initComponent:function(){var A=this.hasTopToolbar?this.buildTopToolbar():null;var B=this.hasBottomToolbar?this.buildBottomToolbar(this.store):null;Ext.applyIf(this,{title:this.getTitle(),tbar:A,bbar:B});Ext.grid.GridPanel.prototype.initComponent.apply(this,arguments)},initEvents:function(){this.addEvents("edit","new","delete");Ext.grid.GridPanel.prototype.initEvents.apply(this,arguments)},initListeners:function(){if(this.dblClickToEdit===true){this.on({scope:this,rowdblclick:this.onEdit})}if(this.controller!=undefined){this.controller.on("delete",this.refreshStore,this)}},destroy:function(){if(this.controller!=undefined){this.controller.un("delete",this.refreshStore,this)}Ext.grid.GridPanel.prototype.destroy.apply(this,arguments)},refreshStore:function(){var A=Ext.getCmp(this.id).store;A.reload()},getTitle:function(){return String.format("All {0}",this.model.prototype.pluralHumanName)},preferredColumns:["id","title","name","first_name","last_name","login","username","email","email_address","content","message","body"],ignoreColumns:["password","password_confirmation"],useColumns:undefined,narrowColumns:["id"],wideColumns:["message","content","description","bio","body"],narrowColumnWidth:30,normalColumnWidth:100,wideColumnWidth:200,hasTopToolbar:true,hasBottomToolbar:true,buildColumns:function(C){if(this.viewsPackage&&this.viewsPackage.GridColumns){var E=this.viewsPackage.GridColumns}else{var A=this.getFields(),E=[];wideColumns=[];Ext.each(A,function(F){if(this.preferredColumns.indexOf(F.name)>-1){E.push(this.buildColumn(F.name))}},this);Ext.each(A,function(F){if(this.preferredColumns.indexOf(F.name)==-1&&this.ignoreColumns.indexOf(F.name)==-1){E.push(this.buildColumn(F.name))}if(this.wideColumns.indexOf(F.name)){wideColumns.push(F.name)}},this);for(var D=E.length-1;D>=0;D--){var B=E[D];if(this.narrowColumns.indexOf(B.id)>-1){Ext.applyIf(B,{width:this.narrowColumnWidth})}else{if(this.wideColumns.indexOf(B.id)>-1){Ext.applyIf(B,{width:this.wideColumnWidth})}else{Ext.applyIf(B,{width:this.normalColumnWidth})}}}}return E},getFields:function(){if(this.useColumns===undefined){return this.model.prototype.fields.items}else{var A=[];Ext.each(this.useColumns,function(B){A.push({name:B})},this);return A}},buildColumn:function(A){var A=A||{};if(typeof(A)=="string"){A={name:A}}return Ext.applyIf(A,{id:A.name,header:A.name.replace(/_/g," ").titleize(),sortable:true,dataIndex:A.name})},hasAddButton:true,hasEditButton:true,hasDeleteButton:true,buildAddButton:function(A){return new Ext.Button(Ext.applyIf(A||{},{text:"New "+this.model.prototype.singularHumanName,scope:this,iconCls:"add",handler:this.onAdd}))},buildEditButton:function(A){return new Ext.Button(Ext.applyIf(A||{},{text:"Edit selected",scope:this,iconCls:"edit",disabled:true,handler:this.onEdit}))},buildDeleteButton:function(A){return new Ext.Button(Ext.applyIf(A||{},{text:"Delete selected",disabled:true,scope:this,iconCls:"delete",handler:this.onDelete}))},buildTopToolbar:function(){var A=[];if(this.hasAddButton===true){this.addButton=this.buildAddButton();A.push(this.addButton,"-")}if(this.hasEditButton===true){this.editButton=this.buildEditButton();A.push(this.editButton,"-")}if(this.hasDeleteButton===true){this.deleteButton=this.buildDeleteButton();A.push(this.deleteButton,"-")}if(this.hasSearchField===true){this.searchField=this.buildSearchField();A.push(this.searchField,"-")}this.getSelectionModel().on("selectionchange",function(B){if(B.getCount()>0){if(this.deleteButton!=undefined){this.deleteButton.enable()}if(this.editButton!=undefined){this.editButton.enable()}}else{if(this.deleteButton!=undefined){this.deleteButton.disable()}if(this.editButton!=undefined){this.editButton.disable()}}},this);return A},pageSize:25,buildBottomToolbar:function(A){return new Ext.PagingToolbar({store:A,displayInfo:true,pageSize:this.pageSize,emptyMsg:String.format("No {0} to display",this.model.prototype.pluralHumanName)})},hasSearchField:false,searchParamName:"q",buildSearchField:function(){this.searchField=new Ext.form.TwinTriggerField({width:200,validationEvent:false,validateOnBlur:false,hideTrigger1:true,onTrigger1Click:this.clearSearchField.createDelegate(this,[]),onTrigger2Click:this.onSearch.createDelegate(this,[]),trigger1Class:"x-form-clear-trigger",trigger2Class:"x-form-search-trigger"});this.searchField.on("specialkey",function(B,A){if(A.getKey()===A.ESC){this.clearSearchField()}A.stopEvent();if(A.getKey()===A.DEL){this.clearSearchField()}A.stopEvent();if(A.getKey()===A.ENTER){this.onSearch()}},this);return this.searchField},clearSearchField:function(){var A=this.searchField;A.el.dom.value="";A.triggers[0].hide();this.doSearch()},onSearch:function(){var B=this.searchField,A=B.getRawValue();if(A.length<1){this.clearSearchField()}else{B.triggers[0].show();this.doSearch(A)}},doSearch:function(A){A=A||this.searchField.getRawValue()||"";var B={start:0};this.store.baseParams=this.store.baseParams||{};this.store.baseParams[this.searchParamName]=A;this.store.reload({params:B})},onXAdd:function(){},onXDelete:function(){var A=this.getSelectionModel().getSelected();if(A){this.onDelete()}},onXEdit:function(){var A=this.getSelectionModel().getSelected();if(A){this.onEdit()}},onAdd:function(){this.fireEvent("new")},onEdit:function(B){var A=this.getSelectionModel().getSelected();if(A){this.fireEvent("edit",A)}},onDelete:function(){Ext.Msg.confirm("Are you sure?",String.format("Are you sure you want to delete this {0}? This cannot be undone.",this.model.prototype.modelName.humanize()),function(A){if(A=="yes"){var B=this.getSelectionModel().getSelected();if(B){this.fireEvent("delete",B)}}},this)}});ExtMVC.registerView("scaffold","new",{xtype:"scaffold_form",registerXType:"scaffold_new",initComponent:function(){Ext.applyIf(this,{title:"New "+this.model.prototype.singularHumanName});ExtMVC.getView("scaffold","form").prototype.initComponent.apply(this,arguments)}});ExtMVC.test.TestRunner=Ext.extend(Ext.util.Observable,{constructor:function(A){ExtMVC.test.TestRunner.superclass.constructor.apply(this,arguments);Ext.apply(this,{hasRecentFailures:false,fullRun:false});this.addEvents("starting","finished");this.tests=[]},onJSpecFinish:function(A){runner.fireEvent("finished",JSpec.stats);if(runner.fullRun==true){runner.hasRecentFailures=JSpec.stats.failures>0}},addTests:function(A){this.tests=this.tests.concat(A)},runTests:function(C){this.fullRun=!Ext.isArray(C);C=C||this.tests;delete JSpec;var B="../vendor/jspec/lib/jspec.js",D=function(){this.fireEvent("starting");JSpec.options.formatter=ExtMVC.test.JSpecFormatter;Ext.each(C,function(E){JSpec.exec(E)},this);JSpec.include({utilities:{runner:this},reporting:this.onJSpecFinish});JSpec.run({failuresOnly:false}).report()}.createDelegate(this);var A=document.createElement("script");A.type="text/javascript";A.src=B;if(A.readyState){A.onreadystatechange=function(){if(A.readyState=="loaded"||A.readyState=="complete"){A.onreadystatechange=null;D()}}}else{A.onload=D}document.getElementsByTagName("head")[0].appendChild(A)}});ExtMVC.test.JSpecFormatter=Ext.extend(Object,{constructor:function(B,A){this.suites=B.suites},getFailingSpecs:function(B){var B=B||this.suites;var A=[];Ext.each(B,function(C){A=A.concat(this.getFailuresForSuite(C));if(C.hasSuites()){A=A.concat(this.getFailingSpecs(C.suites))}},this);return A},getFailuresForSuite:function(B){if(B.ran&&B.passed()){return[]}else{var A=[];Ext.each(B.specs,function(C){if(!C.passed()){Ext.apply(C,{code:this.bodyContents(C.body)});A.push(C)}},this);return A}},bodyContents:function(A){return JSpec.escape(JSpec.contentsOf(A)).replace(/^ */gm,function(B){return(new Array(Math.round(B.length/3))).join(" ")}).replace("\n","<br/>")}});ExtMVC.test.TestClient=Ext.extend(Ext.util.Observable,{constructor:function(A){A=A||{};Ext.applyIf(A,{currentCallbackId:1,lastChangesReceived:new Date()});Ext.apply(this,A);ExtMVC.test.TestClient.superclass.constructor.apply(this,arguments);this.initEvents();this.initListeners();this.runner=new ExtMVC.test.TestRunner();this.runner.on("finished",this.postResults,this);this.loadTestFiles();Ext.TaskMgr.start({interval:1000,scope:this,run:function(){this.jsonpRequest("http://192.168.3.2:5000/changes",{since:Math.floor(this.lastChangesReceived.getTime()/1000)},this.onChangePoll)}})},initEvents:function(){this.addEvents("results-posted","changes-received")},initListeners:function(){this.on("changes-received",this.onChangesReceived,this)},loadTestFiles:function(){this.jsonpRequest("http://192.168.3.2:5000/all_test_files",{},function(A){this.runner.addTests(A.files);this.runner.runTests()})},postResults:function(A){this.jsonpRequest("http://192.168.3.2:5000/results",A,function(){this.fireEvent("results-posted",A);var B=this.runner;if(A.failures==0&&B.hasRecentFailures&&!B.fullRun){console.log("running full suite after failures")}})},onChangePoll:function(A){var B=A.files;if(Ext.isArray(B)&&B.length>0){this.fireEvent("changes-received",B)}},onChangesReceived:function(A){this.lastChangesReceived=new Date();this.runner.runTests(A)},jsonpRequest:function(B,F,G,D){D=D||this;var C=document.getElementsByTagName("head")[0];var E="stProxyCallback"+this.currentCallbackId;this.currentCallbackId+=1;window[E]=function(){G.apply(D,arguments)};var A=["callback="+E];Ext.iterate(F,function(H,I){A.push(String.format("{0}={1}",H,I))},this);B=String.format("{0}?{1}",B,A.join("&"));C.appendChild(this.buildScriptTag(B))},buildScriptTag:function(B,C){C=C||Ext.emptyFn;var A=document.createElement("script");A.type="text/javascript";A.src=B;if(A.readyState){A.onreadystatechange=function(){if(A.readyState=="loaded"||A.readyState=="complete"){A.onreadystatechange=null;C()}}}else{A.onload=C}return A}});ExtMVC.test.TestGrid=Ext.extend(Ext.grid.GridPanel,{initComponent:function(){var A=new Ext.ux.grid.RowExpander({tpl:new Ext.XTemplate('<tpl for="failingSpecs">','<div class="detail">','<tpl for="suite">',"<h2>Suite: {name}</h2>","</tpl>","Expectation: {description}",'<ul class="assertions">','<tpl for="assertions">',"<li>","{message}","</li>","</tpl>","</ul>",'<div class="code">',"{code}","</div>","</div>","</tpl>")});Ext.applyIf(this,{plugins:A,store:new Ext.data.JsonStore({data:[],fields:[{name:"passes",type:"int"},{name:"failures",type:"int"},{name:"time",type:"int"},{name:"total",type:"int",mapping:"specs"},{name:"failingSpecs"}]}),cm:new Ext.grid.ColumnModel({defaults:{sortable:false},columns:[A,{header:"Passes",dataIndex:"passes"},{header:"Failures",dataIndex:"failures"},{header:"Total",dataIndex:"total"},{header:"Time (ms)",dataIndex:"time"}]}),viewConfig:{forceFit:true,getRowClass:function(B,C){return B.get("failures")==0?"pass":"fail"}}});ExtMVC.test.TestGrid.superclass.initComponent.apply(this,arguments);this.getView().on("rowsinserted",function(C,F,D){var B=this.store.getAt(F);if(B.get("failures")>0){this.store.each(function(G,H){var I=C.getRow(H);I.rowIndex=H;A.collapseRow(I)});var E=C.getRow(F);E.rowIndex=F;A.expandRow(E);E.scrollIntoView(this.ownerCt)}},this)}});
/*
* Ext JS Library 3.0+
* Copyright(c) 2006-2009 Ext JS, LLC
* http://www.extjs.com/license
*/
Ext.ns("Ext.ux.grid");Ext.ux.grid.RowExpander=Ext.extend(Ext.util.Observable,{expandOnEnter:true,expandOnDblClick:true,header:"",width:20,sortable:false,fixed:true,menuDisabled:true,dataIndex:"",id:"expander",lazyRender:true,enableCaching:true,constructor:function(A){Ext.apply(this,A);this.addEvents({beforeexpand:true,expand:true,beforecollapse:true,collapse:true});Ext.ux.grid.RowExpander.superclass.constructor.call(this);if(this.tpl){if(typeof this.tpl=="string"){this.tpl=new Ext.Template(this.tpl)}this.tpl.compile()}this.state={};this.bodyContent={}},getRowClass:function(A,E,D,C){D.cols=D.cols-1;var B=this.bodyContent[A.id];if(!B&&!this.lazyRender){B=this.getBodyContent(A,E)}if(B){D.body=B}return this.state[A.id]?"x-grid3-row-expanded":"x-grid3-row-collapsed"},init:function(B){this.grid=B;var A=B.getView();A.getRowClass=A.getRowClass.createSequence(this.getRowClass,this);A.enableRowBody=true;B.on("render",this.onRender,this);B.on("destroy",this.onDestroy,this)},onRender:function(){var A=this.grid;var B=A.getView().mainBody;B.on("mousedown",this.onMouseDown,this,{delegate:".x-grid3-row-expander"});if(this.expandOnEnter){this.keyNav=new Ext.KeyNav(this.grid.getGridEl(),{enter:this.onEnter,scope:this})}if(this.expandOnDblClick){A.on("rowdblclick",this.onRowDblClick,this)}},onDestroy:function(){if(this.keyNav){this.keyNav.disable();delete this.keyNav}var A=this.grid.getView().mainBody;if(A){A.un("mousedown",this.onMouseDown,this)}},onRowDblClick:function(A,B,C){this.toggleRow(B)},onEnter:function(F){var E=this.grid;var G=E.getSelectionModel();var B=G.getSelections();for(var C=0,A=B.length;C<A;C++){var D=E.getStore().indexOf(B[C]);this.toggleRow(D)}},getBodyContent:function(A,B){if(!this.enableCaching){return this.tpl.apply(A.data)}var C=this.bodyContent[A.id];if(!C){C=this.tpl.apply(A.data);this.bodyContent[A.id]=C}return C},onMouseDown:function(B,A){B.stopEvent();var C=B.getTarget(".x-grid3-row");this.toggleRow(C)},renderer:function(B,C,A){C.cellAttr='rowspan="2"';return'<div class="x-grid3-row-expander"> </div>'},beforeExpand:function(B,A,C){if(this.fireEvent("beforeexpand",this,B,A,C)!==false){if(this.tpl&&this.lazyRender){A.innerHTML=this.getBodyContent(B,C)}return true}else{return false}},toggleRow:function(A){if(typeof A=="number"){A=this.grid.view.getRow(A)}this[Ext.fly(A).hasClass("x-grid3-row-collapsed")?"expandRow":"collapseRow"](A)},expandRow:function(C){if(typeof C=="number"){C=this.grid.view.getRow(C)}var B=this.grid.store.getAt(C.rowIndex);var A=Ext.DomQuery.selectNode("tr:nth(2) div.x-grid3-row-body",C);if(this.beforeExpand(B,A,C.rowIndex)){this.state[B.id]=true;Ext.fly(C).replaceClass("x-grid3-row-collapsed","x-grid3-row-expanded");this.fireEvent("expand",this,B,A,C.rowIndex)}},collapseRow:function(C){if(typeof C=="number"){C=this.grid.view.getRow(C)}var B=this.grid.store.getAt(C.rowIndex);var A=Ext.fly(C).child("tr:nth(1) div.x-grid3-row-body",true);if(this.fireEvent("beforecollapse",this,B,A,C.rowIndex)!==false){this.state[B.id]=false;Ext.fly(C).replaceClass("x-grid3-row-expanded","x-grid3-row-collapsed");this.fireEvent("collapse",this,B,A,C.rowIndex)}}});Ext.preg("rowexpander",Ext.ux.grid.RowExpander);Ext.grid.RowExpander=Ext.ux.grid.RowExpander;ExtMVC.test.TestViewport=Ext.extend(Ext.Viewport,{constructor:function(A){A=A||{};this.header=new Ext.Panel({html:"Ext MVC Application Test suite",region:"north"});this.statusText=new Ext.Toolbar.TextItem({text:"Ready"});this.rerunButton=new Ext.Button({text:"Rerun all tests",iconCls:"all",scope:this,handler:function(){this.client.runner.runTests()}});this.main=new ExtMVC.test.TestGrid({region:"center",tbar:[this.rerunButton],bbar:[this.statusText]});Ext.applyIf(A,{layout:"border",items:[this.header,this.main]});ExtMVC.test.TestViewport.superclass.constructor.call(this,A);this.initListeners()},initListeners:function(){if(this.client!=undefined){var A;this.client.runner.on({scope:this,starting:function(){A=new Date();this.statusText.setText("Running specs")},finished:function(B){Ext.apply(B,{time:new Date()-A,failingSpecs:new ExtMVC.test.JSpecFormatter(JSpec,JSpec.options).getFailingSpecs()});this.main.store.loadData([B],true);this.statusText.setText("Ready")}})}}});