<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" type="text/css" href="https://unpkg.com/todomvc-app-css@2.0.6/index.css">
  <style>
    [v-cloak] {  display: none; }
  </style>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.39/system.js"></script>
  <script src="config.js"></script>
  <script>
    System.import('app').catch(console.log.bind(console));
  </script>
</head>

<body>
  <div id="app" v-cloak>
    <section class="todoapp">
      <header class="header">
        <h1>todos</h1>
        <input class="new-todo" placeholder="What needs to be done?" autofocus v-model="newTodoTitle" @keyup.enter="addTodo">
      </header>
      <!-- This section should be hidden by default and shown when there are todos -->
      <section class="main" v-show="anyTodo" v-cloak>
        <input class="toggle-all" type="checkbox" v-model="allDone">
        <label for="toggle-all">Mark all as complete</label>
        <ul class="todo-list">
          <!-- These are here just to show the structure of the list items -->
          <!-- List items should get the class `editing` when editing and `completed` when marked as completed -->
          <li class="todo" v-for="todo in filteredTodo" :class="{completed: todo.completed, editing: todo.editing}">
            <div class="view">
              <input class="toggle" type="checkbox" v-model="todo.completed">
              <label @dblclick="editTodo(todo)">{{todo.title}}</label>
              <button class="destroy" @click="removeTodo(todo)"></button>
            </div>
            <input class="edit" type="text" v-model="todo.title" v-todo-focus="todo.editing" @blur="doneEdit(todo)" @keyup.enter="doneEdit(todo)" @keyup.esc="cancelEdit(todo)">
          </li>
        </ul>
      </section>
      <!-- This footer should hidden by default and shown when there are todos -->
      <footer class="footer" v-show="anyTodo" v-cloak>
        <!-- This should be `0 items left` by default -->
        <span class="todo-count"><strong>{{ remaining }}</strong> {{ remaining | pluralize }} left</span>
        <ul class="filters">
          <li><a href="#/all" :class="{ selected: visibility == 'all' }">All</a></li>
          <li><a href="#/active" :class="{ selected: visibility == 'active' }">Active</a></li>
          <li><a href="#/completed" :class="{ selected: visibility == 'completed' }">Completed</a></li>
        </ul>
        <button class="clear-completed" @click="clearCompleted" v-show="todos.length > remaining">Clear completed</button>
      </footer>
    </section>
    <footer class="info">
      <p>Double-click to edit a todo</p>
      <p>Created by <a href="https://github.com/budiadiono/vue-typed">Budi Adiono</a></p>
      <p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
    </footer>
  </div>
</body>


</html>
#VueTyped - Example - Todo MVC

Example write Todo MVC application using `vue` with `vue-typed`.
System.config({
  defaultJSExtensions: true,
  transpiler: 'typescript',
  typescriptOptions: {
    emitDecoratorMetadata: true
  },
  map: {
    'vue': 'https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.min.js',
    'vue-typed': 'https://cdn.rawgit.com/vue-typed/vue-typed/dev/index.js',
    'typescript': 'https://raw.githubusercontent.com/Microsoft/TypeScript/master/lib/typescript.js',
  },
  packages: {
    app: {
      main: 'index.ts',
      defaultExtension: 'ts',
    }
  }
});
import { App } from './app';


var app = new App();

// handle routing
function onHashChange () {
  app.visibility = window.location.hash.replace(/#\/?/, '') || 'all'
}
window.addEventListener('hashchange', onHashChange)
onHashChange()

app.$mount('#app');
import { Storage } from './storage';

/**
 * Todo Data Model
 */
export class Todo {

	constructor(title: string) {
		this.id = Storage.uid++;
		this.title = title;
		this.completed = false;
		this.editing = false;
	}

	id: number
	title: string
	completed: boolean
	editing: boolean
	
}
import { Todo } from './todo';

// localStorage persistence
var STORAGE_KEY = 'todos-vue-typed-vuejs-2.0'


/**
 * Storage class
 */
export class Storage {
	static uid: number

	static fetch() {
		var todos = <Todo[]> JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]')
    todos.forEach(function (todo, index) {
      todo.id = index
    })
    this.uid = todos.length
    return todos
	}

	static save(todos: Todo[]) {
		localStorage.setItem(STORAGE_KEY, JSON.stringify(todos))
	}
}
import Vue from 'vue'
import { Component, Watch } from 'vue-typed';
import { Todo } from './todo';
import { Storage } from './storage';
import { Utils } from './utils'


@Component({
	directives: {
		'todo-focus': function (el, binding) {

			var value = binding.value;

			if (!value) {
				return;
			}

			Vue.nextTick(function () {
				el.focus();
			});
		}
	},

	filters: {
    pluralize: function (n) {
      return n === 1 ? 'item' : 'items'
    }
  },
})
export class App {
  
	newTodoTitle: string = ''

	oldTodoTitle: string = ''

	visibility: string = 'all'

	todos: Todo[] = Storage.fetch()

	@Watch('todos', true)
	onTodoChange(todos: Todo[]) {
		Storage.save(todos)
	}

	get filteredTodo() {
		return Utils.filter(this.visibility, this.todos);
	}

	get anyTodo(): boolean {
		return this.todos.length > 0;
	}

	addTodo() {
		this.todos.push(new Todo(this.newTodoTitle));
		this.newTodoTitle = '';
	}

	editTodo(todo: Todo) {
		this.oldTodoTitle = todo.title;
		todo.editing = true;
	}

	doneEdit(todo: Todo) {
		todo.editing = false;
	}

	cancelEdit(todo: Todo) {
		todo.title = this.oldTodoTitle;
		todo.editing = false;
	}

	removeTodo(todo: Todo) {
		this.todos.splice(this.todos.indexOf(todo), 1);
	}

	clearCompleted() {
		this.allDone = false;
	}

	get remaining(): number {
		var remaining = this.todos.filter(function (todo) {
			return !todo.completed;
		});

		return remaining.length;
	}

	get allDone(): boolean {
		return this.remaining == 0;
	}

	set allDone(value: boolean) {
		this.todos.forEach(function (todo) {
			todo.completed = value;
		});
	}

}
import { Todo } from './Todo';

/**
 * Utility class
 */
export static class Utils {
	static filter(state: any, todos: Todo[]): Todo[] {

		switch (state) {
			case 'active':
				return todos.filter(function (todo) {
					return !todo.completed
				});

			case 'completed': {
				return todos.filter(function (todo) {
					return todo.completed
				});
			}
		}

		return todos;
		
	}
}