JSFiddle - React, Tailwind, and code Playground

by elcoyote67

HTML

<script type="text/x-handlebars" data-template-name="todo-item">
{{#if isEditing}}
  {{view Ember.TextField class="editing" valueBinding="toDoText"}}
  <a href="#" class="action" {{action "cancel"}}>Cancel</a>
  <a href="#" class="action" {{action "update"}}>Update</a>
{{else}}
  {{view Ember.Checkbox class="complete" checkedBinding="content.completed"}}
  <span class="item">{{toDoText}}</span>
  <a href="#" class="action" {{action "remove"}}>Remove</a>
  <a href="#" class="action" {{action "edit"}}>Edit</a>
{{/if}}
</script>

<script type="text/x-handlebars">
  <h1>Another Ember.js ToDo App</h1>
  <button {{action "addToDo" target="ToDoApp.toDoListController"}}>Add another ToDo item</button>
  <span class="remaining">{{ToDoApp.toDoListController.remaining}} items remaining</span>
  <ul>
    {{#each ToDoApp.toDoListController.todos}}
      {{view ToDoApp.TodoItemView contentBinding="this"}}
    {{/each}}
  </ul>
</script>

CSS

ul {
  background: lightgray;
  padding: 5px;
}

li {
  padding: 10px 20px;
  margin: 5px 20px;
  border-radius: 5px;
  background: #444;
  color: white;
  font: 1.3em sans-serif;
}

input.complete {
  margin-right: 10px;
}

span.item {
  text-shadow: 1px 0 3px black;
  position: absolute;
  left: 70px;
  right: 180px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.completed span.item {
  text-decoration: line-through;
}

a.action {
  float: right;
  margin-left: 10px;
  text-decoration: none;
  color: orange;
}

a.action:hover {
  text-decoration: underline;
  color: orangered;
}

h1 {
  font: 2.1em sans-serif;
  padding: 10px;
  margin-bottom: 10px;
}

button {
  margin: 10px;
}

input.editing {
  width: 65%;
}

span.remaining {
  position: absolute;
  right: 16px; 
  top: 78px;    
}

JavaScript

window.ToDoApp = Ember.Application.create();

ToDoApp.ToDo = Ember.Object.extend({
  // Data
  completed: false,
  toDoText: 'Edit this ToDo item'
});

ToDoApp.toDoListController = Ember.Object.create({
  // Data
  todos: [
    { toDoText: 'Step one: Create great ToDos App', completed: true },
    { toDoText: 'Step two: ???' },
    { toDoText: 'Step three: Profit' }
  ].map(function(item) { return ToDoApp.ToDo.create(item); }),
  
  remaining: function() {
    var todos = this.get('todos');
    return todos.filterProperty('completed', false).get('length');
  }.property('[email protected]'),
  
  // Operations
  addToDo: function() {
    this.get('todos').pushObject(ToDoApp.ToDo.create());
  },
    
  removeToDo: function(obj) {
    this.get('todos').removeObject(obj);
  }
});

ToDoApp.TodoItemView = Ember.View.extend({
  templateName: 'todo-item',
  tagName: 'li',
  classNameBindings: ['content.completed:completed'],
  
  isEditing: false,
  modelTextBinding: 'content.toDoText',

  toDoText: function(key, value) {
    if (!Ember.none(value)) {
      this._editingText = value;
    }
    return this.get('isEditing') ? this._editingText : this.get('modelText');
  }.property('isEditing', 'modelText'),
  
  // Operations
  edit: function() {
    this._editingText = this.get('modelText');
    this.set('isEditing', true);
  },
  
  remove: function() {
    ToDoApp.toDoList.removeToDo(this.get('content'));
  },
    
  update: function() {
    this.set('modelText', this._editingText);
    this.set('isEditing', false);
  },
    
  cancel: function() {
    this.set('isEditing', false);
  }
});