├── .gitignore ├── Buildfile ├── README └── apps └── todos ├── resources ├── stylesheets │ ├── todos.css │ └── todos_mobile.css └── templates │ └── todos.handlebars └── todos.js /.gitignore: -------------------------------------------------------------------------------- 1 | tmp 2 | .bundle 3 | 4 | -------------------------------------------------------------------------------- /Buildfile: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # Project: Todos 3 | # Copyright: ©2011 My Company, Inc. 4 | # =========================================================================== 5 | 6 | # Add initial buildfile information here 7 | config :all, :required => "sproutcore/core_foundation", :theme => "sproutcore/empty_theme" 8 | 9 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ============================================================================= 2 | Project: Todos 3 | Copyright: ©2011 My Company, Inc. 4 | ============================================================================= 5 | 6 | Todos application. 7 | 8 | To learn how to build this app, visit: 9 | 10 | http://guides.sproutcore.com/html_based.html 11 | -------------------------------------------------------------------------------- /apps/todos/resources/stylesheets/todos.css: -------------------------------------------------------------------------------- 1 | @import "compass/css3"; 2 | @import "compass/reset"; 3 | 4 | /* CSS Reset */ 5 | @include global-reset; 6 | 7 | body { 8 | line-height: 1; 9 | font-family: "Lucida Grande", sans-serif; 10 | font-size: 13px; 11 | } 12 | ol, ul { 13 | list-style: none; 14 | } 15 | blockquote, q { 16 | quotes: none; 17 | } 18 | blockquote:before, blockquote:after, 19 | q:before, q:after { 20 | content: ''; 21 | content: none; 22 | } 23 | table { 24 | border-collapse: collapse; 25 | border-spacing: 0; 26 | } 27 | 28 | /* App CSS */ 29 | body, html { 30 | color: #777; 31 | background-color: #F2F4F5; 32 | } 33 | 34 | .sc-view { 35 | position: relative; 36 | overflow: visible; 37 | } 38 | 39 | $width: 600px; 40 | $border: 1px solid #bbb; 41 | 42 | #todos { 43 | @include box-shadow(rgba(0,0,0,0.6) 0 0 1px); 44 | @include border-radius(8px); 45 | 46 | $padding: 10px; 47 | $header-height: 20px; 48 | 49 | position: absolute; 50 | width: $width; 51 | left: 50%; 52 | margin-top: 38px; 53 | border: $border; 54 | margin-left: -300px; 55 | background-color: #fff; 56 | padding: ($header-height + $padding * 2) $padding $padding; 57 | 58 | .mark-all-done label { 59 | margin-left: 5px; 60 | font-weight: bold; 61 | } 62 | 63 | #stats { 64 | overflow: hidden; 65 | width: 100%; 66 | padding: 5px $padding; 67 | margin: $padding ($padding * -1); 68 | background-color: #eee; 69 | border-top: 1px solid #aaa; 70 | border-bottom: 1px solid #aaa; 71 | line-height: 25px; 72 | 73 | .remaining { 74 | float: left; 75 | } 76 | 77 | .sc-button { 78 | @include background-image(linear-gradient(#F9F9F9 1%, #DDD, #F2F2F2, #F7F7F7)); 79 | border: 1px solid #828282; 80 | color: #000; 81 | float: right; 82 | padding: 0 5px; 83 | 84 | &:hover { 85 | @include background-image(linear-gradient(#FFF 1%, #E2E2E2, #F7F7F7, #FCFCFC)); 86 | } 87 | 88 | &.is-active { 89 | @include background-image(linear-gradient(#EFEFEF 1%, #D3D3D3, #E8E8E8, #EDEDED)); 90 | } 91 | } 92 | } 93 | 94 | input[type='text'] { 95 | @include border-radius(5px); 96 | @include single-box-shadow(rgba(0,0,0,0.6), 0, 0, 10px, -2px); 97 | color: #999; 98 | background-color: rgb(240,240,240); 99 | width: $width - ($padding) - 2px; 100 | font-size: 30px; 101 | font-family: Helvetica, sans-serif; 102 | padding: 5px; 103 | border: $border; 104 | font-weight: 500; 105 | 106 | &::-webkit-input-placeholder { 107 | color: #aaa; 108 | } 109 | } 110 | 111 | h1 { 112 | @include border-top-radius(8px); 113 | @include background-image(linear-gradient(color-stops(white, rgb(244,244,244) 49%, rgb(237,237,237) 51%, #dedede))); 114 | @include single-text-shadow(white, 0, 1px, 1px); 115 | 116 | font-size: 15px; 117 | position: absolute; 118 | width: $width; 119 | height: $header-height; 120 | color: rgb(83,86,94); 121 | top: 0; 122 | left: 0; 123 | padding: ($padding / 2) $padding; 124 | border-bottom: $border; 125 | } 126 | 127 | .sc-checkbox { 128 | input[type="checkbox"] { 129 | margin-right: 7px; 130 | } 131 | } 132 | 133 | ul { 134 | margin: 10px 0 2px 0; 135 | 136 | li { 137 | padding: 5px; 138 | 139 | &.is-done { 140 | color: #B7B7B7; 141 | text-decoration: line-through; 142 | } 143 | } 144 | 145 | li:nth-child(odd) { 146 | background-color: #F7F7F7; 147 | } 148 | } 149 | } 150 | 151 | -------------------------------------------------------------------------------- /apps/todos/resources/stylesheets/todos_mobile.css: -------------------------------------------------------------------------------- 1 | /* Using media queries to override the default styling and target "mobile" devices */ 2 | @media only screen and (max-device-width: 768px) { 3 | body, html { 4 | color: #5B5B5B; 5 | background-color: #FFF; 6 | } 7 | 8 | #todos { 9 | @include border-radius(0); 10 | border-style: none; 11 | left: 0; 12 | margin-left: 0; 13 | margin-top: 0; 14 | padding: 0; 15 | top: 0; 16 | width: auto; 17 | right: 0; 18 | 19 | #stats { 20 | font-size: 16px; 21 | line-height: 40px; 22 | margin: 10px 0; 23 | padding: 5px 5px 5px 10px; 24 | width: auto; 25 | 26 | .sc-button { 27 | @include border-radius(5px); 28 | float: right; 29 | font-size: 11px; 30 | line-height: 15px; 31 | padding: 5px; 32 | text-align: center; 33 | text-shadow: rgba(255,255,255, 1.0) 0px -1px 2px; 34 | width: 100px; 35 | } 36 | } 37 | 38 | .sc-checkbox { 39 | font-size: 16px; 40 | margin-left: 10px; 41 | 42 | input[type='checkbox'] { 43 | position: relative; 44 | top: 5px; 45 | } 46 | } 47 | 48 | input[type='text'] { 49 | display: block; 50 | font-size: 24px; 51 | margin-right: auto; 52 | margin-top: 10px; 53 | margin-bottom: 10px; 54 | margin-left: auto; 55 | width: 94%; 56 | } 57 | 58 | h1 { 59 | position: relative; 60 | width: auto; 61 | } 62 | 63 | input[type='checkbox'] { 64 | width: 28px; 65 | height: 28px; 66 | } 67 | 68 | input.mark-all-done { 69 | margin-bottom: 10px; 70 | margin-top: 10px; 71 | } 72 | 73 | ul { 74 | 75 | li { 76 | display: block; 77 | height: 38px; 78 | line-height: 18px; 79 | 80 | .sc-checkbox { 81 | 82 | input[type='checkbox'] { 83 | margin-right: 12px; 84 | } 85 | } 86 | } 87 | 88 | li.is-done { 89 | text-decoration: none; 90 | } 91 | } 92 | } 93 | } 94 | 95 | /* small screen portrait */ 96 | @media only screen and (device-width: 320px) and (orientation:portrait) { 97 | #todos { 98 | } 99 | } 100 | 101 | /* small screen landscape */ 102 | @media only screen and (device-width: 320px) and (orientation:landscape) { 103 | #todos { 104 | } 105 | } 106 | 107 | /* medium screen any orientation */ 108 | @media only screen and (device-width: 768px) { 109 | #todos { 110 | 111 | #stats { 112 | font-size: 20px; 113 | line-height: 38px; 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /apps/todos/resources/templates/todos.handlebars: -------------------------------------------------------------------------------- 1 |

Todos

2 | {{#view Todos.CreateTodoView}} 3 | 4 | {{/view}} 5 | 6 | {{#view Todos.StatsView id="stats"}} 7 | {{#view SC.Button classBinding="isActive" target="Todos.todoListController" action="clearCompletedTodos"}} 8 | Clear Completed Todos 9 | {{/view}} 10 | {{displayRemaining}} remaining. 11 | {{/view}} 12 | 13 | {{view SC.Checkbox class="mark-all-done" title="Mark All as Done" valueBinding="Todos.todoListController.allAreDone"}} 14 | 15 | {{#collection SC.TemplateCollectionView contentBinding="Todos.todoListController" itemClassBinding="content.isDone"}} 16 | {{view Todos.MarkDoneView}} 17 | {{/collection}} 18 | -------------------------------------------------------------------------------- /apps/todos/todos.js: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Project: Todos 3 | // Copyright: ©2011 My Company, Inc. 4 | // ========================================================================== 5 | 6 | /*globals Todos*/ 7 | 8 | Todos = SC.Application.create(); 9 | 10 | Todos.Todo = SC.Object.extend({ title: null, isDone: false }); 11 | 12 | Todos.CreateTodoView = SC.TextField.extend({ 13 | insertNewline: function() { 14 | var value = this.get('value'); 15 | 16 | if (value) { 17 | Todos.todoListController.createTodo(value); 18 | this.set('value', ''); 19 | } 20 | } 21 | }); 22 | 23 | Todos.MarkDoneView = SC.Checkbox.extend({ 24 | titleBinding: '.parentView.content.title', 25 | valueBinding: '.parentView.content.isDone' 26 | }); 27 | 28 | Todos.StatsView = SC.TemplateView.extend({ 29 | remainingBinding: 'Todos.todoListController.remaining', 30 | 31 | displayRemaining: function() { 32 | var remaining = this.get('remaining'); 33 | return remaining + (remaining === 1 ? " item" : " items"); 34 | }.property('remaining').cacheable() 35 | }); 36 | 37 | Todos.todoListController = SC.ArrayController.create({ 38 | // Initialize the array controller with an empty array. 39 | content: [], 40 | 41 | // Creates a new todo with the passed title, then adds it 42 | // to the array. 43 | 44 | createTodo: function(title) { 45 | var todo = Todos.Todo.create({ title: title }); 46 | 47 | this.pushObject(todo); 48 | }, 49 | 50 | remaining: function() { 51 | return this.filterProperty('isDone', false).get('length'); 52 | }.property('@each.isDone'), 53 | 54 | clearCompletedTodos: function() { 55 | this.filterProperty('isDone', true).forEach(this.removeObject, this); 56 | }, 57 | 58 | allAreDone: function(key, value) { 59 | if (value !== undefined) { 60 | this.setEach('isDone', value); 61 | 62 | return value; 63 | } else { 64 | return this.get('length') && this.everyProperty('isDone', true); 65 | } 66 | }.property('@each.isDone') 67 | 68 | }); 69 | 70 | SC.ready(function() { 71 | Todos.mainPane = SC.TemplatePane.append({ 72 | layerId: 'todos', 73 | templateName: 'todos' 74 | }); 75 | }); 76 | 77 | --------------------------------------------------------------------------------