<htmllang="en"><head><metacharset="utf-8"><title>TodoMVC</title><metaname="description"content="Helping you select an MV* framework - Todo apps for Backbone.js, Ember.js, AngularJS, Spine and many more"><metaname="viewport"content="width=device-width,initial-scale=1"><metaname="twitter:card"content="summary"><metaname="twitter:title"content="TodoMVC"><metaname="twitter:site"content="@TasteJS"><metaname="twitter:description"content="Helping you select an MV* framework - Todo apps for Backbone.js, Ember.js, AngularJS and many more"><metaname="twitter:image"content="https://raw.githubusercontent.com/tastejs/todomvc/gh-pages/site-assets/screenshot.png"><metaproperty="og:url"content="http://todomvc.com"><metaproperty="og:title"content="TodoMVC"><metaproperty="og:image"content="https://raw.github.com/tastejs/todomvc/gh-pages/site-assets/screenshot.png"><metaproperty="og:description"content="Helping you select an MV* framework - Todo apps for Backbone.js, Ember.js, AngularJS, Spine and many more"><linkrel="shortcut icon"href="site-assets/favicon.ico"><linkrel="stylesheet"href="site-assets/main.min.css"><script src="bower_components/platform/platform.js"></script><divhidden><style shim-shadowdom="">html/deep/[layout][horizontal],html/deep/[layout][vertical]{display:-ms-flexbox;display:-webkit-flex;display:flex}html/deep/[layout][horizontal][inline],html/deep/[layout][vertical][inline]{display:-ms-inline-flexbox;display:-webkit-inline-flex;display:inline-flex}html/deep/[layout][horizontal]{-ms-flex-direction:row;-webkit-flex-direction:row;flex-direction:row}html/deep/[layout][horizontal][reverse]{-ms-flex-direction:row-reverse;-webkit-flex-direction:row-reverse;flex-direction:row-reverse}html/deep/[layout][vertical]{-ms-flex-direction:column;-webkit-flex-direction:column;flex-direction:column}html/deep/[layout][vertical][reverse]{-ms-flex-direction:column-reverse;-webkit-flex-direction:column-reverse;flex-direction:column-reverse}html/deep/[layout][wrap]{-ms-flex-wrap:wrap;-webkit-flex-wrap:wrap;flex-wrap:wrap}html/deep/[layout][wrap-reverse]{-ms-flex-wrap:wrap-reverse;-webkit-flex-wrap:wrap-reverse;flex-wrap:wrap-reverse}html/deep/[flex]{-ms-flex:1;-webkit-flex:1;flex:1}html/deep/[flex][auto]{-ms-flex:11auto;-webkit-flex:11auto;flex:11auto}html/deep/[flex][none]{-ms-flex:none;-webkit-flex:none;flex:none}html/deep/[flex][one]{-ms-flex:1;-webkit-flex:1;flex:1}html/deep/[flex][two]{-ms-flex:2;-webkit-flex:2;flex:2}html/deep/[flex][three]{-ms-flex:3;-webkit-flex:3;flex:3}html/deep/[flex][four]{-ms-flex:4;-webkit-flex:4;flex:4}html/deep/[flex][five]{-ms-flex:5;-webkit-flex:5;flex:5}html/deep/[flex][six]{-ms-flex:6;-webkit-flex:6;flex:6}html/deep/[flex][seven]{-ms-flex:7;-webkit-flex:7;flex:7}html/deep/[flex][eight]{-ms-flex:8;-webkit-flex:8;flex:8}html/deep/[flex][nine]{-ms-flex:9;-webkit-flex:9;flex:9}html/deep/[flex][ten]{-ms-flex:10;-webkit-flex:10;flex:10}html/deep/[flex][eleven]{-ms-flex:11;-webkit-flex:11;flex:11}html/deep/[flex][twelve]{-ms-flex:12;-webkit-flex:12;flex:12}html/deep/[layout][start]{-ms-flex-align:start;-webkit-align-items:flex-start;align-items:flex-start}html/deep/[layout][center],html/deep/[layout][center-center]{-ms-flex-align:center;-webkit-align-items:center;align-items:center}html/deep/[layout][end]{-ms-flex-align:end;-webkit-align-items:flex-end;align-items:flex-end}html/deep/[layout][start-justified]{-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}html/deep/[layout][center-justified],html/deep/[layout][center-center]{-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center}html/deep/[layout][end-justified]{-ms-flex-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}html/deep/[layout][around-justified]{-ms-flex-pack:around;-webkit-justify-content:space-around;justify-content:space-around}html/deep/[layout][justified]{-ms-flex-pack:justify;-webkit-justify-content:space-between;justify-content:space-between}html/deep/[self-start]{-ms-align-self:flex-start;-webkit-align-self:flex-start;align-self:flex-start}html/deep/[self-center]{-ms-align-self:center;-webkit-align-self:center;align-self:center}html/deep/[self-end]{-ms-align-self:flex-end;-webkit-align-self:flex-end;align-self:flex-end}html/deep/[self-stretch]{-ms-align-self:stretch;-webkit-align-self:stretch;align-self:stretch}html/deep/[block]{display:block}html/deep/[hidden]{display:none!important}html/deep/[relative]{position:relative}html/deep/[fit]{position:absolute;top:0;right:0;bottom:0;left:0}body[fullbleed]{margin:0;height:100vh}html/deep/[segment],html/deep/segment{display:block;position:relative;-webkit-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;margin:1em.5em;padding:1em;background-color:#fff;-webkit-box-shadow:0001pxrgba(0,0,0,.1);box-shadow:0001pxrgba(0,0,0,.1);border-radius:5px5px5px5px}</style><script src="bower_components/polymer/polymer.js"></script><polymer-elementname="core-selection"attributes="multi"hiddenassetpath="bower_components/core-selection/"><script>Polymer("core-selection",{multi:false,ready:function(){this.clear()},clear:function(){this.selection=[]},getSelection:function(){returnthis.multi?this.selection:this.selection[0]},isSelected:function(item){returnthis.selection.indexOf(item)>=0},setItemSelected:function(item,isSelected){if(item!==undefined&&item!==null){if(isSelected){this.selection.push(item)}else{vari=this.selection.indexOf(item);if(i>=0){this.selection.splice(i,1)}}this.fire("core-select",{isSelected:isSelected,item:item})}},select:function(item){if(this.multi){this.toggle(item)}elseif(this.getSelection()!==item){this.setItemSelected(this.getSelection(),false);this.setItemSelected(item,true)}},toggle:function(item){this.setItemSelected(item,!this.isSelected(item))}});</script></polymer-element><polymer-elementname="core-selector"attributes="selected multi valueattr selectedClass selectedProperty selectedAttribute selectedItem selectedModel selectedIndex notap target itemsSelector activateEvent"assetpath="bower_components/core-selector/"><template><core-selectionid="selection"multi="{{multi}}"on-core-select="{{selectionSelect}}"></core-selection><contentid="items"select="*"></content></template><script>Polymer("core-selector",{selected:null,multi:false,valueattr:"name",selectedClass:"core-selected",selectedProperty:"",selectedAttribute:"active",selectedItem:null,selectedModel:null,selectedIndex:-1,target:null,itemsSelector:"",activateEvent:"tap",notap:false,ready:function(){this.activateListener=this.activateHandler.bind(this);this.observer=newMutationObserver(this.updateSelected.bind(this));if(!this.target){this.target=this}},getitems(){if(!this.target){return[]}varnodes=this.target!==this?this.itemsSelector?this.target.querySelectorAll(this.itemsSelector):this.target.children:this.$.items.getDistributedNodes();returnArray.prototype.filter.call(nodes||[],function(n){returnn&&n.localName!=="template"})},targetChanged:function(old){if(old){this.removeListener(old);this.observer.disconnect();this.clearSelection()}if(this.target){this.addListener(this.target);this.observer.observe(this.target,{childList:true});this.updateSelected()}},addListener:function(node){Polymer.addEventListener(node,this.activateEvent,this.activateListener)},removeListener:function(node){Polymer.removeEventListener(node,this.activateEvent,this.activateListener)},getselection(){returnthis.$.selection.getSelection()},selectedChanged:function(){this.updateSelected()},updateSelected:function(){this.validateSelected();if(this.multi){this.clearSelection();this.selected&&this.selected.forEach(function(s){this.valueToSelection(s)},this)}else{this.valueToSelection(this.selected)}},validateSelected:function(){if(this.multi&&!Array.isArray(this.selected)&&this.selected!==null&&this.selected!==undefined){this.selected=[this.selected]}},clearSelection:function(){if(this.multi){this.selection.slice().forEach(function(s){this.$.selection.setItemSelected(s,false)},this)}else{this.$.selection.setItemSelected(this.selection,false)}this.selectedItem=null;this.$.selection.clear()},valueToSelection:function(value){varitem=value===null||value===undefined?null:this.items[this.valueToIndex(value)];this.$.selection.select(item)},updateSelectedItem:function(){this.selectedItem=this.selection},selectedItemChanged:function(){if(this.selectedItem){vart=this.selectedItem.templateInstance;this.selectedModel=t?t.model:undefined}else{this.selectedModel=null}this.selectedIndex=this.selectedItem?parseInt(this.valueToIndex(this.selected)):-1},valueToIndex:function(value){for(vari=0,items=this.items,c;c=items[i];i++){if(this.valueForNode(c)==value){returni}}returnvalue},valueForNode:function(node){returnnode[this.valueattr]||node.getAttribute(this.valueattr)},selectionSelect:function(e,detail){this.updateSelectedItem();if(detail.item){this.applySelection(detail.item,detail.isSelected)}},applySelection:function(item,isSelected){if(this.selectedClass){item.classList.toggle(this.selectedClass,isSelected)}if(this.selectedProperty){item[this.selectedProperty]=isSelected}if(this.selectedAttribute&&item.setAttribute){if(isSelected){item.setAttribute(this.selectedAttribute,"")}else{item.removeAttribute(this.selectedAttribute)}}},activateHandler:function(e){if(!this.notap){vari=this.findDistributedTarget(e.target,this.items);if(i>=0){varitem=this.items[i];vars=this.valueForNode(item)||i;if(this.multi){if(this.selected){this.addRemoveSelected(s)}else{this.selected=[s]}}else{this.selected=s}this.asyncFire("core-activate",{item:item})}}},addRemoveSelected:function(value){vari=this.selected.indexOf(value);if(i>=0){this.selected.splice(i,1)}else{this.selected.push(value)}this.valueToSelection(value)},findDistributedTarget:function(target,nodes){while(target&&target!=this){vari=Array.prototype.indexOf.call(nodes,target);if(i>=0){returni}target=target.parentNode}}});</script></polymer-element><polymer-elementname="paper-ripple"attributes="initialOpacity opacityDecayVelocity"assetpath="bower_components/paper-ripple/"><template><style>:host{display:block;position:relative}#canvas{pointer-events:none;position:absolute;top:0;left:0;width:100%;height:100%}:host(.circle)#canvas{border-radius:50%}</style></template><script>(function(){varwaveMaxRadius=150;functionwaveRadiusFn(touchDownMs,touchUpMs,anim){vartouchDown=touchDownMs/1e3;vartouchUp=touchUpMs/1e3;vartotalElapsed=touchDown+touchUp;varww=anim.width,hh=anim.height;varwaveRadius=Math.min(Math.sqrt(ww*ww+hh*hh),waveMaxRadius)*1.1+5;varduration=1.1-.2*(waveRadius/waveMaxRadius);vartt=totalElapsed/duration;varsize=waveRadius*(1-Math.pow(80,-tt));returnMath.abs(size)}functionwaveOpacityFn(td,tu,anim){vartouchDown=td/1e3;vartouchUp=tu/1e3;vartotalElapsed=touchDown+touchUp;if(tu<=0){returnanim.initialOpacity}returnMath.max(0,anim.initialOpacity-touchUp*anim.opacityDecayVelocity)}functionwaveOuterOpacityFn(td,tu,anim){vartouchDown=td/1e3;vartouchUp=tu/1e3;varouterOpacity=touchDown*.3;varwaveOpacity=waveOpacityFn(td,tu,anim);returnMath.max(0,Math.min(outerOpacity,waveOpacity))}functionwaveDidFinish(wave,radius,anim){varwaveOpacity=waveOpacityFn(wave.tDown,wave.tUp,anim);if(waveOpacity<.01&&radius>=Math.min(wave.maxRadius,waveMaxRadius)){returntrue}returnfalse}functionwaveAtMaximum(wave,radius,anim){varwaveOpacity=waveOpacityFn(wave.tDown,wave.tUp,anim);if(waveOpacity>=anim.initialOpacity&&radius>=Math.min(wave.maxRadius,waveMaxRadius)){returntrue}returnfalse}functiondrawRipple(ctx,x,y,radius,innerColor,outerColor){if(outerColor){ctx.fillStyle=outerColor;ctx.fillRect(0,0,ctx.canvas.width,ctx.canvas.height)}ctx.beginPath();ctx.arc(x,y,radius,0,2*Math.PI,false);ctx.fillStyle=innerColor;ctx.fill()}functioncreateWave(elem){varelementStyle=window.getComputedStyle(elem);varfgColor=elementStyle.color;varwave={waveColor:fgColor,maxRadius:0,isMouseDown:false,mouseDownStart:0,mouseUpStart:0,tDown:0,tUp:0};returnwave}functionremoveWaveFromScope(scope,wave){if(scope.waves){varpos=scope.waves.indexOf(wave);scope.waves.splice(pos,1)}}varpow=Math.pow;varnow=Date.now;if(window.performance&&performance.now){now=performance.now.bind(performance)}functioncssColorWithAlpha(cssColor,alpha){varparts=cssColor.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);if(typeofalpha=="undefined"){alpha=1}if(!parts){return"rgba(255, 255, 255, "+alpha+")"}return"rgba("+parts[1]+", "+parts[2]+", "+parts[3]+", "+alpha+")"}functiondist(p1,p2){returnMath.sqrt(pow(p1.x-p2.x,2)+pow(p1.y-p2.y,2))}functiondistanceFromPointToFurthestCorner(point,size){vartl_d=dist(point,{x:0,y:0});vartr_d=dist(point,{x:size.w,y:0});varbl_d=dist(point,{x:0,y:size.h});varbr_d=dist(point,{x:size.w,y:size.h});returnMath.max(tl_d,tr_d,bl_d,br_d)}Polymer("paper-ripple",{initialOpacity:.25,opacityDecayVelocity:.8,backgroundFill:true,pixelDensity:2,eventDelegates:{down:"downAction",up:"upAction"},attached:function(){if(!this.$.canvas){varcanvas=document.createElement("canvas");canvas.id="canvas";this.shadowRoot.appendChild(canvas);this.$.canvas=canvas}},ready:function(){this.waves=[]},setupCanvas:function(){this.$.canvas.setAttribute("width",this.$.canvas.clientWidth*this.pixelDensity+"px");this.$.canvas.setAttribute("height",this.$.canvas.clientHeight*this.pixelDensity+"px");varctx=this.$.canvas.getContext("2d");ctx.scale(this.pixelDensity,this.pixelDensity);if(!this._loop){this._loop=this.animate.bind(this,ctx)}},downAction:function(e){this.setupCanvas();varwave=createWave(this.$.canvas);this.cancelled=false;wave.isMouseDown=true;wave.tDown=0;wave.tUp=0;wave.mouseUpStart=0;wave.mouseDownStart=now();varwidth=this.$.canvas.width/2;varheight=this.$.canvas.height/2;varrect=this.getBoundingClientRect();vartouchX=e.x-rect.left;vartouchY=e.y-rect.top;wave.startPosition={x:touchX,y:touchY};if(this.classList.contains("recenteringTouch")){wave.endPosition={x:width/2,y:height/2};wave.slideDistance=dist(wave.startPosition,wave.endPosition)}wave.containerSize=Math.max(width,height);wave.maxRadius=distanceFromPointToFurthestCorner(wave.startPosition,{w:width,h:height});this.waves.push(wave);requestAnimationFrame(this._loop)},upAction:function(){for(vari=0;i<this.waves.length;i++){varwave=this.waves[i];if(wave.isMouseDown){wave.isMouseDown=false;wave.mouseUpStart=now();wave.mouseDownStart=0;wave.tUp=0;break}}this._loop&&requestAnimationFrame(this._loop)},cancel:function(){this.cancelled=true},animate:function(ctx){varshouldRenderNextFrame=false;ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);vardeleteTheseWaves=[];varlongestTouchDownDuration=0;varlongestTouchUpDuration=0;varlastWaveColor=null;varanim={initialOpacity:this.initialOpacity,opacityDecayVelocity:this.opacityDecayVelocity,height:ctx.canvas.height,width:ctx.canvas.width};for(vari=0;i<this.waves.length;i++){varwave=this.waves[i];if(wave.mouseDownStart>0){wave.tDown=now()-wave.mouseDownStart}if(wave.mouseUpStart>0){wave.tUp=now()-wave.mouseUpStart}vartUp=wave.tUp;vartDown=wave.tDown;longestTouchDownDuration=Math.max(longestTouchDownDuration,tDown);longestTouchUpDuration=Math.max(longestTouchUpDuration,tUp);varradius=waveRadiusFn(tDown,tUp,anim);varwaveAlpha=waveOpacityFn(tDown,tUp,anim);varwaveColor=cssColorWithAlpha(wave.waveColor,waveAlpha);lastWaveColor=wave.waveColor;varx=wave.startPosition.x;vary=wave.startPosition.y;if(wave.endPosition){vartranslateFraction=Math.min(1,radius/wave.containerSize*2/Math.sqrt(2));x+=translateFraction*(wave.endPosition.x-wave.startPosition.x);y+=translateFraction*(wave.endPosition.y-wave.startPosition.y)}varbgFillColor=null;if(this.backgroundFill){varbgFillAlpha=waveOuterOpacityFn(tDown,tUp,anim);bgFillColor=cssColorWithAlpha(wave.waveColor,bgFillAlpha)}drawRipple(ctx,x,y,radius,waveColor,bgFillColor);varmaximumWave=waveAtMaximum(wave,radius,anim);varwaveDissipated=waveDidFinish(wave,radius,anim);varshouldKeepWave=!waveDissipated||maximumWave;varshouldRenderWaveAgain=!waveDissipated&&!maximumWave;shouldRenderNextFrame=shouldRenderNextFrame||shouldRenderWaveAgain;if(!shouldKeepWave||this.cancelled){deleteTheseWaves.push(wave)}}if(shouldRenderNextFrame){requestAnimationFrame(this._loop)}for(vari=0;i<deleteTheseWaves.length;++i){varwave=deleteTheseWaves[i];removeWaveFromScope(this,wave)}if(!this.waves.length){ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);this._loop=null}}})})();</script></polymer-element><polymer-elementname="paper-tab"attributes="noink"role="tab"assetpath="bower_components/paper-tabs/"><template><style>:host{display:block;position:relative;overflow:hidden}#tabContainer{position:absolute;top:0;right:0;bottom:0;left:0}.tab-content{transition:opacity.1scubic-bezier(0.4,0,1,1),color.1scubic-bezier(0.4,0,1,1);cursor:default;pointer-events:none}:host(:not(.core-selected)).tab-content{opacity:.6}#ink{position:absolute;top:0;right:0;bottom:0;left:0;color:#ffff8d}:host[noink]#ink{pointer-events:none}:host-context(paper-tabs[noink])#ink{pointer-events:none}</style><divid="tabContainer"center-justified=""center=""horizontal=""layout=""><divclass="tab-content"><content></content></div><paper-rippleid="ink"initialopacity="0.95"opacitydecayvelocity="0.98"></paper-ripple></div></template><script>Polymer("paper-tab",{noink:false});</script></polymer-element><polymer-elementname="paper-tabs"extends="core-selector"attributes="noink nobar"role="tablist"assetpath="bower_components/paper-tabs/"><template><style>:host{display:block;position:relative;font-size:14px;font-weight:500;height:48px;overflow:hidden}#tabsContainer{position:absolute;top:0;right:0;bottom:0;left:0;white-space:nowrap}#selectionBar{position:absolute;height:2px;bottom:0;left:0;width:0;background-color:#ffff8d;transition:width,left}#selectionBar[hidden]{display:hidden}#selectionBar.expand{transition-duration:.15s;transition-timing-function:cubic-bezier(0.4,0,1,1)}#selectionBar.contract{transition-duration:.1s;transition-timing-function:cubic-bezier(0,0,.2,1)}polyfill-next-selector{content:'#tabsContainer > *:not(#selectionBar)'}::content>*{-ms-flex:1;-webkit-flex:1;flex:1}</style><divid="tabsContainer"horizontal=""layout=""><shadow></shadow><divid="selectionBar"hidden?="{{nobar}}"on-transitionend="{{barTransitionEnd}}"></div></div></template><script>Polymer("paper-tabs",{noink:false,nobar:false,activateEvent:"down",nostretch:false,selectedIndexChanged:function(old){vars=this.$.selectionBar.style;if(!this.selectedItem){s.width=0;s.left=0;return}varw=100/this.items.length;if(this.nostretch||old===null||old===-1){s.width=w+"%";s.left=this.selectedIndex*w+"%";return}varm=5;this.$.selectionBar.classList.add("expand");if(old<this.selectedIndex){s.width=w+w*(this.selectedIndex-old)-m+"%"}else{s.width=w+w*(old-this.selectedIndex)-m+"%";s.left=this.selectedIndex*w+m+"%"}},barTransitionEnd:function(){varcl=this.$.selectionBar.classList;if(cl.contains("expand")){cl.remove("expand");cl.add("contract");vars=this.$.selectionBar.style;varw=100/this.items.length;s.width=w+"%";s.left=this.selectedIndex*w+"%"}elseif(cl.contains("contract")){cl.remove("contract")}}});</script></polymer-element></div></head><body><divclass="container"><headerclass="row"><divclass="col-md-8"><imgclass="logo"src="site-assets/logo.svg"width="500"height="86"alt="TodoMVC"><p>Helping you <strong>select</strong> an MV* framework</p><nav><ahref="https://github.com/tastejs/todomvc/zipball/1.3.0"class="zocial red">Download (1.3)</a><ahref="https://github.com/tastejs/todomvc"class="zocial ltgray">View on GitHub</a><ahref="http://blog.tastejs.com/"class="zocial ltgray">Blog</a></nav></div><divclass="col-md-4"><imgclass="logo-icon"src="site-assets/logo-icon.png"width="330"height="330"alt="TodoMVC"></div></header><divclass="row"><divclass="col-md-4"><h2>Introduction</h2><p>Developers these days are spoiled with choice when it comes to <ahref="http://coding.smashingmagazine.com/2012/07/27/journey-through-the-javascript-mvc-jungle/">selecting</a> an <strong>MV* framework</strong> for structuring and organizing their JavaScript web apps.</p><p>Backbone, Ember, AngularJS... the list of new and stable solutions continues to grow, but just how do you decide on which to use in a sea of so many options?</p><p>To help solve this problem, we created <ahref="https://github.com/tastejs/todomvc">TodoMVC</a> - a project which offers the same Todo application implemented using MV* concepts in most of the popular JavaScript MV* frameworks of today.</p><ahref="https://twitter.com/tastejs"class="twitter-follow-button"data-show-count="false"data-show-screen-name="false"></a><ahref="https://twitter.com/share"class="twitter-share-button"data-via="tastejs"data-url="http://todomvc.com"data-text="TodoMVC - Helping you select an MV* framework - Todo apps for Backbone.js, Ember.js, AngularJS, and more"></a><divclass="g-plusone"data-size="medium"data-annotation="none"data-href="http://todomvc.com"></div></div><divclass="col-md-8"><style shim-shadowdom="">paper-tabs,core-toolbar{color:#353535;background-color:#f4f4f4;font-family:'Helvetica Neue',Helvetica,Arial;box-shadow:03px2pxrgba(0,0,0,.2)}paper-tabs::shadow#selectionBar{background-color:#b12d2b}paper-tab::shadowpaper-ripple#ink{color:#b12d2b}</style><paper-tabsselected="js"class="js-app-tabs"><paper-tabname="js">JavaScript</paper-tab><paper-tabname="ctojs">Compile-to-JS</paper-tab><paper-tabname="labs">Labs</paper-tab></paper-tabs><divclass="app-lists"><divclass="js-app-list"data-app-list="js"><pclass="applist-intro">
<htmllang="en"><head><metacharset="utf-8"><title>TodoMVC</title><metaname="description"content="Helping you select an MV* framework - Todo apps for Backbone.js, Ember.js, AngularJS, Spine and many more"><metaname="viewport"content="width=device-width,initial-scale=1"><metaname="twitter:card"content="summary"><metaname="twitter:title"content="TodoMVC"><metaname="twitter:site"content="@TasteJS"><metaname="twitter:description"content="Helping you select an MV* framework - Todo apps for Backbone.js, Ember.js, AngularJS and many more"><metaname="twitter:image"content="https://raw.githubusercontent.com/tastejs/todomvc/gh-pages/site-assets/screenshot.png"><metaproperty="og:url"content="http://todomvc.com"><metaproperty="og:title"content="TodoMVC"><metaproperty="og:image"content="https://raw.github.com/tastejs/todomvc/gh-pages/site-assets/screenshot.png"><metaproperty="og:description"content="Helping you select an MV* framework - Todo apps for Backbone.js, Ember.js, AngularJS, Spine and many more"><linkrel="shortcut icon"href="site-assets/favicon.ico"><linkrel="stylesheet"href="site-assets/main.min.css"><script src="bower_components/platform/platform.js"></script><divhidden><style shim-shadowdom="">html/deep/[layout][horizontal],html/deep/[layout][vertical]{display:-ms-flexbox;display:-webkit-flex;display:flex}html/deep/[layout][horizontal][inline],html/deep/[layout][vertical][inline]{display:-ms-inline-flexbox;display:-webkit-inline-flex;display:inline-flex}html/deep/[layout][horizontal]{-ms-flex-direction:row;-webkit-flex-direction:row;flex-direction:row}html/deep/[layout][horizontal][reverse]{-ms-flex-direction:row-reverse;-webkit-flex-direction:row-reverse;flex-direction:row-reverse}html/deep/[layout][vertical]{-ms-flex-direction:column;-webkit-flex-direction:column;flex-direction:column}html/deep/[layout][vertical][reverse]{-ms-flex-direction:column-reverse;-webkit-flex-direction:column-reverse;flex-direction:column-reverse}html/deep/[layout][wrap]{-ms-flex-wrap:wrap;-webkit-flex-wrap:wrap;flex-wrap:wrap}html/deep/[layout][wrap-reverse]{-ms-flex-wrap:wrap-reverse;-webkit-flex-wrap:wrap-reverse;flex-wrap:wrap-reverse}html/deep/[flex]{-ms-flex:1;-webkit-flex:1;flex:1}html/deep/[flex][auto]{-ms-flex:11auto;-webkit-flex:11auto;flex:11auto}html/deep/[flex][none]{-ms-flex:none;-webkit-flex:none;flex:none}html/deep/[flex][one]{-ms-flex:1;-webkit-flex:1;flex:1}html/deep/[flex][two]{-ms-flex:2;-webkit-flex:2;flex:2}html/deep/[flex][three]{-ms-flex:3;-webkit-flex:3;flex:3}html/deep/[flex][four]{-ms-flex:4;-webkit-flex:4;flex:4}html/deep/[flex][five]{-ms-flex:5;-webkit-flex:5;flex:5}html/deep/[flex][six]{-ms-flex:6;-webkit-flex:6;flex:6}html/deep/[flex][seven]{-ms-flex:7;-webkit-flex:7;flex:7}html/deep/[flex][eight]{-ms-flex:8;-webkit-flex:8;flex:8}html/deep/[flex][nine]{-ms-flex:9;-webkit-flex:9;flex:9}html/deep/[flex][ten]{-ms-flex:10;-webkit-flex:10;flex:10}html/deep/[flex][eleven]{-ms-flex:11;-webkit-flex:11;flex:11}html/deep/[flex][twelve]{-ms-flex:12;-webkit-flex:12;flex:12}html/deep/[layout][start]{-ms-flex-align:start;-webkit-align-items:flex-start;align-items:flex-start}html/deep/[layout][center],html/deep/[layout][center-center]{-ms-flex-align:center;-webkit-align-items:center;align-items:center}html/deep/[layout][end]{-ms-flex-align:end;-webkit-align-items:flex-end;align-items:flex-end}html/deep/[layout][start-justified]{-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}html/deep/[layout][center-justified],html/deep/[layout][center-center]{-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center}html/deep/[layout][end-justified]{-ms-flex-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}html/deep/[layout][around-justified]{-ms-flex-pack:around;-webkit-justify-content:space-around;justify-content:space-around}html/deep/[layout][justified]{-ms-flex-pack:justify;-webkit-justify-content:space-between;justify-content:space-between}html/deep/[self-start]{-ms-align-self:flex-start;-webkit-align-self:flex-start;align-self:flex-start}html/deep/[self-center]{-ms-align-self:center;-webkit-align-self:center;align-self:center}html/deep/[self-end]{-ms-align-self:flex-end;-webkit-align-self:flex-end;align-self:flex-end}html/deep/[self-stretch]{-ms-align-self:stretch;-webkit-align-self:stretch;align-self:stretch}html/deep/[block]{display:block}html/deep/[hidden]{display:none!important}html/deep/[relative]{position:relative}html/deep/[fit]{position:absolute;top:0;right:0;bottom:0;left:0}body[fullbleed]{margin:0;height:100vh}html/deep/[segment],html/deep/segment{display:block;position:relative;-webkit-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;margin:1em.5em;padding:1em;background-color:#fff;-webkit-box-shadow:0001pxrgba(0,0,0,.1);box-shadow:0001pxrgba(0,0,0,.1);border-radius:5px5px5px5px}</style><script src="bower_components/polymer/polymer.js"></script><polymer-elementname="core-selection"attributes="multi"hiddenassetpath="bower_components/core-selection/"><script>Polymer("core-selection",{multi:false,ready:function(){this.clear()},clear:function(){this.selection=[]},getSelection:function(){returnthis.multi?this.selection:this.selection[0]},isSelected:function(item){returnthis.selection.indexOf(item)>=0},setItemSelected:function(item,isSelected){if(item!==undefined&&item!==null){if(isSelected){this.selection.push(item)}else{vari=this.selection.indexOf(item);if(i>=0){this.selection.splice(i,1)}}this.fire("core-select",{isSelected:isSelected,item:item})}},select:function(item){if(this.multi){this.toggle(item)}elseif(this.getSelection()!==item){this.setItemSelected(this.getSelection(),false);this.setItemSelected(item,true)}},toggle:function(item){this.setItemSelected(item,!this.isSelected(item))}});</script></polymer-element><polymer-elementname="core-selector"attributes="selected multi valueattr selectedClass selectedProperty selectedAttribute selectedItem selectedModel selectedIndex notap target itemsSelector activateEvent"assetpath="bower_components/core-selector/"><template><core-selectionid="selection"multi="{{multi}}"on-core-select="{{selectionSelect}}"></core-selection><contentid="items"select="*"></content></template><script>Polymer("core-selector",{selected:null,multi:false,valueattr:"name",selectedClass:"core-selected",selectedProperty:"",selectedAttribute:"active",selectedItem:null,selectedModel:null,selectedIndex:-1,target:null,itemsSelector:"",activateEvent:"tap",notap:false,ready:function(){this.activateListener=this.activateHandler.bind(this);this.observer=newMutationObserver(this.updateSelected.bind(this));if(!this.target){this.target=this}},getitems(){if(!this.target){return[]}varnodes=this.target!==this?this.itemsSelector?this.target.querySelectorAll(this.itemsSelector):this.target.children:this.$.items.getDistributedNodes();returnArray.prototype.filter.call(nodes||[],function(n){returnn&&n.localName!=="template"})},targetChanged:function(old){if(old){this.removeListener(old);this.observer.disconnect();this.clearSelection()}if(this.target){this.addListener(this.target);this.observer.observe(this.target,{childList:true});this.updateSelected()}},addListener:function(node){Polymer.addEventListener(node,this.activateEvent,this.activateListener)},removeListener:function(node){Polymer.removeEventListener(node,this.activateEvent,this.activateListener)},getselection(){returnthis.$.selection.getSelection()},selectedChanged:function(){this.updateSelected()},updateSelected:function(){this.validateSelected();if(this.multi){this.clearSelection();this.selected&&this.selected.forEach(function(s){this.valueToSelection(s)},this)}else{this.valueToSelection(this.selected)}},validateSelected:function(){if(this.multi&&!Array.isArray(this.selected)&&this.selected!==null&&this.selected!==undefined){this.selected=[this.selected]}},clearSelection:function(){if(this.multi){this.selection.slice().forEach(function(s){this.$.selection.setItemSelected(s,false)},this)}else{this.$.selection.setItemSelected(this.selection,false)}this.selectedItem=null;this.$.selection.clear()},valueToSelection:function(value){varitem=value===null||value===undefined?null:this.items[this.valueToIndex(value)];this.$.selection.select(item)},updateSelectedItem:function(){this.selectedItem=this.selection},selectedItemChanged:function(){if(this.selectedItem){vart=this.selectedItem.templateInstance;this.selectedModel=t?t.model:undefined}else{this.selectedModel=null}this.selectedIndex=this.selectedItem?parseInt(this.valueToIndex(this.selected)):-1},valueToIndex:function(value){for(vari=0,items=this.items,c;c=items[i];i++){if(this.valueForNode(c)==value){returni}}returnvalue},valueForNode:function(node){returnnode[this.valueattr]||node.getAttribute(this.valueattr)},selectionSelect:function(e,detail){this.updateSelectedItem();if(detail.item){this.applySelection(detail.item,detail.isSelected)}},applySelection:function(item,isSelected){if(this.selectedClass){item.classList.toggle(this.selectedClass,isSelected)}if(this.selectedProperty){item[this.selectedProperty]=isSelected}if(this.selectedAttribute&&item.setAttribute){if(isSelected){item.setAttribute(this.selectedAttribute,"")}else{item.removeAttribute(this.selectedAttribute)}}},activateHandler:function(e){if(!this.notap){vari=this.findDistributedTarget(e.target,this.items);if(i>=0){varitem=this.items[i];vars=this.valueForNode(item)||i;if(this.multi){if(this.selected){this.addRemoveSelected(s)}else{this.selected=[s]}}else{this.selected=s}this.asyncFire("core-activate",{item:item})}}},addRemoveSelected:function(value){vari=this.selected.indexOf(value);if(i>=0){this.selected.splice(i,1)}else{this.selected.push(value)}this.valueToSelection(value)},findDistributedTarget:function(target,nodes){while(target&&target!=this){vari=Array.prototype.indexOf.call(nodes,target);if(i>=0){returni}target=target.parentNode}}});</script></polymer-element><polymer-elementname="paper-ripple"attributes="initialOpacity opacityDecayVelocity"assetpath="bower_components/paper-ripple/"><template><style>:host{display:block;position:relative}#canvas{pointer-events:none;position:absolute;top:0;left:0;width:100%;height:100%}:host(.circle)#canvas{border-radius:50%}</style></template><script>(function(){varwaveMaxRadius=150;functionwaveRadiusFn(touchDownMs,touchUpMs,anim){vartouchDown=touchDownMs/1e3;vartouchUp=touchUpMs/1e3;vartotalElapsed=touchDown+touchUp;varww=anim.width,hh=anim.height;varwaveRadius=Math.min(Math.sqrt(ww*ww+hh*hh),waveMaxRadius)*1.1+5;varduration=1.1-.2*(waveRadius/waveMaxRadius);vartt=totalElapsed/duration;varsize=waveRadius*(1-Math.pow(80,-tt));returnMath.abs(size)}functionwaveOpacityFn(td,tu,anim){vartouchDown=td/1e3;vartouchUp=tu/1e3;vartotalElapsed=touchDown+touchUp;if(tu<=0){returnanim.initialOpacity}returnMath.max(0,anim.initialOpacity-touchUp*anim.opacityDecayVelocity)}functionwaveOuterOpacityFn(td,tu,anim){vartouchDown=td/1e3;vartouchUp=tu/1e3;varouterOpacity=touchDown*.3;varwaveOpacity=waveOpacityFn(td,tu,anim);returnMath.max(0,Math.min(outerOpacity,waveOpacity))}functionwaveDidFinish(wave,radius,anim){varwaveOpacity=waveOpacityFn(wave.tDown,wave.tUp,anim);if(waveOpacity<.01&&radius>=Math.min(wave.maxRadius,waveMaxRadius)){returntrue}returnfalse}functionwaveAtMaximum(wave,radius,anim){varwaveOpacity=waveOpacityFn(wave.tDown,wave.tUp,anim);if(waveOpacity>=anim.initialOpacity&&radius>=Math.min(wave.maxRadius,waveMaxRadius)){returntrue}returnfalse}functiondrawRipple(ctx,x,y,radius,innerColor,outerColor){if(outerColor){ctx.fillStyle=outerColor;ctx.fillRect(0,0,ctx.canvas.width,ctx.canvas.height)}ctx.beginPath();ctx.arc(x,y,radius,0,2*Math.PI,false);ctx.fillStyle=innerColor;ctx.fill()}functioncreateWave(elem){varelementStyle=window.getComputedStyle(elem);varfgColor=elementStyle.color;varwave={waveColor:fgColor,maxRadius:0,isMouseDown:false,mouseDownStart:0,mouseUpStart:0,tDown:0,tUp:0};returnwave}functionremoveWaveFromScope(scope,wave){if(scope.waves){varpos=scope.waves.indexOf(wave);scope.waves.splice(pos,1)}}varpow=Math.pow;varnow=Date.now;if(window.performance&&performance.now){now=performance.now.bind(performance)}functioncssColorWithAlpha(cssColor,alpha){varparts=cssColor.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);if(typeofalpha=="undefined"){alpha=1}if(!parts){return"rgba(255, 255, 255, "+alpha+")"}return"rgba("+parts[1]+", "+parts[2]+", "+parts[3]+", "+alpha+")"}functiondist(p1,p2){returnMath.sqrt(pow(p1.x-p2.x,2)+pow(p1.y-p2.y,2))}functiondistanceFromPointToFurthestCorner(point,size){vartl_d=dist(point,{x:0,y:0});vartr_d=dist(point,{x:size.w,y:0});varbl_d=dist(point,{x:0,y:size.h});varbr_d=dist(point,{x:size.w,y:size.h});returnMath.max(tl_d,tr_d,bl_d,br_d)}Polymer("paper-ripple",{initialOpacity:.25,opacityDecayVelocity:.8,backgroundFill:true,pixelDensity:2,eventDelegates:{down:"downAction",up:"upAction"},attached:function(){if(!this.$.canvas){varcanvas=document.createElement("canvas");canvas.id="canvas";this.shadowRoot.appendChild(canvas);this.$.canvas=canvas}},ready:function(){this.waves=[]},setupCanvas:function(){this.$.canvas.setAttribute("width",this.$.canvas.clientWidth*this.pixelDensity+"px");this.$.canvas.setAttribute("height",this.$.canvas.clientHeight*this.pixelDensity+"px");varctx=this.$.canvas.getContext("2d");ctx.scale(this.pixelDensity,this.pixelDensity);if(!this._loop){this._loop=this.animate.bind(this,ctx)}},downAction:function(e){this.setupCanvas();varwave=createWave(this.$.canvas);this.cancelled=false;wave.isMouseDown=true;wave.tDown=0;wave.tUp=0;wave.mouseUpStart=0;wave.mouseDownStart=now();varwidth=this.$.canvas.width/2;varheight=this.$.canvas.height/2;varrect=this.getBoundingClientRect();vartouchX=e.x-rect.left;vartouchY=e.y-rect.top;wave.startPosition={x:touchX,y:touchY};if(this.classList.contains("recenteringTouch")){wave.endPosition={x:width/2,y:height/2};wave.slideDistance=dist(wave.startPosition,wave.endPosition)}wave.containerSize=Math.max(width,height);wave.maxRadius=distanceFromPointToFurthestCorner(wave.startPosition,{w:width,h:height});this.waves.push(wave);requestAnimationFrame(this._loop)},upAction:function(){for(vari=0;i<this.waves.length;i++){varwave=this.waves[i];if(wave.isMouseDown){wave.isMouseDown=false;wave.mouseUpStart=now();wave.mouseDownStart=0;wave.tUp=0;break}}this._loop&&requestAnimationFrame(this._loop)},cancel:function(){this.cancelled=true},animate:function(ctx){varshouldRenderNextFrame=false;ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);vardeleteTheseWaves=[];varlongestTouchDownDuration=0;varlongestTouchUpDuration=0;varlastWaveColor=null;varanim={initialOpacity:this.initialOpacity,opacityDecayVelocity:this.opacityDecayVelocity,height:ctx.canvas.height,width:ctx.canvas.width};for(vari=0;i<this.waves.length;i++){varwave=this.waves[i];if(wave.mouseDownStart>0){wave.tDown=now()-wave.mouseDownStart}if(wave.mouseUpStart>0){wave.tUp=now()-wave.mouseUpStart}vartUp=wave.tUp;vartDown=wave.tDown;longestTouchDownDuration=Math.max(longestTouchDownDuration,tDown);longestTouchUpDuration=Math.max(longestTouchUpDuration,tUp);varradius=waveRadiusFn(tDown,tUp,anim);varwaveAlpha=waveOpacityFn(tDown,tUp,anim);varwaveColor=cssColorWithAlpha(wave.waveColor,waveAlpha);lastWaveColor=wave.waveColor;varx=wave.startPosition.x;vary=wave.startPosition.y;if(wave.endPosition){vartranslateFraction=Math.min(1,radius/wave.containerSize*2/Math.sqrt(2));x+=translateFraction*(wave.endPosition.x-wave.startPosition.x);y+=translateFraction*(wave.endPosition.y-wave.startPosition.y)}varbgFillColor=null;if(this.backgroundFill){varbgFillAlpha=waveOuterOpacityFn(tDown,tUp,anim);bgFillColor=cssColorWithAlpha(wave.waveColor,bgFillAlpha)}drawRipple(ctx,x,y,radius,waveColor,bgFillColor);varmaximumWave=waveAtMaximum(wave,radius,anim);varwaveDissipated=waveDidFinish(wave,radius,anim);varshouldKeepWave=!waveDissipated||maximumWave;varshouldRenderWaveAgain=!waveDissipated&&!maximumWave;shouldRenderNextFrame=shouldRenderNextFrame||shouldRenderWaveAgain;if(!shouldKeepWave||this.cancelled){deleteTheseWaves.push(wave)}}if(shouldRenderNextFrame){requestAnimationFrame(this._loop)}for(vari=0;i<deleteTheseWaves.length;++i){varwave=deleteTheseWaves[i];removeWaveFromScope(this,wave)}if(!this.waves.length){ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);this._loop=null}}})})();</script></polymer-element><polymer-elementname="paper-tab"attributes="noink"role="tab"assetpath="bower_components/paper-tabs/"><template><style>:host{display:block;position:relative;overflow:hidden}#tabContainer{position:absolute;top:0;right:0;bottom:0;left:0}.tab-content{transition:opacity.1scubic-bezier(0.4,0,1,1),color.1scubic-bezier(0.4,0,1,1);cursor:default;pointer-events:none}:host(:not(.core-selected)).tab-content{opacity:.6}#ink{position:absolute;top:0;right:0;bottom:0;left:0;color:#ffff8d}:host[noink]#ink{pointer-events:none}:host-context(paper-tabs[noink])#ink{pointer-events:none}</style><divid="tabContainer"center-justified=""center=""horizontal=""layout=""><divclass="tab-content"><content></content></div><paper-rippleid="ink"initialopacity="0.95"opacitydecayvelocity="0.98"></paper-ripple></div></template><script>Polymer("paper-tab",{noink:false});</script></polymer-element><polymer-elementname="paper-tabs"extends="core-selector"attributes="noink nobar"role="tablist"assetpath="bower_components/paper-tabs/"><template><style>:host{display:block;position:relative;font-size:14px;font-weight:500;height:48px;overflow:hidden}#tabsContainer{position:absolute;top:0;right:0;bottom:0;left:0;white-space:nowrap}#selectionBar{position:absolute;height:2px;bottom:0;left:0;width:0;background-color:#ffff8d;transition:width,left}#selectionBar[hidden]{display:hidden}#selectionBar.expand{transition-duration:.15s;transition-timing-function:cubic-bezier(0.4,0,1,1)}#selectionBar.contract{transition-duration:.1s;transition-timing-function:cubic-bezier(0,0,.2,1)}polyfill-next-selector{content:'#tabsContainer > *:not(#selectionBar)'}::content>*{-ms-flex:1;-webkit-flex:1;flex:1}</style><divid="tabsContainer"horizontal=""layout=""><shadow></shadow><divid="selectionBar"hidden?="{{nobar}}"on-transitionend="{{barTransitionEnd}}"></div></div></template><script>Polymer("paper-tabs",{noink:false,nobar:false,activateEvent:"down",nostretch:false,selectedIndexChanged:function(old){vars=this.$.selectionBar.style;if(!this.selectedItem){s.width=0;s.left=0;return}varw=100/this.items.length;if(this.nostretch||old===null||old===-1){s.width=w+"%";s.left=this.selectedIndex*w+"%";return}varm=5;this.$.selectionBar.classList.add("expand");if(old<this.selectedIndex){s.width=w+w*(this.selectedIndex-old)-m+"%"}else{s.width=w+w*(old-this.selectedIndex)-m+"%";s.left=this.selectedIndex*w+m+"%"}},barTransitionEnd:function(){varcl=this.$.selectionBar.classList;if(cl.contains("expand")){cl.remove("expand");cl.add("contract");vars=this.$.selectionBar.style;varw=100/this.items.length;s.width=w+"%";s.left=this.selectedIndex*w+"%"}elseif(cl.contains("contract")){cl.remove("contract")}}});</script></polymer-element></div></head><body><divclass="container"><headerclass="row"><divclass="col-md-8"><imgclass="logo"src="site-assets/logo.svg"width="500"height="86"alt="TodoMVC"><p>Helping you <strong>select</strong> an MV* framework</p><nav><ahref="https://github.com/tastejs/todomvc/zipball/1.3.0"class="zocial red">Download (1.3)</a><ahref="https://github.com/tastejs/todomvc"class="zocial ltgray">View on GitHub</a><ahref="http://blog.tastejs.com/"class="zocial ltgray">Blog</a></nav></div><divclass="col-md-4"><imgclass="logo-icon"src="site-assets/logo-icon.png"width="330"height="330"alt="TodoMVC"></div></header><divclass="row"><divclass="col-md-4"><h2>Introduction</h2><p>Developers these days are spoiled with choice when it comes to <ahref="http://coding.smashingmagazine.com/2012/07/27/journey-through-the-javascript-mvc-jungle/">selecting</a> an <strong>MV* framework</strong> for structuring and organizing their JavaScript web apps.</p><p>Backbone, Ember, AngularJS... the list of new and stable solutions continues to grow, but just how do you decide on which to use in a sea of so many options?</p><p>To help solve this problem, we created <ahref="https://github.com/tastejs/todomvc">TodoMVC</a> - a project which offers the same Todo application implemented using MV* concepts in most of the popular JavaScript MV* frameworks of today.</p><ahref="https://twitter.com/tastejs"class="twitter-follow-button"data-show-count="false"data-show-screen-name="false"></a><ahref="https://twitter.com/share"class="twitter-share-button"data-via="tastejs"data-url="http://todomvc.com"data-text="TodoMVC - Helping you select an MV* framework - Todo apps for Backbone.js, Ember.js, AngularJS, and more"></a><divclass="g-plusone"data-size="medium"data-annotation="none"data-href="http://todomvc.com"></div></div><divclass="col-md-8"><h2>Examples</h2><style shim-shadowdom="">paper-tabs,core-toolbar{color:#353535;background-color:#f4f4f4;font-family:'Helvetica Neue',Helvetica,Arial;box-shadow:03px2pxrgba(0,0,0,.2)}paper-tabs::shadow#selectionBar{background-color:#b12d2b}paper-tab::shadowpaper-ripple#ink{color:#b12d2b}</style><paper-tabsselected="js"class="js-app-tabs"><paper-tabname="js">JavaScript</paper-tab><paper-tabname="ctojs">Compile-to-JS</paper-tab><paper-tabname="labs">Labs</paper-tab></paper-tabs><divclass="app-lists"><divclass="js-app-list"data-app-list="js"><pclass="applist-intro">
These are examples written in pure JavaScript.
</p><ulclass="applist js"><liclass="routing"><ahref="architecture-examples/backbone"data-source="http://documentcloud.github.com/backbone/"data-content="Backbone.js gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface.">Backbone.js</a></li><liclass="routing"><ahref="architecture-examples/angularjs"data-source="http://angularjs.org"data-content="What HTML would have been had it been designed for web apps">AngularJS</a></li><liclass="routing"><ahref="architecture-examples/emberjs"data-source="http://emberjs.com"data-content="Ember is a JavaScript framework for creating ambitious web applications that eliminates boilerplate and provides a standard application architecture.">Ember.js</a></li><liclass="routing"><ahref="architecture-examples/knockoutjs"data-source="http://knockoutjs.com"data-content="Simplify dynamic JavaScript UIs by applying the Model-View-View Model (MVVM) pattern">KnockoutJS</a></li><liclass="routing"><ahref="architecture-examples/dojo"data-source="http://dojotoolkit.org"data-content="Dojo saves you time and scales with your development process, using web standards as its platform. It’s the toolkit experienced developers turn to for building high quality desktop and mobile web applications.">Dojo</a></li><liclass="routing"><ahref="architecture-examples/yui"data-source="http://yuilibrary.com"data-content="YUI's lightweight core and modular architecture make it scalable, fast, and robust. Built by frontend engineers at Yahoo!, YUI powers the most popular websites in the world.">YUI</a></li><liclass="routing"><ahref="architecture-examples/agilityjs"data-source="http://agilityjs.com"data-content="Agility.js is an MVC library for Javascript that lets you write maintainable and reusable browser code without the infrastructural overhead found in other MVC libraries. The goal is to enable developers to write web apps at least as quickly as with jQuery, while simplifying long-term maintainability through MVC objects.">Agility.js</a></li><liclass="routing"><ahref="architecture-examples/knockback"data-source="http://kmalakoff.github.com/knockback/"data-content="Knockback.js provides Knockout.js magic for Backbone.js Models and Collections.">Knockback.js</a></li><liclass="routing"><ahref="architecture-examples/canjs"data-source="http://canjs.us"data-content="CanJS with jQuery. CanJS is a client-side, JavaScript framework that makes building rich web applications easy. It provides can.Model (for connecting to RESTful JSON interfaces), can.View (for template loading and caching), can.Observe (for key-value binding), can.EJS (live binding templates), can.Control (declarative event bindings) and can.route (routing support).">CanJS</a></li><liclass="routing"><ahref="architecture-examples/maria"data-source="https://github.com/petermichaux/maria"data-content="An MVC framework for JavaScript applications. The real MVC. The Smalltalk MVC. The Gang of Four MVC. The three core design patterns of MVC (observer, composite, and strategy) are embedded in Maria's Model, View, and Controller objects. Other patterns traditionally included in MVC implementations (e.g. factory method and template) make appearances too.">Maria</a></li><liclass="routing"><ahref="architecture-examples/polymer/index.html"data-source="http://polymer-project.org"data-content="Polymer is a new type of library for the web, built on top of Web Components, and designed to leverage the evolving web platform on modern browsers. It is comprised of core platform features (e.g Shadow DOM, Custom Elements, MDV) enabled with polyfills and a next generation web application framework built on these technologies.">Polymer</a></li><liclass="routing"><ahref="architecture-examples/react"data-source="http://facebook.github.io/react/"data-content="React is a JavaScript library for building user interfaces.">React</a></li><liclass="routing"><ahref="dependency-examples/flight"data-source="http://twitter.github.com/flight"data-content="Flight is a lightweight, component-based JavaScript framework that maps behavior to DOM nodes. Twitter uses it for their web applications.">Flight</a></li></ul></div><divclass="js-app-list"data-app-list="ctojs"><pclass="applist-intro">