diff --git a/build b/build index 25dac70..b519619 100644 --- a/build +++ b/build @@ -4,6 +4,7 @@ MVC.js App.js +lib/ClassManager.js lib/*.js overrides/*.js controller/*.js diff --git a/ext-mvc-all-min.js b/ext-mvc-all-min.js index c48092a..7c67018 100644 --- a/ext-mvc-all-min.js +++ b/ext-mvc-all-min.js @@ -1,4 +1,4 @@ -ExtMVC=Ext.extend(Ext.util.Observable,{version:"0.7a",constructor:function(){ExtMVC.superclass.constructor.apply(this,arguments);this.addEvents("environment-changed");this.getEnvSettings=this.getCurrentEnvironmentSettings},setApplication:function(A){this.app=A;this.name=A.name;ExtMVC.model.modelNamespace=window[A.name].models},controllers:{},registerController:function(A,B){this.controllers[A]=B},getController:function(A){var B=this.controllers[A];if(B){if(typeof B==="function"){this.controllers[A]=new this.controllers[A]()}return this.controllers[A]}else{return null}},currentEnvironment:"production",environments:{production:{}},setCurrentEnvironment:function(A){if(this.getEnvironmentSettings(A)){this.currentEnvironment=A;this.fireEvent("environment-changed",A,this.getEnvironmentSettings(A))}},getCurrentEnvironment:function(){return ExtMVC.currentEnvironment},getCurrentEnvironmentSettings:function(){return this.getEnvironmentSettings(this.getCurrentEnvironment())},addEnvironmentSettings:function(B,A){ExtMVC.environments[B]=ExtMVC.environments[B]||{};Ext.apply(ExtMVC.environments[B],A)},getEnvironmentSettings:function(A){A=A||ExtMVC.environment;return ExtMVC.environments[A]}});ExtMVC=new ExtMVC();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()},onReady:function(){if(this.fireEvent("before-launch",this)){this.initializeRouter();this.initializeEvents();if(this.usesHistory===true){this.initializeHistory()}this.launch();this.fireEvent("launched",this);if(this.usesHistory){if(this.dispatchHistoryOnLoad===true){Ext.History.init(function(B){var A=document.location.hash.replace("#","");var C=this.router.recognise(A);if(C){this.dispatch(C)}},this)}else{Ext.History.init()}}}},name:"MyApp",usesHistory:false,dispatchHistoryOnLoad:true,launch:Ext.emptyFn,params:{},dispatch:function(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(A){var A=A||this.name;if(A){Ext.ns(A,A+".controllers",A+".models",A+".views")}},initializeHistory:function(){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(B){var A=this.router.recognise(B);if(A){this.dispatch(A,null,[{url:B}])}},initializeEvents:function(){this.addEvents("before-launch","launched")}});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)&&G.scripts.length>0){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.overrides,function(J){B.push(String.format("{0}/{1}.js",G.overridesDir,J))},this);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.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:true,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;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)}}});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.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=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=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/g,">").replace(/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-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.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})},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.titleize()),function(A){if(A=="yes"){var B=this.getSelectionModel().getSelected();if(B){this.fireEvent("delete",B)}}},this)}});Ext.reg("scaffold_index",ExtMVC.view.scaffold.Index);ExtMVC.view.scaffold.New=Ext.extend(ExtMVC.view.scaffold.ScaffoldFormPanel,{initComponent:function(){Ext.applyIf(this,{title:"New "+this.model.prototype.singularHumanName});ExtMVC.view.scaffold.New.superclass.initComponent.apply(this,arguments)}});Ext.reg("scaffold_new",ExtMVC.view.scaffold.New);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","
")}});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.4.3: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.4.3:5000/all_test_files",{},function(A){this.runner.addTests(A.files);this.runner.runTests()})},postResults:function(A){this.jsonpRequest("http://192.168.4.3: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('','
','',"

Suite: {name}

","
","Expectation: {description}",'
    ','',"
  • ","{message}","
  • ","
    ","
",'
',"{code}","
","
","
")});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)}}); +ExtMVC=Ext.extend(Ext.util.Observable,{version:"0.7a",constructor:function(){ExtMVC.superclass.constructor.apply(this,arguments);this.addEvents("environment-changed");this.getEnvSettings=this.getCurrentEnvironmentSettings},setApplication:function(A){this.app=A;this.name=A.name;ExtMVC.model.modelNamespace=window[A.name].models},controllers:{},registerController:function(A,B){this.controllers[A]=B},getController:function(A){var B=this.controllers[A];if(B){if(typeof B==="function"){this.controllers[A]=new this.controllers[A]()}return this.controllers[A]}else{return null}},currentEnvironment:"production",environments:{production:{}},setCurrentEnvironment:function(A){if(this.getEnvironmentSettings(A)){this.currentEnvironment=A;this.fireEvent("environment-changed",A,this.getEnvironmentSettings(A))}},getCurrentEnvironment:function(){return ExtMVC.currentEnvironment},getCurrentEnvironmentSettings:function(){return this.getEnvironmentSettings(this.getCurrentEnvironment())},addEnvironmentSettings:function(B,A){ExtMVC.environments[B]=ExtMVC.environments[B]||{};Ext.apply(ExtMVC.environments[B],A)},getEnvironmentSettings:function(A){A=A||ExtMVC.environment;return ExtMVC.environments[A]}});ExtMVC=new ExtMVC();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()},onReady:function(){if(this.fireEvent("before-launch",this)){this.initializeRouter();this.initializeEvents();if(this.usesHistory===true){this.initializeHistory()}this.launch();this.fireEvent("launched",this);if(this.usesHistory){if(this.dispatchHistoryOnLoad===true){Ext.History.init(function(B){var A=document.location.hash.replace("#","");var C=this.router.recognise(A);if(C){this.dispatch(C)}},this)}else{Ext.History.init()}}}},name:"MyApp",usesHistory:false,dispatchHistoryOnLoad:true,launch:Ext.emptyFn,params:{},dispatch:function(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(A){var A=A||this.name;if(A){Ext.ns(A,A+".controllers",A+".models",A+".views")}},initializeHistory:function(){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(B){var A=this.router.recognise(B);if(A){this.dispatch(A,null,[{url:B}])}},initializeEvents:function(){this.addEvents("before-launch","launched")}});ExtMVC.lib.ClassManager=Ext.extend(Ext.util.Observable,{constructor:function(A){A=A||{};Ext.applyIf(A,{autoDefine:true,autoInstantiate:false,registeredClasses:{},constructors:{},instances:{}});Ext.apply(this,A);this.addEvents("class-registered","class-defined","class-instantiated");this.on({scope:this,"class-registered":this.afterRegister,"class-defined":this.afterDefine})},register:function(B,A){this.registeredClasses[B]=A;this.fireEvent("class-registered",B,A)},getRegistered:function(A){return this.registeredClasses[A]},define:function(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(A){return this.constructors[A]||this.define(A)},instantiate:function(C,B){var A=this.instances[C];if(A==undefined){A=new (this.getConstructor(C))(B);this.instances[C]=A;this.fireEvent("class-instantiated",C,A)}return A},getInstance:function(A){return this.instances[A]||this.instantiate(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)&&G.scripts.length>0){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.overrides,function(J){B.push(String.format("{0}/{1}.js",G.overridesDir,J))},this);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.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:true,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;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)}}});ExtMVC.lib.ControllerClassManager=Ext.extend(ExtMVC.lib.ClassManager,{autoInstantiate:true});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.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=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=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/g,">").replace(/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-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.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})},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.titleize()),function(A){if(A=="yes"){var B=this.getSelectionModel().getSelected();if(B){this.fireEvent("delete",B)}}},this)}});Ext.reg("scaffold_index",ExtMVC.view.scaffold.Index);ExtMVC.view.scaffold.New=Ext.extend(ExtMVC.view.scaffold.ScaffoldFormPanel,{initComponent:function(){Ext.applyIf(this,{title:"New "+this.model.prototype.singularHumanName});ExtMVC.view.scaffold.New.superclass.initComponent.apply(this,arguments)}});Ext.reg("scaffold_new",ExtMVC.view.scaffold.New);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","
")}});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.4.3: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.4.3:5000/all_test_files",{},function(A){this.runner.addTests(A.files);this.runner.runTests()})},postResults:function(A){this.jsonpRequest("http://192.168.4.3: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('','
','',"

Suite: {name}

","
","Expectation: {description}",'
    ','',"
  • ","{message}","
  • ","
    ","
",'
',"{code}","
","
","
")});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 diff --git a/ext-mvc-all.js b/ext-mvc-all.js index 73f4d9e..ac6bb7c 100644 --- a/ext-mvc-all.js +++ b/ext-mvc-all.js @@ -354,6 +354,429 @@ ExtMVC.App = Ext.extend(Ext.util.Observable, { } }); +ExtMVC.lib.ClassManager = Ext.extend(Ext.util.Observable, { + constructor: function(config) { + config = config || {}; + + Ext.applyIf(config, { + /** + * @property autoDefine + * @type Boolean + * If true, the ClassManager will attempt to define classes immediately via this.define (defaults to true) + */ + autoDefine: true, + + /** + * @property autoInstantiate + * @type Boolean + * If true, the ClassManager will attempt to instantiate classes immediately after they are defined (defaults to false) + */ + autoInstantiate: false, + + /** + * @property registeredClasses + * @type Object + * {name: config} mapping of all registered classes + */ + registeredClasses: {}, + + /** + * @property constructors + * @type Object + * {name: Function} mapping of all registered classes to their constructor functions + */ + constructors: {}, + + /** + * @property instances + * @type Object + * {name: instance} mapping of any classes which have been instantiated with this manager + * This is only really used for controllers, where there is only ever one instance at a time + */ + instances: {} + }); + + Ext.apply(this, config); + + this.addEvents( + /** + * @event class-registered + * Fires when a class has been registered to this package + * @param {String} name The name of the class + * @param {Object} config The class config object + */ + 'class-registered', + + /** + * @event class-defined + * Fires after a class has been registered and then defined using Ext.extend + * @param {String} name The name of the class + * @param {Function} constructor The class constructor + */ + 'class-defined', + + /** + * @event class-instantiated + * Fires when a class in this manager has been instantiated by the manager. This is mostly + * useful when using autoInstantiate, e.g. for classes for which there should only be one instance + * @param {String} name The name of the class that was instantiated + * @param {Object} instance The instance that was just created + */ + 'class-instantiated' + ); + + this.on({ + scope : this, + 'class-registered': this.afterRegister, + 'class-defined' : this.afterDefine + }); + }, + + /** + * Registers a config object or class constructor to a given class name + * @param {String} name The name to register this class under + * @param {Object/Function} config Either a config object or a constructor function + */ + register: function(name, config) { + this.registeredClasses[name] = config; + + this.fireEvent('class-registered', name, config); + }, + + /** + * Returns the config object for a given class name. Only really useful privately + * @param {String} name The name of the class + * @return {Object} The config object for this class + */ + getRegistered: function(name) { + return this.registeredClasses[name]; + }, + + /** + * Defines the given class name by using Ext.extend to declare it. The result of Ext.extend + * is then stored in this.constructors, and the constructor can then be retrieved with this.getConstructor(name) + * @param {String} name The name of the class to define + * @return {Function} The newly defined class constructor + */ + define: function(name) { + var overrides = this.getRegistered(name); + + //extend the parent object and register the constructor + var klass = Ext.extend(this.getConstructor(overrides.extend), overrides); + this.constructors[name] = klass; + + this.fireEvent('class-defined', name, klass); + + return klass; + }, + + /** + * Returns the constructor function for a registered class name. If the constructor + * itself hasn't been defined yet, it is defined first using this.define(), then returned + * @param {String} name The name of the class to return the constructor for + * @return {Function} The constructor function + */ + getConstructor: function(name) { + return this.constructors[name] || this.define(name); + }, + + /** + * Instantiates the given class name, with an optional config object (usually the config is not needed) + * + */ + instantiate: function(name, config) { + //get the controller instance that has already been created + var instance = this.instances[name]; + + //if the instance isn't defined yet, instantiate it now and cache it + if (instance == undefined) { + instance = new (this.getConstructor(name))(config); + this.instances[name] = instance; + + this.fireEvent('class-instantiated', name, instance); + } + + return instance; + }, + + /** + * Only really useful for controllers, this returns the canonical instance for a given + * class name (e.g. getInstance('funds') would return the Funds Controller, instaniating first if required) + * @param {String} name The name of the class to instantiate + * @return {Object} The canonical instance of this class + */ + getInstance: function(name) { + return this.instances[name] || this.instantiate(name); + } +}); +// +// Ext.apply(ExtMVC, { +// /** +// * Registers a model class with Ext MVC +// * @param {String} name The name to give this model +// * @param {Object} config Model definition configuration +// */ +// registerModel: function(name, config) { +// this.registerClass('model', arguments); +// }, +// +// /** +// * Registers a controller class with Ext MVC +// * @param {String} name The name to give this controller +// * @param {Object} config Controller definition configuration +// */ +// registerController: function(name, config) { +// this.registerClass('controller', arguments); +// }, +// +// /** +// * Registers a view class with Ext MVC. +// * @param {String} namesapce The namespace to add this view to +// * @param {String} name The name to give this view +// * @param {Object} config View definition configuration +// */ +// registerView: function(namespace, name, config) { +// this.registerClass('view', arguments); +// }, +// +// /** +// * Abstraction for registering views, models and controllers +// * @param {String} managerName The name of the class manager to register with +// * @param {Array} args The args to pass to the manager's register method +// */ +// registerClass: function(managerName, args) { +// var manager = this.getClassManager(managerName); +// +// manager.register.apply(manager, args); +// }, +// +// /** +// * @property classManagers +// * @type Object +// * {name: classManager} mappings used by this.getClassManager and this.registerClassManager +// */ +// classManagers: {}, +// +// /** +// * @private +// * Sets up model, view and controller class managers +// */ +// initializeClassManagers: function() { +// this.registerClassManager('model', new ExtMVC.lib.ModelClassManager()); +// this.registerClassManager('view', new ExtMVC.lib.ViewClassManager()); +// this.registerClassManager('controller', new ExtMVC.lib.ControllerClassManager()); +// }, +// +// /** +// * Returns the class manager for the given name +// * @param {String} name The name of the manager (model, view or controller) +// * @return {ExtMVC.lib.ClassManager} The class manager instance +// */ +// getClassManager: function(name) { +// return this.classManagers[name]; +// }, +// +// /** +// * Registers a class manager instance under a given name +// * @param {String} name The name of the class manager +// * @param {ExtMVC.lib.ClassManager} manager The ClassManager instance to register +// */ +// registerClassManager: function(name, manager) { +// this.classManagers[name] = manager; +// }, +// +// /** +// * Returns the canonical controller instance for the given controller name +// * @return {ExtMVC.Controller} The controller instance +// */ +// getController: function(name) { +// return this.controllerManager.getInstance(name); +// }, +// +// /** +// * Returns the constructor for a given model name +// * @param {String} name The name of the model +// * @return {Function} The model constructor +// */ +// getModel: function(name) { +// return this.getClassManager('model').getConstructor(name); +// }, +// +// /** +// * Instantiates a model of the given name with the data supplied +// * @param {String} modelName The name of the model to instantiate +// * @param {Object} data Data object to instantiate the instance with +// * @return {ExtMVC.Model} The new model instance +// */ +// buildModel: function(modelName, data) { +// return new (this.getModel(modelName))(data); +// }, +// +// /** +// * Returns the constructor for a given view namespace/name combination +// * @param {String} namespace The view namespace to look in +// * @param {String} name The name of the view within the view namespace +// * @return {Function} The view constructor +// */ +// getView: function(namespace) { +// return this.getClassManager('view').getConstructor(namespace, name); +// }, +// +// /** +// * Loads packaged classes from a given url, calling a callback when they have been registered. Sample return: +//
+//   {
+//     controllers: [
+//       {
+//         name: 'comments',
+//         superclass: 'crud',
+//         config: {
+//           index: function() {
+//             this.render('index', {
+//               title: "Loaded on demand!"
+//             });
+//           }
+//         }
+//       }
+//     ],
+//     views: [
+//       {
+//         name: 'new',
+//         namespace: 'comments',
+//         config: {
+//           xtype: 'scaffoldnew',
+//           title: "New Comment"
+//         }
+//       }
+//     ],
+//     models: [
+//       {
+//         name  : 'Comment',
+//         config: {
+//           fields: [
+//             {name: 'id',      type: 'int'},
+//             {name: 'title',   type: 'string'},
+//             {name: 'message', type: 'string'}
+//           ]
+//         }
+//       }
+//     ]
+//   }
+//   
+// * @param {String} url The url to retrieve the package from +// * @param {Function} callback Optional callback function, called after the package has been read and registered +// * @param {Object} scope The scope to execute the callback function in +// */ +// loadOnDemand: function(url, callback, scope) { +// Ext.Ajax.request({ +// url : url, +// scope : scope || this, +// success: function(response) { +// var pkg = Ext.decode(response.responseText); +// +// Ext.each(pkg.controllers || [], function(config) { +// this.registerController(config.name, config); +// }, this); +// +// Ext.each(pkg.models || [], function(config) { +// this.registerModel(config.name, config); +// }, this); +// +// Ext.each(pkg.views || [], function(config) { +// this.registerView(config.namespace, config.name, config); +// }, this); +// +// if (Ext.isFunction(callback)) callback.call(scope, pkg); +// } +// }); +// } +// }); + + +/** + * Ideal syntax after these changes: + */ + +// ExtMVC.registerView('index', 'index', { +// xtype: "panel", +// title: "Welcome to Ext MVC", +// html : "This is a test" +// }); +// +// Ext.registerController("index", { +// index: function() { +// this.render("index", { +// title: "Different Title" +// }); +// }, +// +// //this would actually be here by default +// welcome: function() { +// this.render("index"); +// }, +// +// //if we give the function a name, we can accept alternative render format: +// //all MVC Crud controller methods can be made like this +// search: function search() { +// this.render({ +// //options for new MyApp.views.index.search +// }); +// }, +// +// create: function(data) { +// var newUser = ExtMVC.buildModel("SuperUser", data); +// +// newUser.save({ +// success: function(user) { +// +// }, +// failure: function(user) { +// +// } +// }); +// +// //or how about +// ExtMVC.createModel("SuperUser", data, { +// success: function(user) { +// +// }, +// failure: function(user) { +// +// } +// }); +// }, +// +// update: function(user, changes) { +// user.update(changes, { +// success: function(user) { +// +// }, +// failure: function(user) { +// +// } +// }); +// } +// }); +// +// ExtMVC.registerController("someSubController", { +// extend: "index", +// +// index: function() { +// this.superclass.index.call(this); +// } +// }); +// +// +// ExtMVC.registerModel("SuperUser", { +// extend: "User", +// fields: [ +// {name: 'id', type: 'int'} +// ] +// }); + + + + /** * @class Array * Extensions to the array class @@ -770,6 +1193,15 @@ ExtMVC.lib.Booter = Ext.extend(Ext.util.Observable, { } }); +/** + * @class ExtMVC.lib.ControllerClassManager + * @extends ExtMVC.lib.ClassManager + * Customised class manager for managing Controllers + */ +ExtMVC.lib.ControllerClassManager = Ext.extend(ExtMVC.lib.ClassManager, { + autoInstantiate: true +}); + /** * @class ExtMVC.lib.Dependencies * @extends Ext.util.Observable @@ -998,6 +1430,18 @@ ExtMVC.Inflector = { } }; +/** + * @class ExtMVC.lib.ModelClassManager + * @extends ExtMVC.lib.ClassManager + * Specialised class manager for managing models + */ +ExtMVC.lib.ModelClassManager = Ext.extend(ExtMVC.lib.ClassManager, { + //usual model definition stuff to go here + define: function(name) { + + } +}); + /** * @class ExtMVC.router.Route * @extends Object @@ -1499,6 +1943,46 @@ String.prototype.toCurrency = function(symbol) { return afterDecimal ? String.format("{0}.{1}", beforeDecimal, afterDecimal) : beforeDecimal; }; +/** + * @class ExtMVC.lib.ViewClassManager + * @extends ExtMVC.lib.ClassManager + * Customised class manager for views, which take namespace as well as name + */ +ExtMVC.lib.ViewClassManager = Ext.extend(ExtMVC.lib.ClassManager, { + autoDefine: false, + + /** + * Register works slightly differently for views because we use a namespace too, + * so convert it here first + */ + register: function(namespace, name, config) { + var viewName = this.buildName(namespace, name); + + this.registeredClasses[viewName] = config; + }, + + getRegistered: function(namespace, name) { + return this.registeredClasses[this.buildName(namespace, name)]; + }, + + getConstructor: function(namespace, name) { + var viewName = this.buildName(namespace, name); + + ExtMVC.lib.ViewClassManager.superclass.getConstructor.call(this, viewName); + }, + + /** + * Because views are named by namespace and name, we need to turn these 2 names into 1 + * to be able to register them, which is what this function does + * @param {String} namespace The view namespace + * @param {String} name The view name + * @return {String} The composited view name (defaults to "{namespace}-{name}") + */ + buildName: function(namespace, name) { + return String.format("{0}-{1}", namespace, name); + } +}); + /** * An extension to Ext.extend which calls the extended object's onExtended function, if it exists * The only lines that are different from vanilla Ext.extend are the 2 before the return sb statement diff --git a/lib/ClassManager.js b/lib/ClassManager.js index f12fd39..62b63f6 100644 --- a/lib/ClassManager.js +++ b/lib/ClassManager.js @@ -1,4 +1,4 @@ -ExtMVC.ClassManager = Ext.extend(Ext.util.Observable, { +ExtMVC.lib.ClassManager = Ext.extend(Ext.util.Observable, { constructor: function(config) { config = config || {}; @@ -153,270 +153,270 @@ ExtMVC.ClassManager = Ext.extend(Ext.util.Observable, { return this.instances[name] || this.instantiate(name); } }); - -Ext.apply(ExtMVC, { - /** - * Registers a model class with Ext MVC - * @param {String} name The name to give this model - * @param {Object} config Model definition configuration - */ - registerModel: function(name, config) { - this.registerClass('model', arguments); - }, - - /** - * Registers a controller class with Ext MVC - * @param {String} name The name to give this controller - * @param {Object} config Controller definition configuration - */ - registerController: function(name, config) { - this.registerClass('controller', arguments); - }, - - /** - * Registers a view class with Ext MVC. - * @param {String} namesapce The namespace to add this view to - * @param {String} name The name to give this view - * @param {Object} config View definition configuration - */ - registerView: function(namespace, name, config) { - this.registerClass('view', arguments); - }, - - /** - * Abstraction for registering views, models and controllers - * @param {String} managerName The name of the class manager to register with - * @param {Array} args The args to pass to the manager's register method - */ - registerClass: function(managerName, args) { - var manager = this.getClassManager(managerName); - - manager.register.apply(manager, args); - }, - - /** - * @property classManagers - * @type Object - * {name: classManager} mappings used by this.getClassManager and this.registerClassManager - */ - classManagers: {}, - - /** - * @private - * Sets up model, view and controller class managers - */ - initializeClassManagers: function() { - this.registerClassManager('model', new ExtMVC.lib.ModelClassManager()); - this.registerClassManager('view', new ExtMVC.lib.ViewClassManager()); - this.registerClassManager('controller', new ExtMVC.lib.ControllerClassManager()); - }, - - /** - * Returns the class manager for the given name - * @param {String} name The name of the manager (model, view or controller) - * @return {ExtMVC.ClassManager} The class manager instance - */ - getClassManager: function(name) { - return this.classManagers[name]; - }, - - /** - * Registers a class manager instance under a given name - * @param {String} name The name of the class manager - * @param {ExtMVC.ClassManager} manager The ClassManager instance to register - */ - registerClassManager: function(name, manager) { - this.classManagers[name] = manager; - }, - - /** - * Returns the canonical controller instance for the given controller name - * @return {ExtMVC.Controller} The controller instance - */ - getController: function(name) { - return this.controllerManager.getInstance(name); - }, - - /** - * Returns the constructor for a given model name - * @param {String} name The name of the model - * @return {Function} The model constructor - */ - getModel: function(name) { - return this.getClassManager('model').getConstructor(name); - }, - - /** - * Instantiates a model of the given name with the data supplied - * @param {String} modelName The name of the model to instantiate - * @param {Object} data Data object to instantiate the instance with - * @return {ExtMVC.Model} The new model instance - */ - buildModel: function(modelName, data) { - return new (this.getModel(modelName))(data); - }, - - /** - * Returns the constructor for a given view namespace/name combination - * @param {String} namespace The view namespace to look in - * @param {String} name The name of the view within the view namespace - * @return {Function} The view constructor - */ - getView: function(namespace) { - return this.getClassManager('view').getConstructor(namespace, name); - }, - - /** - * Loads packaged classes from a given url, calling a callback when they have been registered. Sample return: -
-  {
-    controllers: [
-      {
-        name: 'comments',
-        superclass: 'crud',
-        config: {
-          index: function() {
-            this.render('index', {
-              title: "Loaded on demand!"
-            });
-          }
-        }
-      }
-    ],
-    views: [
-      {
-        name: 'new',
-        namespace: 'comments',
-        config: {
-          xtype: 'scaffoldnew',
-          title: "New Comment"
-        }
-      }
-    ],
-    models: [
-      {
-        name  : 'Comment',
-        config: {
-          fields: [
-            {name: 'id',      type: 'int'},
-            {name: 'title',   type: 'string'},
-            {name: 'message', type: 'string'}
-          ]
-        }
-      }
-    ]
-  }
-  
- * @param {String} url The url to retrieve the package from - * @param {Function} callback Optional callback function, called after the package has been read and registered - * @param {Object} scope The scope to execute the callback function in - */ - loadOnDemand: function(url, callback, scope) { - Ext.Ajax.request({ - url : url, - scope : scope || this, - success: function(response) { - var pkg = Ext.decode(response.responseText); - - Ext.each(pkg.controllers || [], function(config) { - this.registerController(config.name, config); - }, this); - - Ext.each(pkg.models || [], function(config) { - this.registerModel(config.name, config); - }, this); - - Ext.each(pkg.views || [], function(config) { - this.registerView(config.namespace, config.name, config); - }, this); - - if (Ext.isFunction(callback)) callback.call(scope, pkg); - } - }); - } -}); +// +// Ext.apply(ExtMVC, { +// /** +// * Registers a model class with Ext MVC +// * @param {String} name The name to give this model +// * @param {Object} config Model definition configuration +// */ +// registerModel: function(name, config) { +// this.registerClass('model', arguments); +// }, +// +// /** +// * Registers a controller class with Ext MVC +// * @param {String} name The name to give this controller +// * @param {Object} config Controller definition configuration +// */ +// registerController: function(name, config) { +// this.registerClass('controller', arguments); +// }, +// +// /** +// * Registers a view class with Ext MVC. +// * @param {String} namesapce The namespace to add this view to +// * @param {String} name The name to give this view +// * @param {Object} config View definition configuration +// */ +// registerView: function(namespace, name, config) { +// this.registerClass('view', arguments); +// }, +// +// /** +// * Abstraction for registering views, models and controllers +// * @param {String} managerName The name of the class manager to register with +// * @param {Array} args The args to pass to the manager's register method +// */ +// registerClass: function(managerName, args) { +// var manager = this.getClassManager(managerName); +// +// manager.register.apply(manager, args); +// }, +// +// /** +// * @property classManagers +// * @type Object +// * {name: classManager} mappings used by this.getClassManager and this.registerClassManager +// */ +// classManagers: {}, +// +// /** +// * @private +// * Sets up model, view and controller class managers +// */ +// initializeClassManagers: function() { +// this.registerClassManager('model', new ExtMVC.lib.ModelClassManager()); +// this.registerClassManager('view', new ExtMVC.lib.ViewClassManager()); +// this.registerClassManager('controller', new ExtMVC.lib.ControllerClassManager()); +// }, +// +// /** +// * Returns the class manager for the given name +// * @param {String} name The name of the manager (model, view or controller) +// * @return {ExtMVC.lib.ClassManager} The class manager instance +// */ +// getClassManager: function(name) { +// return this.classManagers[name]; +// }, +// +// /** +// * Registers a class manager instance under a given name +// * @param {String} name The name of the class manager +// * @param {ExtMVC.lib.ClassManager} manager The ClassManager instance to register +// */ +// registerClassManager: function(name, manager) { +// this.classManagers[name] = manager; +// }, +// +// /** +// * Returns the canonical controller instance for the given controller name +// * @return {ExtMVC.Controller} The controller instance +// */ +// getController: function(name) { +// return this.controllerManager.getInstance(name); +// }, +// +// /** +// * Returns the constructor for a given model name +// * @param {String} name The name of the model +// * @return {Function} The model constructor +// */ +// getModel: function(name) { +// return this.getClassManager('model').getConstructor(name); +// }, +// +// /** +// * Instantiates a model of the given name with the data supplied +// * @param {String} modelName The name of the model to instantiate +// * @param {Object} data Data object to instantiate the instance with +// * @return {ExtMVC.Model} The new model instance +// */ +// buildModel: function(modelName, data) { +// return new (this.getModel(modelName))(data); +// }, +// +// /** +// * Returns the constructor for a given view namespace/name combination +// * @param {String} namespace The view namespace to look in +// * @param {String} name The name of the view within the view namespace +// * @return {Function} The view constructor +// */ +// getView: function(namespace) { +// return this.getClassManager('view').getConstructor(namespace, name); +// }, +// +// /** +// * Loads packaged classes from a given url, calling a callback when they have been registered. Sample return: +//
+//   {
+//     controllers: [
+//       {
+//         name: 'comments',
+//         superclass: 'crud',
+//         config: {
+//           index: function() {
+//             this.render('index', {
+//               title: "Loaded on demand!"
+//             });
+//           }
+//         }
+//       }
+//     ],
+//     views: [
+//       {
+//         name: 'new',
+//         namespace: 'comments',
+//         config: {
+//           xtype: 'scaffoldnew',
+//           title: "New Comment"
+//         }
+//       }
+//     ],
+//     models: [
+//       {
+//         name  : 'Comment',
+//         config: {
+//           fields: [
+//             {name: 'id',      type: 'int'},
+//             {name: 'title',   type: 'string'},
+//             {name: 'message', type: 'string'}
+//           ]
+//         }
+//       }
+//     ]
+//   }
+//   
+// * @param {String} url The url to retrieve the package from +// * @param {Function} callback Optional callback function, called after the package has been read and registered +// * @param {Object} scope The scope to execute the callback function in +// */ +// loadOnDemand: function(url, callback, scope) { +// Ext.Ajax.request({ +// url : url, +// scope : scope || this, +// success: function(response) { +// var pkg = Ext.decode(response.responseText); +// +// Ext.each(pkg.controllers || [], function(config) { +// this.registerController(config.name, config); +// }, this); +// +// Ext.each(pkg.models || [], function(config) { +// this.registerModel(config.name, config); +// }, this); +// +// Ext.each(pkg.views || [], function(config) { +// this.registerView(config.namespace, config.name, config); +// }, this); +// +// if (Ext.isFunction(callback)) callback.call(scope, pkg); +// } +// }); +// } +// }); /** * Ideal syntax after these changes: */ -ExtMVC.registerView('index', 'index', { - xtype: "panel", - title: "Welcome to Ext MVC", - html : "This is a test" -}); - -Ext.registerController("index", { - index: function() { - this.render("index", { - title: "Different Title" - }); - }, - - //this would actually be here by default - welcome: function() { - this.render("index"); - }, - - //if we give the function a name, we can accept alternative render format: - //all MVC Crud controller methods can be made like this - search: function search() { - this.render({ - //options for new MyApp.views.index.search - }); - }, - - create: function(data) { - var newUser = ExtMVC.buildModel("SuperUser", data); - - newUser.save({ - success: function(user) { - - }, - failure: function(user) { - - } - }); - - //or how about - ExtMVC.createModel("SuperUser", data, { - success: function(user) { - - }, - failure: function(user) { - - } - }); - }, - - update: function(user, changes) { - user.update(changes, { - success: function(user) { - - }, - failure: function(user) { - - } - }); - } -}); - -ExtMVC.registerController("someSubController", { - extend: "index", - - index: function() { - this.superclass.index.call(this); - } -}); - - -ExtMVC.registerModel("SuperUser", { - extend: "User", - fields: [ - {name: 'id', type: 'int'} - ] -}); +// ExtMVC.registerView('index', 'index', { +// xtype: "panel", +// title: "Welcome to Ext MVC", +// html : "This is a test" +// }); +// +// Ext.registerController("index", { +// index: function() { +// this.render("index", { +// title: "Different Title" +// }); +// }, +// +// //this would actually be here by default +// welcome: function() { +// this.render("index"); +// }, +// +// //if we give the function a name, we can accept alternative render format: +// //all MVC Crud controller methods can be made like this +// search: function search() { +// this.render({ +// //options for new MyApp.views.index.search +// }); +// }, +// +// create: function(data) { +// var newUser = ExtMVC.buildModel("SuperUser", data); +// +// newUser.save({ +// success: function(user) { +// +// }, +// failure: function(user) { +// +// } +// }); +// +// //or how about +// ExtMVC.createModel("SuperUser", data, { +// success: function(user) { +// +// }, +// failure: function(user) { +// +// } +// }); +// }, +// +// update: function(user, changes) { +// user.update(changes, { +// success: function(user) { +// +// }, +// failure: function(user) { +// +// } +// }); +// } +// }); +// +// ExtMVC.registerController("someSubController", { +// extend: "index", +// +// index: function() { +// this.superclass.index.call(this); +// } +// }); +// +// +// ExtMVC.registerModel("SuperUser", { +// extend: "User", +// fields: [ +// {name: 'id', type: 'int'} +// ] +// });