Commit 3d71ff07 authored by Sindre Sorhus's avatar Sindre Sorhus

Fixed crlf issue

parent 9e536a3c
html, body, div, span, applet, object, iframe, html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre, h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code, a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp, del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var, small, strike, strong, sub, sup, tt, var,
dl, dt, dd, ol, ul, li, dl, dt, dd, ol, ul, li,
fieldset, form, label, legend, fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td { table, caption, tbody, tfoot, thead, tr, th, td {
margin: 0; margin: 0;
padding: 0; padding: 0;
border: 0; border: 0;
outline: 0; outline: 0;
font-weight: inherit; font-weight: inherit;
font-style: inherit; font-style: inherit;
font-size: 100%; font-size: 100%;
font-family: inherit; font-family: inherit;
vertical-align: baseline; vertical-align: baseline;
} }
body { body {
line-height: 1; line-height: 1;
color: black; color: black;
background: white; background: white;
} }
ol, ul { ol, ul {
list-style: none; list-style: none;
} }
a img { a img {
border: none; border: none;
} }
html { html {
background: #eeeeee; background: #eeeeee;
} }
body { body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px; font-size: 14px;
line-height: 1.4em; line-height: 1.4em;
background: #eeeeee; background: #eeeeee;
color: #333333; color: #333333;
} }
#todoapp { #todoapp {
width: 480px; width: 480px;
margin: 0 auto 40px; margin: 0 auto 40px;
background: white; background: white;
padding: 20px; padding: 20px;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0; -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0; -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0; -o-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0; box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
-moz-border-radius: 0 0 5px 5px; -moz-border-radius: 0 0 5px 5px;
-o-border-radius: 0 0 5px 5px; -o-border-radius: 0 0 5px 5px;
-webkit-border-radius: 0 0 5px 5px; -webkit-border-radius: 0 0 5px 5px;
border-radius: 0 0 5px 5px; border-radius: 0 0 5px 5px;
} }
#todoapp h1 { #todoapp h1 {
font-size: 36px; font-size: 36px;
font-weight: bold; font-weight: bold;
text-align: center; text-align: center;
padding: 20px 0 30px 0; padding: 20px 0 30px 0;
line-height: 1; line-height: 1;
} }
#create-todo { #create-todo {
position: relative; position: relative;
} }
#create-todo input { #create-todo input {
width: 466px; width: 466px;
font-size: 24px; font-size: 24px;
font-family: inherit; font-family: inherit;
line-height: 1.4em; line-height: 1.4em;
border: 0; border: 0;
outline: none; outline: none;
padding: 6px; padding: 6px;
border: 1px solid #999999; border: 1px solid #999999;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; -o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
} }
#create-todo input::-webkit-input-placeholder { #create-todo input::-webkit-input-placeholder {
font-style: italic; font-style: italic;
} }
#create-todo span { #create-todo span {
position: absolute; position: absolute;
z-index: 999; z-index: 999;
width: 170px; width: 170px;
left: 50%; left: 50%;
margin-left: -85px; margin-left: -85px;
} }
#todo-list { #todo-list {
margin-top: 10px; margin-top: 10px;
} }
#todo-list li { #todo-list li {
padding: 12px 20px 11px 0; padding: 12px 20px 11px 0;
position: relative; position: relative;
font-size: 24px; font-size: 24px;
line-height: 1.1em; line-height: 1.1em;
border-bottom: 1px solid #cccccc; border-bottom: 1px solid #cccccc;
} }
#todo-list li:after { #todo-list li:after {
content: "\0020"; content: "\0020";
display: block; display: block;
height: 0; height: 0;
clear: both; clear: both;
overflow: hidden; overflow: hidden;
visibility: hidden; visibility: hidden;
} }
#todo-list li.editing { #todo-list li.editing {
padding: 0; padding: 0;
border-bottom: 0; border-bottom: 0;
} }
#todo-list .editing .display, #todo-list .editing .display,
#todo-list .edit { #todo-list .edit {
display: none; display: none;
} }
#todo-list .editing .edit { #todo-list .editing .edit {
display: block; display: block;
} }
#todo-list .editing input { #todo-list .editing input {
width: 444px; width: 444px;
font-size: 24px; font-size: 24px;
font-family: inherit; font-family: inherit;
margin: 0; margin: 0;
line-height: 1.6em; line-height: 1.6em;
border: 0; border: 0;
outline: none; outline: none;
padding: 10px 7px 0px 27px; padding: 10px 7px 0px 27px;
border: 1px solid #999999; border: 1px solid #999999;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; -o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
} }
#todo-list .check { #todo-list .check {
position: relative; position: relative;
top: 9px; top: 9px;
margin: 0 10px 0 7px; margin: 0 10px 0 7px;
float: left; float: left;
} }
#todo-list .done .todo-content { #todo-list .done .todo-content {
text-decoration: line-through; text-decoration: line-through;
color: #777777; color: #777777;
} }
#todo-list .todo-destroy { #todo-list .todo-destroy {
position: absolute; position: absolute;
right: 5px; right: 5px;
top: 14px; top: 14px;
display: none; display: none;
cursor: pointer; cursor: pointer;
width: 20px; width: 20px;
height: 20px; height: 20px;
background: url(destroy.png) no-repeat 0 0; background: url(destroy.png) no-repeat 0 0;
} }
#todo-list li:hover .todo-destroy { #todo-list li:hover .todo-destroy {
display: block; display: block;
} }
#todo-list .todo-destroy:hover { #todo-list .todo-destroy:hover {
background-position: 0 -20px; background-position: 0 -20px;
} }
#todo-stats { #todo-stats {
*zoom: 1; *zoom: 1;
margin-top: 10px; margin-top: 10px;
color: #777777; color: #777777;
} }
#todo-stats:after { #todo-stats:after {
content: "\0020"; content: "\0020";
display: block; display: block;
height: 0; height: 0;
clear: both; clear: both;
overflow: hidden; overflow: hidden;
visibility: hidden; visibility: hidden;
} }
#todo-stats .todo-count { #todo-stats .todo-count {
float: left; float: left;
} }
#todo-stats .todo-count .number { #todo-stats .todo-count .number {
font-weight: bold; font-weight: bold;
color: #333333; color: #333333;
} }
#todo-stats .todo-clear { #todo-stats .todo-clear {
float: right; float: right;
} }
#todo-stats .todo-clear a { #todo-stats .todo-clear a {
color: #777777; color: #777777;
font-size: 12px; font-size: 12px;
} }
/* these two rules are overridden below. find ".todo-clear a" */ /* these two rules are overridden below. find ".todo-clear a" */
#todo-stats .todo-clear a:visited { #todo-stats .todo-clear a:visited {
color: #777777; color: #777777;
} }
#todo-stats .todo-clear a:hover, #todo-stats .todo-clear a:focus { #todo-stats .todo-clear a:hover, #todo-stats .todo-clear a:focus {
color: #336699; color: #336699;
} }
#instructions { #instructions {
width: 520px; width: 520px;
margin: 10px auto; margin: 10px auto;
color: #777777; color: #777777;
text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0; text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
text-align: center; text-align: center;
} }
#instructions a { #instructions a {
color: #336699; color: #336699;
} }
#credits { #credits {
width: 520px; width: 520px;
margin: 30px auto; margin: 30px auto;
color: #999; color: #999;
text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0; text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
text-align: center; text-align: center;
} }
#credits a { #credits a {
color: #888; color: #888;
} }
/* /*
* François 'cahnory' Germain * François 'cahnory' Germain
*/ */
.ui-tooltip, .ui-tooltip-top, .ui-tooltip-right, .ui-tooltip-bottom, .ui-tooltip-left { .ui-tooltip, .ui-tooltip-top, .ui-tooltip-right, .ui-tooltip-bottom, .ui-tooltip-left {
color:#ffffff; color:#ffffff;
cursor:normal; cursor:normal;
display:-moz-inline-stack; display:-moz-inline-stack;
display:inline-block; display:inline-block;
font-size:12px; font-size:12px;
font-family:arial; font-family:arial;
padding:.5em 1em; padding:.5em 1em;
position:relative; position:relative;
text-align:center; text-align:center;
text-shadow:0 -1px 1px #111111; text-shadow:0 -1px 1px #111111;
-webkit-border-top-left-radius:4px ; -webkit-border-top-left-radius:4px ;
-webkit-border-top-right-radius:4px ; -webkit-border-top-right-radius:4px ;
-webkit-border-bottom-right-radius:4px ; -webkit-border-bottom-right-radius:4px ;
-webkit-border-bottom-left-radius:4px ; -webkit-border-bottom-left-radius:4px ;
-khtml-border-top-left-radius:4px ; -khtml-border-top-left-radius:4px ;
-khtml-border-top-right-radius:4px ; -khtml-border-top-right-radius:4px ;
-khtml-border-bottom-right-radius:4px ; -khtml-border-bottom-right-radius:4px ;
-khtml-border-bottom-left-radius:4px ; -khtml-border-bottom-left-radius:4px ;
-moz-border-radius-topleft:4px ; -moz-border-radius-topleft:4px ;
-moz-border-radius-topright:4px ; -moz-border-radius-topright:4px ;
-moz-border-radius-bottomright:4px ; -moz-border-radius-bottomright:4px ;
-moz-border-radius-bottomleft:4px ; -moz-border-radius-bottomleft:4px ;
border-top-left-radius:4px ; border-top-left-radius:4px ;
border-top-right-radius:4px ; border-top-right-radius:4px ;
border-bottom-right-radius:4px ; border-bottom-right-radius:4px ;
border-bottom-left-radius:4px ; border-bottom-left-radius:4px ;
-o-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444; -o-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
-moz-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444; -moz-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
-khtml-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444; -khtml-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
-webkit-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444; -webkit-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444; box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
background-color:#3b3b3b; background-color:#3b3b3b;
background-image:-moz-linear-gradient(top,#555555,#222222); background-image:-moz-linear-gradient(top,#555555,#222222);
background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#555555),color-stop(1,#222222)); background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#555555),color-stop(1,#222222));
filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#555555,EndColorStr=#222222); filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#555555,EndColorStr=#222222);
-ms-filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#555555,EndColorStr=#222222); -ms-filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#555555,EndColorStr=#222222);
} }
.ui-tooltip:after, .ui-tooltip-top:after, .ui-tooltip-right:after, .ui-tooltip-bottom:after, .ui-tooltip-left:after { .ui-tooltip:after, .ui-tooltip-top:after, .ui-tooltip-right:after, .ui-tooltip-bottom:after, .ui-tooltip-left:after {
content:"\25B8"; content:"\25B8";
display:block; display:block;
font-size:2em; font-size:2em;
height:0; height:0;
line-height:0; line-height:0;
position:absolute; position:absolute;
} }
.ui-tooltip:after, .ui-tooltip-bottom:after { .ui-tooltip:after, .ui-tooltip-bottom:after {
color:#2a2a2a; color:#2a2a2a;
bottom:0; bottom:0;
left:1px; left:1px;
text-align:center; text-align:center;
text-shadow:1px 0 2px #000000; text-shadow:1px 0 2px #000000;
-o-transform:rotate(90deg); -o-transform:rotate(90deg);
-moz-transform:rotate(90deg); -moz-transform:rotate(90deg);
-khtml-transform:rotate(90deg); -khtml-transform:rotate(90deg);
-webkit-transform:rotate(90deg); -webkit-transform:rotate(90deg);
width:100%; width:100%;
} }
.ui-tooltip-top:after { .ui-tooltip-top:after {
bottom:auto; bottom:auto;
color:#4f4f4f; color:#4f4f4f;
left:-2px; left:-2px;
top:0; top:0;
text-align:center; text-align:center;
text-shadow:none; text-shadow:none;
-o-transform:rotate(-90deg); -o-transform:rotate(-90deg);
-moz-transform:rotate(-90deg); -moz-transform:rotate(-90deg);
-khtml-transform:rotate(-90deg); -khtml-transform:rotate(-90deg);
-webkit-transform:rotate(-90deg); -webkit-transform:rotate(-90deg);
width:100%; width:100%;
} }
.ui-tooltip-right:after { .ui-tooltip-right:after {
color:#222222; color:#222222;
right:-0.375em; right:-0.375em;
top:50%; top:50%;
margin-top:-.05em; margin-top:-.05em;
text-shadow:0 1px 2px #000000; text-shadow:0 1px 2px #000000;
-o-transform:rotate(0); -o-transform:rotate(0);
-moz-transform:rotate(0); -moz-transform:rotate(0);
-khtml-transform:rotate(0); -khtml-transform:rotate(0);
-webkit-transform:rotate(0); -webkit-transform:rotate(0);
} }
.ui-tooltip-left:after { .ui-tooltip-left:after {
color:#222222; color:#222222;
left:-0.375em; left:-0.375em;
top:50%; top:50%;
margin-top:.1em; margin-top:.1em;
text-shadow:0 -1px 2px #000000; text-shadow:0 -1px 2px #000000;
-o-transform:rotate(180deg); -o-transform:rotate(180deg);
-moz-transform:rotate(180deg); -moz-transform:rotate(180deg);
-khtml-transform:rotate(180deg); -khtml-transform:rotate(180deg);
-webkit-transform:rotate(180deg); -webkit-transform:rotate(180deg);
} }
/* new additions - cleanup required*/ /* new additions - cleanup required*/
/* line 109 */ /* line 109 */
#todoapp #todo-stats { #todoapp #todo-stats {
*zoom: 1; *zoom: 1;
margin-top: 10px; margin-top: 10px;
color: #555555; color: #555555;
-moz-border-radius-bottomleft: 5px; -moz-border-radius-bottomleft: 5px;
-webkit-border-bottom-left-radius: 5px; -webkit-border-bottom-left-radius: 5px;
-o-border-bottom-left-radius: 5px; -o-border-bottom-left-radius: 5px;
-ms-border-bottom-left-radius: 5px; -ms-border-bottom-left-radius: 5px;
-khtml-border-bottom-left-radius: 5px; -khtml-border-bottom-left-radius: 5px;
border-bottom-left-radius: 5px; border-bottom-left-radius: 5px;
-moz-border-radius-bottomright: 5px; -moz-border-radius-bottomright: 5px;
-webkit-border-bottom-right-radius: 5px; -webkit-border-bottom-right-radius: 5px;
-o-border-bottom-right-radius: 5px; -o-border-bottom-right-radius: 5px;
-ms-border-bottom-right-radius: 5px; -ms-border-bottom-right-radius: 5px;
-khtml-border-bottom-right-radius: 5px; -khtml-border-bottom-right-radius: 5px;
border-bottom-right-radius: 5px; border-bottom-right-radius: 5px;
background: #f4fce8; background: #f4fce8;
border-top: 1px solid #ededed; border-top: 1px solid #ededed;
padding: 0 20px; padding: 0 20px;
line-height: 36px; line-height: 36px;
} }
/* line 22, /opt/ree/lib/ruby/gems/1.8/gems/compass-0.10.5/frameworks/compass/stylesheets/compass/utilities/general/_clearfix.scss */ /* line 22, /opt/ree/lib/ruby/gems/1.8/gems/compass-0.10.5/frameworks/compass/stylesheets/compass/utilities/general/_clearfix.scss */
#todoapp #todo-stats:after { #todoapp #todo-stats:after {
content: "\0020"; content: "\0020";
display: block; display: block;
height: 0; height: 0;
clear: both; clear: both;
overflow: hidden; overflow: hidden;
visibility: hidden; visibility: hidden;
} }
/* line 118 */ /* line 118 */
#todoapp #todo-stats .todo-count { #todoapp #todo-stats .todo-count {
float: left; float: left;
} }
/* line 120 */ /* line 120 */
#todoapp #todo-stats .todo-count .number { #todoapp #todo-stats .todo-count .number {
font-weight: bold; font-weight: bold;
color: #555555; color: #555555;
} }
/* line 123 */ /* line 123 */
#todoapp #todo-stats .todo-clear { #todoapp #todo-stats .todo-clear {
float: right; float: right;
} }
/* line 125 */ /* line 125 */
#todoapp #todo-stats .todo-clear a { #todoapp #todo-stats .todo-clear a {
display: block; display: block;
line-height: 20px; line-height: 20px;
text-decoration: none; text-decoration: none;
-moz-border-radius: 12px; -moz-border-radius: 12px;
-webkit-border-radius: 12px; -webkit-border-radius: 12px;
-o-border-radius: 12px; -o-border-radius: 12px;
-ms-border-radius: 12px; -ms-border-radius: 12px;
-khtml-border-radius: 12px; -khtml-border-radius: 12px;
border-radius: 12px; border-radius: 12px;
background: rgba(0, 0, 0, 0.1); background: rgba(0, 0, 0, 0.1);
color: #555555; color: #555555;
font-size: 11px; font-size: 11px;
margin-top: 8px; margin-top: 8px;
padding: 0 10px 1px; padding: 0 10px 1px;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0; -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0; -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0; -o-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0; box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
} }
/* line 136 */ /* line 136 */
#todoapp #todo-stats .todo-clear a:hover, #todoapp #todo-stats .todo-clear a:focus { #todoapp #todo-stats .todo-clear a:hover, #todoapp #todo-stats .todo-clear a:focus {
background: rgba(0, 0, 0, 0.15); background: rgba(0, 0, 0, 0.15);
-moz-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0; -moz-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
-webkit-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0; -webkit-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
-o-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0; -o-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0; box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
} }
/* line 139 */ /* line 139 */
#todoapp #todo-stats .todo-clear a:active { #todoapp #todo-stats .todo-clear a:active {
position: relative; position: relative;
top: 1px; top: 1px;
} }
goog.require('goog.array'); goog.require('goog.array');
goog.require('goog.events.EventType'); goog.require('goog.events.EventType');
goog.require('goog.events.KeyCodes'); goog.require('goog.events.KeyCodes');
goog.require('goog.ui.Component'); goog.require('goog.ui.Component');
goog.require('goog.ui.Control'); goog.require('goog.ui.Control');
goog.require('todomvc.model.ToDoItem'); goog.require('todomvc.model.ToDoItem');
goog.require('todomvc.view'); goog.require('todomvc.view');
goog.require('todomvc.view.ClearCompletedControlRenderer'); goog.require('todomvc.view.ClearCompletedControlRenderer');
goog.require('todomvc.view.ItemCountControlRenderer'); goog.require('todomvc.view.ItemCountControlRenderer');
goog.require('todomvc.view.ToDoItemControl'); goog.require('todomvc.view.ToDoItemControl');
goog.require('todomvc.view.ToDoListContainer'); goog.require('todomvc.view.ToDoListContainer');
/** /**
* @fileoverview The controller/business logic for the application. * @fileoverview The controller/business logic for the application.
* *
* This file creates the interface and marshalls changes from the interface to the model and back. * This file creates the interface and marshalls changes from the interface to the model and back.
*/ */
/** /**
* @type {Array.<todomvc.model.ToDoItem>} * @type {Array.<todomvc.model.ToDoItem>}
*/ */
var items = []; var items = [];
/** /**
* @type {Element} * @type {Element}
*/ */
var todoStats = document.getElementById('todo-stats'); var todoStats = document.getElementById('todo-stats');
/** /**
* @type {goog.ui.Control} * @type {goog.ui.Control}
*/ */
var itemCountControl = new goog.ui.Control(null, todomvc.view.ItemCountControlRenderer.getInstance()); var itemCountControl = new goog.ui.Control(null, todomvc.view.ItemCountControlRenderer.getInstance());
itemCountControl.render(todoStats); itemCountControl.render(todoStats);
/** /**
* @type {goog.ui.Control} * @type {goog.ui.Control}
*/ */
var clearCompletedControl = new goog.ui.Control(null, todomvc.view.ClearCompletedControlRenderer.getInstance()); var clearCompletedControl = new goog.ui.Control(null, todomvc.view.ClearCompletedControlRenderer.getInstance());
clearCompletedControl.render(todoStats); clearCompletedControl.render(todoStats);
goog.events.listen(clearCompletedControl, goog.ui.Component.EventType.ACTION, function(e) { goog.events.listen(clearCompletedControl, goog.ui.Component.EventType.ACTION, function(e) {
// go backwards to avoid collection modification problems // go backwards to avoid collection modification problems
goog.array.forEachRight(items, function(model) { goog.array.forEachRight(items, function(model) {
if (model.isDone()) { if (model.isDone()) {
goog.array.remove(items, model); goog.array.remove(items, model);
// do optimised model view sync // do optimised model view sync
container.forEachChild(function(control) { container.forEachChild(function(control) {
if (control.getModel() === model) { if (control.getModel() === model) {
container.removeChild(control, true); container.removeChild(control, true);
} }
}); });
} }
}); });
updateStats(); updateStats();
}); });
function updateStats() { function updateStats() {
var doneCount = goog.array.reduce(items, function(count, model) { var doneCount = goog.array.reduce(items, function(count, model) {
return model.isDone() ? count + 1 : count; return model.isDone() ? count + 1 : count;
}, 0); }, 0);
var remainingCount = items.length - (/**@type {number}*/ doneCount); var remainingCount = items.length - (/**@type {number}*/ doneCount);
itemCountControl.setContent((/**@type {string}*/ remainingCount)); itemCountControl.setContent((/**@type {string}*/ remainingCount));
itemCountControl.setVisible(remainingCount > 0); itemCountControl.setVisible(remainingCount > 0);
clearCompletedControl.setContent((/**@type {string}*/ doneCount)); clearCompletedControl.setContent((/**@type {string}*/ doneCount));
clearCompletedControl.setVisible((/**@type {number}*/ doneCount) > 0); clearCompletedControl.setVisible((/**@type {number}*/ doneCount) > 0);
} }
updateStats(); updateStats();
/** /**
* @type {todomvc.view.ToDoListContainer} * @type {todomvc.view.ToDoListContainer}
*/ */
var container = new todomvc.view.ToDoListContainer(); var container = new todomvc.view.ToDoListContainer();
container.decorate(document.getElementById('todo-list')); container.decorate(document.getElementById('todo-list'));
goog.events.listen(container, todomvc.view.ToDoItemControl.EventType.EDIT, function(e) { goog.events.listen(container, todomvc.view.ToDoItemControl.EventType.EDIT, function(e) {
/** /**
* @type {todomvc.view.ToDoItemControl} * @type {todomvc.view.ToDoItemControl}
*/ */
var control = e.target; var control = e.target;
/** /**
* @type {todomvc.model.ToDoItem} * @type {todomvc.model.ToDoItem}
*/ */
var model = (/**@type {todomvc.model.ToDoItem} */ control.getModel()); var model = (/**@type {todomvc.model.ToDoItem} */ control.getModel());
// do optimised model view sync // do optimised model view sync
model.setNote((/**@type {!string} */ control.getContent())); model.setNote((/**@type {!string} */ control.getContent()));
model.setDone((/**@type {!boolean} */ control.isChecked())); model.setDone((/**@type {!boolean} */ control.isChecked()));
updateStats(); updateStats();
}); });
goog.events.listen(container, todomvc.view.ToDoItemControl.EventType.DESTROY, function(e) { goog.events.listen(container, todomvc.view.ToDoItemControl.EventType.DESTROY, function(e) {
/** /**
* @type {todomvc.view.ToDoItemControl} * @type {todomvc.view.ToDoItemControl}
*/ */
var control = e.target; var control = e.target;
/** /**
* @type {todomvc.model.ToDoItem} * @type {todomvc.model.ToDoItem}
*/ */
var model = (/**@type {todomvc.model.ToDoItem} */ control.getModel()); var model = (/**@type {todomvc.model.ToDoItem} */ control.getModel());
// do optimised model view sync // do optimised model view sync
goog.array.remove(items, model); goog.array.remove(items, model);
container.removeChild(control, true); container.removeChild(control, true);
updateStats(); updateStats();
}); });
/** /**
* @type {Element} * @type {Element}
*/ */
var newToDo = document.getElementById('new-todo'); var newToDo = document.getElementById('new-todo');
goog.events.listen(newToDo, goog.events.EventType.KEYUP, function(e) { goog.events.listen(newToDo, goog.events.EventType.KEYUP, function(e) {
if (e.keyCode === goog.events.KeyCodes.ENTER) { if (e.keyCode === goog.events.KeyCodes.ENTER) {
/** /**
* @type {todomvc.model.ToDoItem} * @type {todomvc.model.ToDoItem}
*/ */
var model = new todomvc.model.ToDoItem(newToDo.value); var model = new todomvc.model.ToDoItem(newToDo.value);
/** /**
* @type {todomvc.view.ToDoItemControl} * @type {todomvc.view.ToDoItemControl}
*/ */
var control = new todomvc.view.ToDoItemControl(); var control = new todomvc.view.ToDoItemControl();
// do optimised model view sync // do optimised model view sync
items.push(model); items.push(model);
control.setContent(model.getNote()); control.setContent(model.getNote());
control.setChecked(model.isDone()); control.setChecked(model.isDone());
control.setModel(model); control.setModel(model);
container.addChild(control, true); container.addChild(control, true);
// clear the input box // clear the input box
newToDo.value = ''; newToDo.value = '';
updateStats(); updateStats();
} }
}); });
\ No newline at end of file
goog.provide('todomvc.model.ToDoItem'); goog.provide('todomvc.model.ToDoItem');
/** /**
* The model object representing a todo item. * The model object representing a todo item.
* *
* @param {!string} note the text associated with this item * @param {!string} note the text associated with this item
* @param {!boolean=} opt_done is this item complete? defaults to false * @param {!boolean=} opt_done is this item complete? defaults to false
* @constructor * @constructor
*/ */
todomvc.model.ToDoItem = function(note, opt_done) { todomvc.model.ToDoItem = function(note, opt_done) {
/** /**
* note the text associated with this item * note the text associated with this item
* @private * @private
* @type {!string} * @type {!string}
*/ */
this.note_ = note; this.note_ = note;
/** /**
* is this item complete? * is this item complete?
* @private * @private
* @type {!boolean} * @type {!boolean}
*/ */
this.done_ = opt_done || false; this.done_ = opt_done || false;
}; };
/** /**
* @return {!string} the text associated with this item * @return {!string} the text associated with this item
*/ */
todomvc.model.ToDoItem.prototype.getNote = function() { todomvc.model.ToDoItem.prototype.getNote = function() {
return this.note_; return this.note_;
}; };
/** /**
* @return {!boolean} is this item complete? * @return {!boolean} is this item complete?
*/ */
todomvc.model.ToDoItem.prototype.isDone = function() { todomvc.model.ToDoItem.prototype.isDone = function() {
return this.done_; return this.done_;
}; };
/** /**
* @param {!string} note the text associated with this item * @param {!string} note the text associated with this item
*/ */
todomvc.model.ToDoItem.prototype.setNote = function(note) { todomvc.model.ToDoItem.prototype.setNote = function(note) {
this.note_ = note; this.note_ = note;
}; };
/** /**
* @param {!boolean} done is this item complete? * @param {!boolean} done is this item complete?
*/ */
todomvc.model.ToDoItem.prototype.setDone = function(done) { todomvc.model.ToDoItem.prototype.setDone = function(done) {
this.done_ = done; this.done_ = done;
}; };
\ No newline at end of file
goog.provide('todomvc.view.ClearCompletedControlRenderer'); goog.provide('todomvc.view.ClearCompletedControlRenderer');
goog.require('goog.dom'); goog.require('goog.dom');
goog.require('goog.ui.Component.State'); goog.require('goog.ui.Component.State');
goog.require('goog.ui.ControlRenderer'); goog.require('goog.ui.ControlRenderer');
/** /**
* A renderer for the clear completed control. * A renderer for the clear completed control.
* *
* @constructor * @constructor
* @extends {goog.ui.ControlRenderer} * @extends {goog.ui.ControlRenderer}
*/ */
todomvc.view.ClearCompletedControlRenderer = function() { todomvc.view.ClearCompletedControlRenderer = function() {
goog.ui.ControlRenderer.call(this); goog.ui.ControlRenderer.call(this);
}; };
goog.inherits(todomvc.view.ClearCompletedControlRenderer, goog.ui.ControlRenderer); goog.inherits(todomvc.view.ClearCompletedControlRenderer, goog.ui.ControlRenderer);
// add getInstance method to todomvc.view.ClearCompletedControlRenderer // add getInstance method to todomvc.view.ClearCompletedControlRenderer
goog.addSingletonGetter(todomvc.view.ClearCompletedControlRenderer); goog.addSingletonGetter(todomvc.view.ClearCompletedControlRenderer);
/** /**
* @param {goog.ui.Control} control Control to render. * @param {goog.ui.Control} control Control to render.
* @return {Element} Root element for the control. * @return {Element} Root element for the control.
*/ */
todomvc.view.ClearCompletedControlRenderer.prototype.createDom = function(control) { todomvc.view.ClearCompletedControlRenderer.prototype.createDom = function(control) {
var html = todomvc.view.clearCompleted({ var html = todomvc.view.clearCompleted({
number : control.getContent() number : control.getContent()
}); });
var element = (/**@type {!Element}*/ goog.dom.htmlToDocumentFragment(html)); var element = (/**@type {!Element}*/ goog.dom.htmlToDocumentFragment(html));
this.setAriaStates(control, element); this.setAriaStates(control, element);
return element; return element;
}; };
/** /**
* @param {Element} element Element to decorate. * @param {Element} element Element to decorate.
* @return {boolean} Whether the renderer can decorate the element. * @return {boolean} Whether the renderer can decorate the element.
*/ */
todomvc.view.ClearCompletedControlRenderer.prototype.canDecorate = function(element) { todomvc.view.ClearCompletedControlRenderer.prototype.canDecorate = function(element) {
return false; return false;
}; };
/** /**
* @param {Element} element Element to populate. * @param {Element} element Element to populate.
* @param {goog.ui.ControlContent} content Text caption or DOM * @param {goog.ui.ControlContent} content Text caption or DOM
*/ */
todomvc.view.ClearCompletedControlRenderer.prototype.setContent = function(element, content) { todomvc.view.ClearCompletedControlRenderer.prototype.setContent = function(element, content) {
element.innerHTML = todomvc.view.clearCompletedInner({ element.innerHTML = todomvc.view.clearCompletedInner({
number : content number : content
}); });
}; };
/** /**
* Updates the appearance of the control in response to a state change. * Updates the appearance of the control in response to a state change.
* *
* @param {goog.ui.Control} control Control instance to update. * @param {goog.ui.Control} control Control instance to update.
* @param {goog.ui.Component.State} state State to enable or disable. * @param {goog.ui.Component.State} state State to enable or disable.
* @param {boolean} enable Whether the control is entering or exiting the state. * @param {boolean} enable Whether the control is entering or exiting the state.
*/ */
todomvc.view.ClearCompletedControlRenderer.prototype.setState = function(control, state, enable) { todomvc.view.ClearCompletedControlRenderer.prototype.setState = function(control, state, enable) {
var element = control.getElement(); var element = control.getElement();
if (element) { if (element) {
this.updateAriaState(element, state, enable); this.updateAriaState(element, state, enable);
} }
}; };
goog.provide('todomvc.view.ItemCountControlRenderer'); goog.provide('todomvc.view.ItemCountControlRenderer');
goog.require('goog.dom'); goog.require('goog.dom');
goog.require('goog.ui.Component.State'); goog.require('goog.ui.Component.State');
goog.require('goog.ui.ControlRenderer'); goog.require('goog.ui.ControlRenderer');
/** /**
* A renderer for the item count control. * A renderer for the item count control.
* *
* @constructor * @constructor
* @extends {goog.ui.ControlRenderer} * @extends {goog.ui.ControlRenderer}
*/ */
todomvc.view.ItemCountControlRenderer = function() { todomvc.view.ItemCountControlRenderer = function() {
goog.ui.ControlRenderer.call(this); goog.ui.ControlRenderer.call(this);
}; };
goog.inherits(todomvc.view.ItemCountControlRenderer, goog.ui.ControlRenderer); goog.inherits(todomvc.view.ItemCountControlRenderer, goog.ui.ControlRenderer);
// add getInstance method to todomvc.view.ItemCountControlRenderer // add getInstance method to todomvc.view.ItemCountControlRenderer
goog.addSingletonGetter(todomvc.view.ItemCountControlRenderer); goog.addSingletonGetter(todomvc.view.ItemCountControlRenderer);
/** /**
* @param {goog.ui.Control} control Control to render. * @param {goog.ui.Control} control Control to render.
* @return {Element} Root element for the control. * @return {Element} Root element for the control.
*/ */
todomvc.view.ItemCountControlRenderer.prototype.createDom = function(control) { todomvc.view.ItemCountControlRenderer.prototype.createDom = function(control) {
var html = todomvc.view.itemCount({ var html = todomvc.view.itemCount({
number : control.getContent() number : control.getContent()
}); });
var element = (/**@type {!Element}*/ goog.dom.htmlToDocumentFragment(html)); var element = (/**@type {!Element}*/ goog.dom.htmlToDocumentFragment(html));
this.setAriaStates(control, element); this.setAriaStates(control, element);
return element; return element;
}; };
/** /**
* @param {Element} element Element to decorate. * @param {Element} element Element to decorate.
* @return {boolean} Whether the renderer can decorate the element. * @return {boolean} Whether the renderer can decorate the element.
*/ */
todomvc.view.ItemCountControlRenderer.prototype.canDecorate = function(element) { todomvc.view.ItemCountControlRenderer.prototype.canDecorate = function(element) {
return false; return false;
}; };
/** /**
* @param {Element} element Element to populate. * @param {Element} element Element to populate.
* @param {goog.ui.ControlContent} content Text caption or DOM * @param {goog.ui.ControlContent} content Text caption or DOM
*/ */
todomvc.view.ItemCountControlRenderer.prototype.setContent = function(element, content) { todomvc.view.ItemCountControlRenderer.prototype.setContent = function(element, content) {
element.innerHTML = todomvc.view.itemCountInner({ element.innerHTML = todomvc.view.itemCountInner({
number : content number : content
}); });
}; };
/** /**
* Updates the appearance of the control in response to a state change. * Updates the appearance of the control in response to a state change.
* *
* @param {goog.ui.Control} control Control instance to update. * @param {goog.ui.Control} control Control instance to update.
* @param {goog.ui.Component.State} state State to enable or disable. * @param {goog.ui.Component.State} state State to enable or disable.
* @param {boolean} enable Whether the control is entering or exiting the state. * @param {boolean} enable Whether the control is entering or exiting the state.
*/ */
todomvc.view.ItemCountControlRenderer.prototype.setState = function(control, state, enable) { todomvc.view.ItemCountControlRenderer.prototype.setState = function(control, state, enable) {
var element = control.getElement(); var element = control.getElement();
if (element) { if (element) {
this.updateAriaState(element, state, enable); this.updateAriaState(element, state, enable);
} }
}; };
goog.provide('todomvc.view.ToDoItemControl'); goog.provide('todomvc.view.ToDoItemControl');
goog.require('goog.dom'); goog.require('goog.dom');
goog.require('goog.events'); goog.require('goog.events');
goog.require('goog.ui.Component.State'); goog.require('goog.ui.Component.State');
goog.require('goog.ui.Control'); goog.require('goog.ui.Control');
goog.require('todomvc.view.ToDoItemControlRenderer'); goog.require('todomvc.view.ToDoItemControlRenderer');
/** /**
* A control representing each item in the todo list. It makes use of the CHECKED and SELECTED states to represent being * A control representing each item in the todo list. It makes use of the CHECKED and SELECTED states to represent being
* done and being in edit mode. * done and being in edit mode.
* *
* @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper, used for document interaction. * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper, used for document interaction.
* @constructor * @constructor
* @extends {goog.ui.Control} * @extends {goog.ui.Control}
*/ */
todomvc.view.ToDoItemControl = function(opt_domHelper) { todomvc.view.ToDoItemControl = function(opt_domHelper) {
goog.ui.Control.call(this, "", todomvc.view.ToDoItemControlRenderer goog.ui.Control.call(this, "", todomvc.view.ToDoItemControlRenderer
.getInstance(), opt_domHelper); .getInstance(), opt_domHelper);
// enable CHECKED and SELECTED states // enable CHECKED and SELECTED states
this.setSupportedState(goog.ui.Component.State.CHECKED, true); this.setSupportedState(goog.ui.Component.State.CHECKED, true);
this.setSupportedState(goog.ui.Component.State.SELECTED, true); this.setSupportedState(goog.ui.Component.State.SELECTED, true);
// disable auto handling of CHECKED and SELECTED states // disable auto handling of CHECKED and SELECTED states
this.setAutoStates(goog.ui.Component.State.CHECKED, false); this.setAutoStates(goog.ui.Component.State.CHECKED, false);
this.setAutoStates(goog.ui.Component.State.SELECTED, false); this.setAutoStates(goog.ui.Component.State.SELECTED, false);
// allow text selection within this control // allow text selection within this control
this.setAllowTextSelection(true); this.setAllowTextSelection(true);
}; };
goog.inherits(todomvc.view.ToDoItemControl, goog.ui.Control); goog.inherits(todomvc.view.ToDoItemControl, goog.ui.Control);
todomvc.view.ToDoItemControl.EventType = { todomvc.view.ToDoItemControl.EventType = {
EDIT: "edit", EDIT: "edit",
DESTROY: "destroy" DESTROY: "destroy"
}; };
/** /**
* Configures the component after its DOM has been rendered, and sets up event * Configures the component after its DOM has been rendered, and sets up event
* handling. Overrides {@link goog.ui.Component#enterDocument}. * handling. Overrides {@link goog.ui.Component#enterDocument}.
* *
* @override * @override
*/ */
todomvc.view.ToDoItemControl.prototype.enterDocument = function() { todomvc.view.ToDoItemControl.prototype.enterDocument = function() {
todomvc.view.ToDoItemControl.superClass_.enterDocument.call(this); todomvc.view.ToDoItemControl.superClass_.enterDocument.call(this);
// prevent clicking the checkbox (or anything within the root element) // prevent clicking the checkbox (or anything within the root element)
// from having any default behaviour. This stops the checkbox being set // from having any default behaviour. This stops the checkbox being set
// by the browser. // by the browser.
this.getHandler().listen(this.getElement(), goog.events.EventType.CLICK, this.getHandler().listen(this.getElement(), goog.events.EventType.CLICK,
function(e) { function(e) {
e.preventDefault(); e.preventDefault();
}); });
}; };
/** /**
* Returns the renderer used by this component to render itself or to decorate * Returns the renderer used by this component to render itself or to decorate
* an existing element. * an existing element.
* *
* @return {todomvc.view.ToDoItemControlRenderer} Renderer used by the component * @return {todomvc.view.ToDoItemControlRenderer} Renderer used by the component
*/ */
todomvc.view.ToDoItemControl.prototype.getRenderer = function() { todomvc.view.ToDoItemControl.prototype.getRenderer = function() {
return (/**@type {todomvc.view.ToDoItemControlRenderer}*/ this.renderer_); return (/**@type {todomvc.view.ToDoItemControlRenderer}*/ this.renderer_);
}; };
/** /**
* Specialised handling of mouse events when clicking on the checkbox, label, * Specialised handling of mouse events when clicking on the checkbox, label,
* textbox or remove link. * textbox or remove link.
* *
* @param {goog.events.Event} e Mouse event to handle. * @param {goog.events.Event} e Mouse event to handle.
*/ */
todomvc.view.ToDoItemControl.prototype.handleMouseUp = function(e) { todomvc.view.ToDoItemControl.prototype.handleMouseUp = function(e) {
todomvc.view.ToDoItemControl.superClass_.handleMouseUp.call(this, e); todomvc.view.ToDoItemControl.superClass_.handleMouseUp.call(this, e);
if (this.isEnabled()) { if (this.isEnabled()) {
if (e.target === this.getRenderer().getCheckboxElement( if (e.target === this.getRenderer().getCheckboxElement(
this.getElement())) { this.getElement())) {
this.setChecked(!this.isChecked()); this.setChecked(!this.isChecked());
this.dispatchEvent(todomvc.view.ToDoItemControl.EventType.EDIT); this.dispatchEvent(todomvc.view.ToDoItemControl.EventType.EDIT);
} else if (e.target === this.getRenderer().getDestroyElement( } else if (e.target === this.getRenderer().getDestroyElement(
this.getElement())) { this.getElement())) {
this.dispatchEvent(todomvc.view.ToDoItemControl.EventType.DESTROY); this.dispatchEvent(todomvc.view.ToDoItemControl.EventType.DESTROY);
} else if (!this.isSelected()) { } else if (!this.isSelected()) {
this.setSelected(true); this.setSelected(true);
} }
} }
}; };
/** /**
* Override the behaviour when the control is unfocused. * Override the behaviour when the control is unfocused.
* @param {boolean} focused * @param {boolean} focused
*/ */
todomvc.view.ToDoItemControl.prototype.setFocused = function(focused) { todomvc.view.ToDoItemControl.prototype.setFocused = function(focused) {
todomvc.view.ToDoItemControl.superClass_.setFocused.call(this, focused); todomvc.view.ToDoItemControl.superClass_.setFocused.call(this, focused);
if (!focused && this.isSelected()) { if (!focused && this.isSelected()) {
/** /**
* @type {Element} * @type {Element}
*/ */
var inputElement = this.getRenderer().getInputElement( var inputElement = this.getRenderer().getInputElement(
this.getElement()); this.getElement());
this.setContent(inputElement.value); this.setContent(inputElement.value);
this.setSelected(false); this.setSelected(false);
this.dispatchEvent(todomvc.view.ToDoItemControl.EventType.EDIT); this.dispatchEvent(todomvc.view.ToDoItemControl.EventType.EDIT);
} }
}; };
/** /**
* Override the behaviour to switch to editing mode when the control is selected * Override the behaviour to switch to editing mode when the control is selected
* @param {boolean} selected * @param {boolean} selected
*/ */
todomvc.view.ToDoItemControl.prototype.setSelected = function(selected) { todomvc.view.ToDoItemControl.prototype.setSelected = function(selected) {
todomvc.view.ToDoItemControl.superClass_.setSelected.call(this, selected); todomvc.view.ToDoItemControl.superClass_.setSelected.call(this, selected);
if (selected) { if (selected) {
/** /**
* @type {Element} * @type {Element}
*/ */
var inputElement = this.getRenderer().getInputElement( var inputElement = this.getRenderer().getInputElement(
this.getElement()); this.getElement());
inputElement.value = this.getContent(); inputElement.value = this.getContent();
inputElement.focus(); inputElement.focus();
} }
}; };
\ No newline at end of file
goog.provide('todomvc.view.ToDoItemControlRenderer'); goog.provide('todomvc.view.ToDoItemControlRenderer');
goog.require('goog.ui.Component.State'); goog.require('goog.ui.Component.State');
goog.require('goog.ui.ControlRenderer'); goog.require('goog.ui.ControlRenderer');
/** /**
* The renderer for the ToDoItemControl which has knowledge of the DOM structure of the Control and the applicable CSS * The renderer for the ToDoItemControl which has knowledge of the DOM structure of the Control and the applicable CSS
* classes. * classes.
* *
* @constructor * @constructor
* @extends {goog.ui.ControlRenderer} * @extends {goog.ui.ControlRenderer}
*/ */
todomvc.view.ToDoItemControlRenderer = function() { todomvc.view.ToDoItemControlRenderer = function() {
goog.ui.ControlRenderer.call(this); goog.ui.ControlRenderer.call(this);
}; };
goog.inherits(todomvc.view.ToDoItemControlRenderer, goog.ui.ControlRenderer); goog.inherits(todomvc.view.ToDoItemControlRenderer, goog.ui.ControlRenderer);
// add getInstance method to todomvc.view.ToDoItemControlRenderer // add getInstance method to todomvc.view.ToDoItemControlRenderer
goog.addSingletonGetter(todomvc.view.ToDoItemControlRenderer); goog.addSingletonGetter(todomvc.view.ToDoItemControlRenderer);
/** /**
* @param {goog.ui.Control} control Control to render. * @param {goog.ui.Control} control Control to render.
* @return {Element} Root element for the control. * @return {Element} Root element for the control.
*/ */
todomvc.view.ToDoItemControlRenderer.prototype.createDom = function(control) { todomvc.view.ToDoItemControlRenderer.prototype.createDom = function(control) {
var html = todomvc.view.toDoItem({ var html = todomvc.view.toDoItem({
content : control.getContent() content : control.getContent()
}); });
var element = (/**@type {!Element}*/ goog.dom.htmlToDocumentFragment(html)); var element = (/**@type {!Element}*/ goog.dom.htmlToDocumentFragment(html));
this.setAriaStates(control, element); this.setAriaStates(control, element);
return element; return element;
}; };
/** /**
* Updates the appearance of the control in response to a state change. * Updates the appearance of the control in response to a state change.
* *
* @param {goog.ui.Control} control Control instance to update. * @param {goog.ui.Control} control Control instance to update.
* @param {goog.ui.Component.State} state State to enable or disable. * @param {goog.ui.Component.State} state State to enable or disable.
* @param {boolean} enable Whether the control is entering or exiting the state. * @param {boolean} enable Whether the control is entering or exiting the state.
*/ */
todomvc.view.ToDoItemControlRenderer.prototype.setState = function(control, state, enable) { todomvc.view.ToDoItemControlRenderer.prototype.setState = function(control, state, enable) {
var element = control.getElement(); var element = control.getElement();
if (element) { if (element) {
switch (state) { switch (state) {
case goog.ui.Component.State.CHECKED: case goog.ui.Component.State.CHECKED:
this.enableClassName(control, "done", enable); this.enableClassName(control, "done", enable);
this.getCheckboxElement(element).checked = enable; this.getCheckboxElement(element).checked = enable;
break; break;
case goog.ui.Component.State.SELECTED: case goog.ui.Component.State.SELECTED:
this.enableClassName(control, "editing", enable); this.enableClassName(control, "editing", enable);
break; break;
} }
this.updateAriaState(element, state, enable); this.updateAriaState(element, state, enable);
} }
}; };
/** /**
* Returns the element within the component's DOM that should receive keyboard * Returns the element within the component's DOM that should receive keyboard
* focus (null if none). The default implementation returns the control's root * focus (null if none). The default implementation returns the control's root
* element. * element.
* @param {goog.ui.Control} control Control whose key event target is to be * @param {goog.ui.Control} control Control whose key event target is to be
* returned. * returned.
* @return {Element} The key event target. * @return {Element} The key event target.
*/ */
todomvc.view.ToDoItemControlRenderer.prototype.getKeyEventTarget = function(control) { todomvc.view.ToDoItemControlRenderer.prototype.getKeyEventTarget = function(control) {
return this.getInputElement(control.getElement()); return this.getInputElement(control.getElement());
}; };
/** /**
* Takes the control's root element and returns the display element * Takes the control's root element and returns the display element
* *
* @param {Element} element Root element of the control whose display element is * @param {Element} element Root element of the control whose display element is
* to be returned. * to be returned.
* @return {Element} The control's display element. * @return {Element} The control's display element.
*/ */
todomvc.view.ToDoItemControlRenderer.prototype.getDisplayElement = function( todomvc.view.ToDoItemControlRenderer.prototype.getDisplayElement = function(
element) { element) {
return element ? element.childNodes[0].childNodes[0] : null; return element ? element.childNodes[0].childNodes[0] : null;
}; };
/** /**
* Takes the control's root element and returns the parent element of the * Takes the control's root element and returns the parent element of the
* control's contents. * control's contents.
* *
* @param {Element} element Root element of the control whose content element is * @param {Element} element Root element of the control whose content element is
* to be returned. * to be returned.
* @return {Element} The control's content element. * @return {Element} The control's content element.
*/ */
todomvc.view.ToDoItemControlRenderer.prototype.getContentElement = function( todomvc.view.ToDoItemControlRenderer.prototype.getContentElement = function(
element) { element) {
return element ? this.getDisplayElement(element).childNodes[1] : null; return element ? this.getDisplayElement(element).childNodes[1] : null;
}; };
/** /**
* Takes the control's root element and returns the checkbox element * Takes the control's root element and returns the checkbox element
* *
* @param {Element} element Root element of the control whose checkbox element * @param {Element} element Root element of the control whose checkbox element
* is to be returned. * is to be returned.
* @return {Element} The control's checkbox element. * @return {Element} The control's checkbox element.
*/ */
todomvc.view.ToDoItemControlRenderer.prototype.getCheckboxElement = function( todomvc.view.ToDoItemControlRenderer.prototype.getCheckboxElement = function(
element) { element) {
return element ? this.getDisplayElement(element).childNodes[0] : null; return element ? this.getDisplayElement(element).childNodes[0] : null;
}; };
/** /**
* Takes the control's root element and returns the destroy element * Takes the control's root element and returns the destroy element
* *
* @param {Element} element Root element of the control whose destroy element is * @param {Element} element Root element of the control whose destroy element is
* to be returned. * to be returned.
* @return {Element} The control's destroy element. * @return {Element} The control's destroy element.
*/ */
todomvc.view.ToDoItemControlRenderer.prototype.getDestroyElement = function( todomvc.view.ToDoItemControlRenderer.prototype.getDestroyElement = function(
element) { element) {
return element ? this.getDisplayElement(element).childNodes[2] : null; return element ? this.getDisplayElement(element).childNodes[2] : null;
}; };
/** /**
* Takes the control's root element and returns the input element * Takes the control's root element and returns the input element
* *
* @param {Element} element Root element of the control whose input element is * @param {Element} element Root element of the control whose input element is
* to be returned. * to be returned.
* @return {Element} The control's input element. * @return {Element} The control's input element.
*/ */
todomvc.view.ToDoItemControlRenderer.prototype.getInputElement = function( todomvc.view.ToDoItemControlRenderer.prototype.getInputElement = function(
element) { element) {
return element ? element.childNodes[0].childNodes[1].childNodes[0] : null; return element ? element.childNodes[0].childNodes[1].childNodes[0] : null;
}; };
goog.provide('todomvc.view.ToDoListContainer'); goog.provide('todomvc.view.ToDoListContainer');
goog.require('goog.ui.Container'); goog.require('goog.ui.Container');
goog.require('todomvc.view.ToDoListContainerRenderer'); goog.require('todomvc.view.ToDoListContainerRenderer');
/** /**
* A container for the ToDoItemControls, overridden to support keyboard focus on child controls. * A container for the ToDoItemControls, overridden to support keyboard focus on child controls.
* *
* @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper, used for document interaction. * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper, used for document interaction.
* @constructor * @constructor
* @extends {goog.ui.Container} * @extends {goog.ui.Container}
*/ */
todomvc.view.ToDoListContainer = function(opt_domHelper) { todomvc.view.ToDoListContainer = function(opt_domHelper) {
goog.ui.Container goog.ui.Container
.call(this, goog.ui.Container.Orientation.VERTICAL, .call(this, goog.ui.Container.Orientation.VERTICAL,
todomvc.view.ToDoListContainerRenderer.getInstance(), todomvc.view.ToDoListContainerRenderer.getInstance(),
opt_domHelper); opt_domHelper);
// allow focus on children // allow focus on children
this.setFocusable(false); this.setFocusable(false);
this.setFocusableChildrenAllowed(true); this.setFocusableChildrenAllowed(true);
}; };
goog.inherits(todomvc.view.ToDoListContainer, goog.ui.Container); goog.inherits(todomvc.view.ToDoListContainer, goog.ui.Container);
/** /**
* Override this method to allow text selection in children. * Override this method to allow text selection in children.
* *
* @param {goog.events.BrowserEvent} e Mousedown event to handle. * @param {goog.events.BrowserEvent} e Mousedown event to handle.
*/ */
todomvc.view.ToDoListContainer.prototype.handleMouseDown = function(e) { todomvc.view.ToDoListContainer.prototype.handleMouseDown = function(e) {
if (this.enabled_) { if (this.enabled_) {
this.setMouseButtonPressed(true); this.setMouseButtonPressed(true);
} }
}; };
\ No newline at end of file
goog.provide('todomvc.view.ToDoListContainerRenderer'); goog.provide('todomvc.view.ToDoListContainerRenderer');
goog.require('goog.ui.Component.State'); goog.require('goog.ui.Component.State');
goog.require('goog.ui.Container'); goog.require('goog.ui.Container');
goog.require('goog.ui.ContainerRenderer'); goog.require('goog.ui.ContainerRenderer');
/** /**
* A renderer for the container, overridden to support keyboard focus on child controls. * A renderer for the container, overridden to support keyboard focus on child controls.
* @constructor * @constructor
* @extends {goog.ui.ContainerRenderer} * @extends {goog.ui.ContainerRenderer}
*/ */
todomvc.view.ToDoListContainerRenderer = function() { todomvc.view.ToDoListContainerRenderer = function() {
goog.ui.ContainerRenderer.call(this); goog.ui.ContainerRenderer.call(this);
}; };
goog.inherits(todomvc.view.ToDoListContainerRenderer, goog.inherits(todomvc.view.ToDoListContainerRenderer,
goog.ui.ContainerRenderer); goog.ui.ContainerRenderer);
goog.addSingletonGetter(todomvc.view.ToDoListContainerRenderer); goog.addSingletonGetter(todomvc.view.ToDoListContainerRenderer);
/** /**
* @param {Element} element Element to decorate. * @param {Element} element Element to decorate.
* @return {boolean} Whether the renderer can decorate the element. * @return {boolean} Whether the renderer can decorate the element.
*/ */
todomvc.view.ToDoListContainerRenderer.prototype.canDecorate = function(element) { todomvc.view.ToDoListContainerRenderer.prototype.canDecorate = function(element) {
return element.tagName == 'UL'; return element.tagName == 'UL';
}; };
/** /**
* Override this method to allow text selection in children * Override this method to allow text selection in children
* *
* @param {goog.ui.Container} container Container whose DOM is to be initialized * @param {goog.ui.Container} container Container whose DOM is to be initialized
* as it enters the document. * as it enters the document.
*/ */
todomvc.view.ToDoListContainerRenderer.prototype.initializeDom = function(container) { todomvc.view.ToDoListContainerRenderer.prototype.initializeDom = function(container) {
var elem = (/**@type {!Element}*/ container.getElement()); var elem = (/**@type {!Element}*/ container.getElement());
// Set the ARIA role. // Set the ARIA role.
var ariaRole = this.getAriaRole(); var ariaRole = this.getAriaRole();
if (ariaRole) { if (ariaRole) {
goog.dom.a11y.setRole(elem, ariaRole); goog.dom.a11y.setRole(elem, ariaRole);
} }
}; };
\ No newline at end of file
{namespace todomvc.view} {namespace todomvc.view}
/** /**
* A todo list item template * A todo list item template
* @param content the label for this item * @param content the label for this item
*/ */
{template .toDoItem} {template .toDoItem}
<li> <li>
<div> <div>
<div class="display"> <div class="display">
<input class="check" type="checkbox" /> <input class="check" type="checkbox" />
<div class="todo-content" style="cursor: pointer;">{$content}</div> <div class="todo-content" style="cursor: pointer;">{$content}</div>
<span class="todo-destroy"></span> <span class="todo-destroy"></span>
</div> </div>
<div class="edit"> <div class="edit">
<input class="todo-input" type="text"/> <input class="todo-input" type="text"/>
</div> </div>
</div> </div>
</li> </li>
{/template} {/template}
/** /**
* A todo list item count template * A todo list item count template
* @param number the count of items * @param number the count of items
*/ */
{template .itemCount} {template .itemCount}
<span class="todo-count"> <span class="todo-count">
{call .itemCountInner data="all"/} {call .itemCountInner data="all"/}
</span> </span>
{/template} {/template}
/** /**
* A todo list item count template * A todo list item count template
* @param number the count of items * @param number the count of items
*/ */
{template .itemCountInner} {template .itemCountInner}
<span class="number">{$number}</span> <span class="word">{if $number > 1}items{else}item{/if}</span> left. <span class="number">{$number}</span> <span class="word">{if $number > 1}items{else}item{/if}</span> left.
{/template} {/template}
/** /**
* A todo list clear completed template * A todo list clear completed template
* @param number the count of items * @param number the count of items
*/ */
{template .clearCompleted} {template .clearCompleted}
<span class="todo-clear"> <span class="todo-clear">
{call .clearCompletedInner data="all"/} {call .clearCompletedInner data="all"/}
</span> </span>
{/template} {/template}
/** /**
* A todo list clear completed template * A todo list clear completed template
* @param number the count of items * @param number the count of items
*/ */
{template .clearCompletedInner} {template .clearCompletedInner}
<a href="#"> <a href="#">
Clear <span class="number-done">{$number}</span> <span class="word-done">{if $number > 1}items{else}item{/if}</span> Clear <span class="number-done">{$number}</span> <span class="word-done">{if $number > 1}items{else}item{/if}</span>
</a> </a>
{/template} {/template}
\ No newline at end of file
{ {
"id" : "todomvc", "id" : "todomvc",
"inputs" : "js/main.js", "inputs" : "js/main.js",
"paths" : "js/", "paths" : "js/",
"output-wrapper" : "(function(){%output%})();", "output-wrapper" : "(function(){%output%})();",
"mode" : "ADVANCED", "mode" : "ADVANCED",
"define" : { "define" : {
"goog.LOCALE": "en_GB" "goog.LOCALE": "en_GB"
}, },
"checks": { "checks": {
// Unfortunately, the Closure Library violates these in many places. // Unfortunately, the Closure Library violates these in many places.
// "accessControls": "ERROR", // "accessControls": "ERROR",
// "visibility": "ERROR" // "visibility": "ERROR"
"checkRegExp": "WARNING", "checkRegExp": "WARNING",
"checkTypes": "WARNING", "checkTypes": "WARNING",
"checkVars": "WARNING", "checkVars": "WARNING",
"deprecated": "WARNING", "deprecated": "WARNING",
"fileoverviewTags": "WARNING", "fileoverviewTags": "WARNING",
"invalidCasts": "WARNING", "invalidCasts": "WARNING",
"missingProperties": "WARNING", "missingProperties": "WARNING",
"nonStandardJsDocs": "WARNING", "nonStandardJsDocs": "WARNING",
"undefinedVars": "WARNING" "undefinedVars": "WARNING"
} }
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment