22 |
30 |
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/todomvc/choo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | choo • TodoMVC
7 |
8 |
9 |
14 |
15 |
16 |
17 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/todomvc/vanilla-es6/src/app.js:
--------------------------------------------------------------------------------
1 | import Controller from './controller';
2 | import * as helpers from './helpers';
3 | import Template from './template';
4 | import Store from './store';
5 | import Model from './model';
6 | import View from './view';
7 |
8 | const $on = helpers.$on;
9 | const setView = () => todo.controller.setView(document.location.hash);
10 |
11 | class Todo {
12 | /**
13 | * Init new Todo List
14 | * @param {string} The name of your list
15 | */
16 | constructor(name) {
17 | this.storage = new Store(name);
18 | this.model = new Model(this.storage);
19 |
20 | this.template = new Template();
21 | this.view = new View(this.template);
22 |
23 | this.controller = new Controller(this.model, this.view);
24 | }
25 | }
26 |
27 | const todo = new Todo('todos-vanillajs');
28 |
29 | $on(window, 'load', setView);
30 | $on(window, 'hashchange', setView);
31 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todomvc-perf-comparison",
3 | "version": "0.0.1",
4 | "description": "Speed FTW",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "opener http://localhost:3000 && http-server -p 3000",
8 | "deploy": "gh-pages -d .",
9 | "test": "echo \"Error: no test specified\" && exit 1"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/rabbots/todomvc-perf-comparison.git"
14 | },
15 | "keywords": [
16 | "pref",
17 | "speed",
18 | "todomvc"
19 | ],
20 | "author": "katopz",
21 | "license": "MIT",
22 | "bugs": {
23 | "url": "https://github.com/rabbots/todomvc-perf-comparison/issues"
24 | },
25 | "homepage": "https://github.com/rabbots/todomvc-perf-comparison#readme",
26 | "devDependencies": {
27 | "gh-pages": "^0.11.0",
28 | "http-server": "^0.9.0",
29 | "opener": "^1.4.1"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/mithril/deploy/cdnjs-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mithril",
3 | "npmName": "mithril",
4 | "version": "$version",
5 | "filename": "mithril.min.js",
6 | "description": "A Javascript Framework for building brilliant applications",
7 | "homepage": "http://lhorie.github.io/mithril",
8 | "license": "MIT",
9 | "main": "mithril",
10 | "keywords": [
11 | "mvc",
12 | "browser"
13 | ],
14 | "author": "Leo Horie (http://lhorie.blogspot.com/)",
15 | "contributors": [
16 | "Leo Horie (http://lhorie.blogspot.com/)"
17 | ],
18 | "bugs": "https://github.com/lhorie/mithril.js/issues",
19 | "repository": {
20 | "type": "git",
21 | "url": "https://github.com/lhorie/mithril.js.git"
22 | },
23 | "npmFileMap": [
24 | {
25 | "basePath": "/",
26 | "files": [
27 | "mithril.js",
28 | "mithril.min.js",
29 | "mithril.min.map"
30 | ]
31 | }
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/todomvc/preact/src/footer.js:
--------------------------------------------------------------------------------
1 | import { h, Component } from 'preact';
2 | import { pluralize } from './util';
3 |
4 | const ALL_TODOS = 'all';
5 | const ACTIVE_TODOS = 'active';
6 | const COMPLETED_TODOS = 'completed';
7 |
8 | export default ({ nowShowing, count, completedCount, onClearCompleted }) => (
9 |
32 | );
33 |
--------------------------------------------------------------------------------
/todomvc/react/todomvc-app-css/readme.md:
--------------------------------------------------------------------------------
1 | # todomvc-app-css
2 |
3 | > CSS for TodoMVC apps
4 |
5 | 
6 |
7 |
8 | ## Install
9 |
10 |
11 | ```
12 | $ npm install --save todomvc-app-css
13 | ```
14 |
15 |
16 | ## Getting started
17 |
18 | ```html
19 |
20 | ```
21 |
22 | See the [TodoMVC app template](https://github.com/tastejs/todomvc-app-template).
23 |
24 |
25 |
26 | ## License
27 |
28 | This work by Sindre Sorhus is licensed under a Creative Commons Attribution 4.0 International License.
29 |
--------------------------------------------------------------------------------
/todomvc/vue/readme.md:
--------------------------------------------------------------------------------
1 | # Vue.js TodoMVC Example
2 |
3 | > Vue.js is a library for building interactive web interfaces.
4 | It provides data-driven, nestable view components with a simple and flexible API.
5 |
6 | > _[Vue.js - vuejs.org](http://vuejs.org)_
7 |
8 | ## Learning Vue.js
9 |
10 | The [Vue.js website](http://vuejs.org/) is a great resource to get started.
11 |
12 | Here are some links you may find helpful:
13 |
14 | * [Official Guide](http://vuejs.org/guide/)
15 | * [API Reference](http://vuejs.org/api/)
16 | * [Examples](http://vuejs.org/examples/)
17 | * [Building Larger Apps with Vue.js](http://vuejs.org/guide/application.html)
18 |
19 | Get help from other Vue.js users:
20 |
21 | * [Vue.js on Twitter](https://twitter.com/vuejs)
22 | * [Vue.js on Gitter](https://gitter.im/vuejs/vue)
23 | * [Vue.js Forum](http://forum.vuejs.org)
24 |
25 | _If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._
26 |
27 | ## Credit
28 |
29 | This TodoMVC application was created by [Evan You](http://evanyou.me).
30 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014 Matt Esch.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/todomvc/emberjs/js/router.js:
--------------------------------------------------------------------------------
1 | /*global Ember, Todos */
2 | 'use strict';
3 |
4 | Todos.Router.map(function () {
5 | this.resource('todos', { path: '/' }, function () {
6 | this.route('active');
7 | this.route('completed');
8 | });
9 | });
10 |
11 | Todos.TodosRoute = Ember.Route.extend({
12 | model: function () {
13 | return this.store.find('todo');
14 | }
15 | });
16 |
17 | Todos.TodosIndexRoute = Ember.Route.extend({
18 | setupController: function () {
19 | this.controllerFor('todos').set('filteredTodos', this.modelFor('todos'));
20 | }
21 | });
22 |
23 | Todos.TodosActiveRoute = Ember.Route.extend({
24 | setupController: function () {
25 | var todos = this.store.filter('todo', function (todo) {
26 | return !todo.get('isCompleted');
27 | });
28 |
29 | this.controllerFor('todos').set('filteredTodos', todos);
30 | }
31 | });
32 |
33 | Todos.TodosCompletedRoute = Ember.Route.extend({
34 | setupController: function () {
35 | var todos = this.store.filter('todo', function (todo) {
36 | return todo.get('isCompleted');
37 | });
38 |
39 | this.controllerFor('todos').set('filteredTodos', todos);
40 | }
41 | });
42 |
--------------------------------------------------------------------------------
/todomvc/mercury/state.js:
--------------------------------------------------------------------------------
1 | var cuid = require("cuid")
2 | var extend = require("xtend")
3 | var mercury = require("../../index.js")
4 |
5 | var TodoApp = {
6 | todos: [],
7 | route: "all",
8 | field: {
9 | text: ""
10 | }
11 | }
12 |
13 | var TodoItem = {
14 | id: null,
15 | title: "",
16 | editing: false,
17 | completed: false
18 | }
19 |
20 | module.exports = {
21 | todoApp: todoApp,
22 | todoItem: todoItem
23 | }
24 |
25 | function todoApp(events, initialState) {
26 | var state = extend(TodoApp, initialState)
27 |
28 | return mercury.hash({
29 | todos: mercury.array(state.todos.map(todoItem)),
30 | route: mercury.value(state.route),
31 | field: mercury.hash({
32 | text :mercury.value(state.field.text)
33 | }),
34 | events: events
35 | })
36 | }
37 |
38 | function todoItem(item) {
39 | var state = extend(TodoItem, item)
40 |
41 | return mercury.hash({
42 | id: cuid(),
43 | title: mercury.value(state.title),
44 | editing: mercury.value(state.editing),
45 | completed: mercury.value(state.completed)
46 | })
47 | }
48 |
--------------------------------------------------------------------------------
/todomvc/mithril/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Jean-Philippe Monette
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/todomvc/om/bower_components/director/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2011 Nodejitsu Inc.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
--------------------------------------------------------------------------------
/todomvc/om/bower_components/director/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "director",
3 | "description": "A client Side/Server Side Router",
4 | "author": "Nodejitsu Inc. ",
5 | "version": "1.2.0",
6 | "maintainers": [
7 | "hij1nx ",
8 | "indexzero "
9 | ],
10 | "repository": {
11 | "type": "git",
12 | "url": "http://github.com/flatiron/director.git"
13 | },
14 | "keywords": [
15 | "URL",
16 | "router",
17 | "http",
18 | "cli",
19 | "flatiron",
20 | "client side",
21 | "ender"
22 | ],
23 | "devDependencies": {
24 | "codesurgeon": "https://github.com/hij1nx/codesurgeon/tarball/master",
25 | "colors": "0.5.x",
26 | "api-easy": "0.3.x",
27 | "uglify-js": "1.0.6",
28 | "request": "2.9.x",
29 | "qunitjs": "1.9.x",
30 | "vows": "0.6.x"
31 | },
32 | "ender": "./build/ender.js",
33 | "browserify": "./build/director",
34 | "main": "./lib/director",
35 | "engines": {
36 | "node": ">= 0.4.0"
37 | },
38 | "scripts": {
39 | "test": "vows test/server/*/*-test.js --spec"
40 | }
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/mithril/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Leo Horie
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/todomvc/om/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Om • TodoMVC
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/todomvc/react/js/utils.js:
--------------------------------------------------------------------------------
1 | var app = app || {};
2 |
3 | (function () {
4 | 'use strict';
5 |
6 | app.Utils = {
7 | uuid: function () {
8 | /*jshint bitwise:false */
9 | var i, random;
10 | var uuid = '';
11 |
12 | for (i = 0; i < 32; i++) {
13 | random = Math.random() * 16 | 0;
14 | if (i === 8 || i === 12 || i === 16 || i === 20) {
15 | uuid += '-';
16 | }
17 | uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random))
18 | .toString(16);
19 | }
20 |
21 | return uuid;
22 | },
23 |
24 | pluralize: function (count, word) {
25 | return count === 1 ? word : word + 's';
26 | },
27 |
28 | store: function (namespace, data) {
29 | if (data) {
30 | return localStorage.setItem(namespace, JSON.stringify(data));
31 | }
32 |
33 | var store = localStorage.getItem(namespace);
34 | return (store && JSON.parse(store)) || [];
35 | },
36 |
37 | extend: function () {
38 | var newObj = {};
39 | for (var i = 0; i < arguments.length; i++) {
40 | var obj = arguments[i];
41 | for (var key in obj) {
42 | if (obj.hasOwnProperty(key)) {
43 | newObj[key] = obj[key];
44 | }
45 | }
46 | }
47 | return newObj;
48 | }
49 | };
50 | })();
51 |
--------------------------------------------------------------------------------
/todomvc/mithril/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Mithril • TodoMVC
6 |
7 |
8 |
9 |
10 |
11 |
12 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/todomvc/om/project.clj:
--------------------------------------------------------------------------------
1 | (defproject todomvc "0.1.0-SNAPSHOT"
2 | :description "FIXME: write this!"
3 | :url "http://example.com/FIXME"
4 |
5 | :jvm-opts ^:replace ["-Xmx1g" "-server"]
6 |
7 | :dependencies [[org.clojure/clojure "1.5.1"]
8 | [org.clojure/clojurescript "0.0-2173"]
9 | [org.clojure/core.async "0.1.267.0-0d7780-alpha"]
10 | [secretary "0.4.0"]
11 | [om "0.5.0"]]
12 |
13 | :plugins [[lein-cljsbuild "1.0.2"]]
14 |
15 | :source-paths ["src"]
16 |
17 | :cljsbuild {
18 | :builds [{:id "dev"
19 | :source-paths ["src"]
20 | :compiler {
21 | :output-to "app.js"
22 | :output-dir "out"
23 | :optimizations :none
24 | :source-map true}}
25 | {:id "release"
26 | :source-paths ["src"]
27 | :compiler {
28 | :output-to "app.js"
29 | :optimizations :advanced
30 | :elide-asserts true
31 | :pretty-print false
32 | :output-wrapper false
33 | :preamble ["react/react.min.js"]
34 | :externs ["react/externs/react.js"]}}]})
35 |
--------------------------------------------------------------------------------
/todomvc/emberjs/js/controllers/todos_controller.js:
--------------------------------------------------------------------------------
1 | /*global Todos, Ember */
2 | 'use strict';
3 |
4 | Todos.TodosController = Ember.ArrayController.extend({
5 | actions: {
6 | createTodo: function () {
7 | var title, todo;
8 |
9 | // Get the todo title set by the "New Todo" text field
10 | title = this.get('newTitle').trim();
11 | if (!title) {
12 | return;
13 | }
14 |
15 | // Create the new Todo model
16 | todo = this.store.createRecord('todo', {
17 | title: title,
18 | isCompleted: false
19 | });
20 | todo.save();
21 |
22 | // Clear the "New Todo" text field
23 | this.set('newTitle', '');
24 | },
25 |
26 | clearCompleted: function () {
27 | var completed = this.get('completed');
28 | completed.invoke('deleteRecord');
29 | completed.invoke('save');
30 | },
31 | },
32 |
33 | /* properties */
34 |
35 | remaining: Ember.computed.filterBy('content', 'isCompleted', false),
36 | completed: Ember.computed.filterBy('content', 'isCompleted', true),
37 |
38 | allAreDone: function (key, value) {
39 | if (value !== undefined) {
40 | this.setEach('isCompleted', value);
41 | return value;
42 | } else {
43 | var length = this.get('length');
44 | var completedLength = this.get('completed.length');
45 |
46 | return length > 0 && length === completedLength;
47 | }
48 | }.property('length', 'completed.length')
49 | });
50 |
--------------------------------------------------------------------------------
/todomvc/vanilla-es6/README.md:
--------------------------------------------------------------------------------
1 | # Vanilla ES6 (ES2015) • [TodoMVC](http://todomvc.com)
2 |
3 | > An exact port of the [Vanilla JS Example](http://todomvc.com/examples/vanillajs/), but translated into ES6, also known as ES2015.
4 |
5 | ## Learning ES6
6 |
7 | - [ES6 Features](https://github.com/lukehoban/es6features)
8 | - [Learning Resources](https://github.com/ericdouglas/ES6-Learning)
9 | - [Babel's ES6 Guide](https://babeljs.io/docs/learn-es2015/)
10 | - [Babel Compiler](https://babeljs.io/)
11 |
12 | ## Installation
13 |
14 | To get started with this example, navigate into the example folder and install the NPM modules.
15 | ```bash
16 | cd todomvc/examples/vanilla-es6
17 | npm install
18 | ```
19 |
20 | ## Compiling ES6 to ES5
21 |
22 | After NPM modules have been installed, use the pre-defined Babel script to convert the `src` files. Browserify is also used so that `module.exports` and `require()` can be run in your browser.
23 |
24 | ```bash
25 | npm run compile
26 | ```
27 |
28 | ## Support
29 |
30 | - [Twitter](http://twitter.com/lukeed05)
31 |
32 | *Let us [know](https://github.com/tastejs/todomvc/issues) if you discover anything worth sharing.*
33 |
34 |
35 | ## Implementation
36 |
37 | Uses [Babel JS](https://babeljs.io/) to compile ES6 code to ES5, which is then readable by all browsers.
38 |
39 |
40 | ## Credit
41 |
42 | Created by [Luke Edwards](http://www.lukeed.com)
43 |
--------------------------------------------------------------------------------
/todomvc/vanilla-es6/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ES6 • TodoMVC
6 |
7 |
8 |
9 |
10 |
11 |
12 |
todos
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/todomvc/emberjs/readme.md:
--------------------------------------------------------------------------------
1 | # Ember.js TodoMVC Example
2 |
3 | > A framework for creating ambitious web applications.
4 |
5 | > _[Ember.js - emberjs.com](http://emberjs.com)_
6 |
7 |
8 | ## Learning Ember.js
9 |
10 | The [Ember.js website](http://emberjs.com) is a great resource for getting started.
11 |
12 | Here are some links you may find helpful:
13 |
14 | * [Guides](http://emberjs.com/guides)
15 | * [API Reference](http://emberjs.com/api)
16 | * [Screencast - Building an App with Ember.js](https://www.youtube.com/watch?v=Ga99hMi7wfY)
17 | * [Applications built with Ember.js](http://emberjs.com/ember-users)
18 | * [Blog](http://emberjs.com/blog)
19 |
20 | Articles and guides from the community:
21 |
22 | * [Getting Into Ember.js](http://net.tutsplus.com/tutorials/javascript-ajax/getting-into-ember-js)
23 | * [EmberWatch](http://emberwatch.com)
24 | * [CodeSchool course Warming Up With Ember.js](https://www.codeschool.com/courses/warming-up-with-emberjs)
25 |
26 | Get help from other Ember.js users:
27 |
28 | * [Ember.js on StackOverflow](http://stackoverflow.com/questions/tagged/ember.js)
29 | * [Ember.js on Twitter](http://twitter.com/emberjs)
30 | * [Ember.js on Google +](https://plus.google.com/communities/106387049790387471205)
31 |
32 | _If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._
33 |
--------------------------------------------------------------------------------
/todomvc/mithril/js/views/footer-view.js:
--------------------------------------------------------------------------------
1 | var app = app || {};
2 |
3 | (function () {
4 | 'use strict';
5 |
6 | app.footer = function(ctrl) {
7 | return m('footer#footer', [
8 | m('span#todo-count', [
9 | m('strong', ctrl.list.length), ' item' + (ctrl.list.length > 1 ? 's' : '') + ' left'
10 | ]),
11 | m('ul#filters', [
12 | m('li', [
13 | m('a[href=/]', {
14 | config: m.route,
15 | class: ctrl.filter() == '' ? 'selected' : ''
16 | }, 'All')
17 | ]),
18 | m('li', [
19 | m('a[href=/active]', {
20 | config: m.route,
21 | class: ctrl.filter() == 'active' ? 'selected' : ''
22 | }, 'Active')
23 | ]),
24 | m('li', [
25 | m('a[href=/completed]', {
26 | config: m.route,
27 | class: ctrl.filter() == 'completed' ? 'selected' : ''
28 | }, 'Completed')
29 | ])
30 | ]),
31 | ctrl.amountCompleted() == 0 ? '' : m('button#clear-completed', {
32 | onclick: ctrl.clearCompleted.bind(ctrl)
33 | }, 'Clear completed (' + ctrl.amountCompleted() + ')')
34 | ]);
35 | }
36 |
37 | })();
38 |
--------------------------------------------------------------------------------
/todomvc/preact/src/model.js:
--------------------------------------------------------------------------------
1 | import { uuid, store } from './util';
2 |
3 | // note: commented out localStorage persistence as it mucks up tests.
4 |
5 | export default () => {
6 | let onChanges = [];
7 |
8 | function inform() {
9 | for (let i=onChanges.length; i--; ) {
10 | onChanges[i](model);
11 | }
12 | }
13 |
14 | let model = {
15 | todos: [],
16 |
17 | onChanges: [],
18 |
19 | subscribe(fn) {
20 | onChanges.push(fn);
21 | },
22 |
23 | addTodo(title) {
24 | model.todos = model.todos.concat({
25 | id: uuid(),
26 | title,
27 | completed: false
28 | });
29 | inform();
30 | },
31 |
32 | toggleAll(completed) {
33 | model.todos = model.todos.map(
34 | todo => ({ ...todo, completed })
35 | );
36 | inform();
37 | },
38 |
39 | toggle(todoToToggle) {
40 | model.todos = model.todos.map( todo => (
41 | todo !== todoToToggle ? todo : ({ ...todo, completed: !todo.completed })
42 | ) );
43 | inform();
44 | },
45 |
46 | destroy(todo) {
47 | model.todos = model.todos.filter( t => t !== todo );
48 | inform();
49 | },
50 |
51 | save(todoToSave, title) {
52 | model.todos = model.todos.map( todo => (
53 | todo !== todoToSave ? todo : ({ ...todo, title })
54 | ));
55 | inform();
56 | },
57 |
58 | clearCompleted() {
59 | model.todos = model.todos.filter( todo => !todo.completed );
60 | inform();
61 | }
62 | };
63 |
64 | return model;
65 | };
66 |
--------------------------------------------------------------------------------
/todomvc/ractive/js/persistence.js:
--------------------------------------------------------------------------------
1 | /*global window, todoList */
2 | (function (window, todoList) {
3 | 'use strict';
4 |
5 | // In Ractive, 'models' are usually just POJOs - plain old JavaScript objects.
6 | // Our todo list is simply an array of objects, which is handy for fetching
7 | // and persisting from/to localStorage
8 |
9 | var items, localStorage, removeEditingState;
10 |
11 | // Firefox throws a SecurityError if you try to access localStorage while
12 | // cookies are disabled
13 | try {
14 | localStorage = window.localStorage;
15 | } catch (err) {
16 | todoList.set('items', []);
17 | return;
18 | }
19 |
20 | if (localStorage) {
21 | items = JSON.parse(localStorage.getItem('todos-ractive')) || [];
22 |
23 | // Editing state should not be persisted, so we remove it
24 | // (https://github.com/tastejs/todomvc/blob/gh-pages/app-spec.md#persistence)
25 | removeEditingState = function (item) {
26 | return {
27 | description: item.description,
28 | completed: item.completed
29 | };
30 | };
31 |
32 | // Whenever the model changes (including child properties like
33 | // `items[1].completed`)...
34 | todoList.observe('items', function (items) {
35 |
36 | // ...we persist it to localStorage
37 | localStorage.setItem('todos-ractive', JSON.stringify(items.map(removeEditingState)));
38 | });
39 | } else {
40 | items = [];
41 | }
42 |
43 | todoList.set('items', items);
44 |
45 | })(window, todoList);
46 |
--------------------------------------------------------------------------------
/todomvc/backbone/js/collections/todos.js:
--------------------------------------------------------------------------------
1 | /*global Backbone */
2 | var app = app || {};
3 |
4 | (function () {
5 | 'use strict';
6 |
7 | // Todo Collection
8 | // ---------------
9 |
10 | // The collection of todos is backed by *localStorage* instead of a remote
11 | // server.
12 | var Todos = Backbone.Collection.extend({
13 | // Reference to this collection's model.
14 | model: app.Todo,
15 |
16 | // Save all of the todo items under the `"todos"` namespace.
17 | localStorage: new Backbone.LocalStorage('todos-backbone'),
18 |
19 | // Filter down the list of all todo items that are finished.
20 | completed: function () {
21 | return this.filter(function (todo) {
22 | return todo.get('completed');
23 | });
24 | },
25 |
26 | // Filter down the list to only todo items that are still not finished.
27 | remaining: function () {
28 | return this.without.apply(this, this.completed());
29 | },
30 |
31 | // We keep the Todos in sequential order, despite being saved by unordered
32 | // GUID in the database. This generates the next order number for new items.
33 | nextOrder: function () {
34 | if (!this.length) {
35 | return 1;
36 | }
37 | return this.last().get('order') + 1;
38 | },
39 |
40 | // Todos are sorted by their original insertion order.
41 | comparator: function (todo) {
42 | return todo.get('order');
43 | }
44 | });
45 |
46 | // Create our global collection of **Todos**.
47 | app.todos = new Todos();
48 | })();
49 |
--------------------------------------------------------------------------------
/todomvc/backbone/readme.md:
--------------------------------------------------------------------------------
1 | # Backbone.js TodoMVC Example
2 |
3 | > 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.
4 |
5 | > _[Backbone.js - backbonejs.org](http://backbonejs.org)_
6 |
7 |
8 | ## Learning Backbone.js
9 |
10 | The [Backbone.js website](http://backbonejs.org) is a great resource for getting started.
11 |
12 | Here are some links you may find helpful:
13 |
14 | * [Annotated source code](http://backbonejs.org/docs/backbone.html)
15 | * [Applications built with Backbone.js](http://backbonejs.org/#examples)
16 | * [FAQ](http://backbonejs.org/#faq)
17 |
18 | Articles and guides from the community:
19 |
20 | * [Developing Backbone.js Applications](http://addyosmani.github.io/backbone-fundamentals)
21 | * [Collection of tutorials, blog posts, and example sites](https://github.com/documentcloud/backbone/wiki/Tutorials%2C-blog-posts-and-example-sites)
22 |
23 | Get help from other Backbone.js users:
24 |
25 | * [Backbone.js on StackOverflow](http://stackoverflow.com/questions/tagged/backbone.js)
26 | * [Google Groups mailing list](https://groups.google.com/forum/#!forum/backbonejs)
27 | * [Backbone.js on Twitter](http://twitter.com/documentcloud)
28 |
29 | _If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._
30 |
--------------------------------------------------------------------------------
/todomvc/react/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | React • TodoMVC
6 |
7 |
8 |
9 |
10 |
11 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/todomvc/react/js/footer.jsx:
--------------------------------------------------------------------------------
1 | /*jshint quotmark:false */
2 | /*jshint white:false */
3 | /*jshint trailing:false */
4 | /*jshint newcap:false */
5 | /*global React */
6 | var app = app || {};
7 |
8 | (function () {
9 | 'use strict';
10 |
11 | app.TodoFooter = React.createClass({
12 | render: function () {
13 | var activeTodoWord = app.Utils.pluralize(this.props.count, 'item');
14 | var clearButton = null;
15 |
16 | if (this.props.completedCount > 0) {
17 | clearButton = (
18 |
23 | );
24 | }
25 |
26 | var nowShowing = this.props.nowShowing;
27 | return (
28 |
59 | );
60 | }
61 | });
62 | })();
63 |
--------------------------------------------------------------------------------
/todomvc/vanilla-es6/src/helpers.js:
--------------------------------------------------------------------------------
1 | // Allow for looping on nodes by chaining:
2 | // qsa('.foo').forEach(function () {})
3 | NodeList.prototype.forEach = Array.prototype.forEach;
4 |
5 | // Get element(s) by CSS selector:
6 | export function qs(selector, scope) {
7 | return (scope || document).querySelector(selector);
8 | }
9 |
10 | export function qsa(selector, scope) {
11 | return (scope || document).querySelectorAll(selector);
12 | }
13 |
14 | // addEventListener wrapper:
15 | export function $on(target, type, callback, useCapture) {
16 | target.addEventListener(type, callback, !!useCapture);
17 | }
18 |
19 | // Attach a handler to event for all elements that match the selector,
20 | // now or in the future, based on a root element
21 | export function $delegate(target, selector, type, handler) {
22 | const dispatchEvent = event => {
23 | const targetElement = event.target;
24 | const potentialElements = qsa(selector, target);
25 | const hasMatch = Array.from(potentialElements).includes(targetElement);
26 |
27 | if (hasMatch) {
28 | handler.call(targetElement, event);
29 | }
30 | };
31 |
32 | // https://developer.mozilla.org/en-US/docs/Web/Events/blur
33 | const useCapture = type === 'blur' || type === 'focus';
34 |
35 | $on(target, type, dispatchEvent, useCapture);
36 | }
37 |
38 | // Find the element's parent with the given tag name:
39 | // $parent(qs('a'), 'div')
40 | export function $parent(element, tagName) {
41 | if (!element.parentNode) {
42 | return;
43 | }
44 |
45 | if (element.parentNode.tagName.toLowerCase() === tagName.toLowerCase()) {
46 | return element.parentNode;
47 | }
48 |
49 | return $parent(element.parentNode, tagName);
50 | }
51 |
--------------------------------------------------------------------------------
/todomvc/emberjs/js/controllers/todo_controller.js:
--------------------------------------------------------------------------------
1 | /*global Todos, Ember */
2 | 'use strict';
3 |
4 | Todos.TodoController = Ember.ObjectController.extend({
5 | isEditing: false,
6 |
7 | // We use the bufferedTitle to store the original value of
8 | // the model's title so that we can roll it back later in the
9 | // `cancelEditing` action.
10 | bufferedTitle: Ember.computed.oneWay('title'),
11 |
12 | actions: {
13 | editTodo: function () {
14 | this.set('isEditing', true);
15 | },
16 |
17 | doneEditing: function () {
18 | var bufferedTitle = this.get('bufferedTitle').trim();
19 |
20 | if (Ember.isEmpty(bufferedTitle)) {
21 | // The `doneEditing` action gets sent twice when the user hits
22 | // enter (once via 'insert-newline' and once via 'focus-out').
23 | //
24 | // We debounce our call to 'removeTodo' so that it only gets
25 | // made once.
26 | Ember.run.debounce(this, 'removeTodo', 0);
27 | } else {
28 | var todo = this.get('model');
29 | todo.set('title', bufferedTitle);
30 | todo.save();
31 | }
32 |
33 | // Re-set our newly edited title to persist its trimmed version
34 | this.set('bufferedTitle', bufferedTitle);
35 | this.set('isEditing', false);
36 | },
37 |
38 | cancelEditing: function () {
39 | this.set('bufferedTitle', this.get('title'));
40 | this.set('isEditing', false);
41 | },
42 |
43 | removeTodo: function () {
44 | this.removeTodo();
45 | }
46 | },
47 |
48 | removeTodo: function () {
49 | var todo = this.get('model');
50 |
51 | todo.deleteRecord();
52 | todo.save();
53 | },
54 |
55 | saveWhenCompleted: function () {
56 | this.get('model').save();
57 | }.observes('isCompleted')
58 | });
59 |
--------------------------------------------------------------------------------
/todomvc/mercury/browser.js:
--------------------------------------------------------------------------------
1 | var mercury = require("../../index.js")
2 | var TimeTravel = require("../../time-travel.js")
3 | var document = require("global/document")
4 | var window = require("global/window")
5 | var rafListen = require("./lib/raf-listen.js")
6 | var localStorage = window.localStorage
7 |
8 | var Input = require("./input.js")
9 | var State = require("./state.js")
10 | var Render = require("./render.js")
11 | var Update = require("./update.js")
12 |
13 | module.exports = createApp
14 |
15 | var state = createApp()
16 | window.undo = TimeTravel(state)
17 | mercury.app(document.body, state, Render)
18 |
19 | function createApp() {
20 | // load from localStorage
21 | var storedState = localStorage.getItem("todos-mercury")
22 | var initialState = storedState ? JSON.parse(storedState) : null
23 |
24 | var events = Input()
25 | var state = window.state = State.todoApp(events, initialState)
26 |
27 | wireUpEvents(state, events)
28 |
29 | rafListen(state, function (value) {
30 | localStorage.setItem("todos-mercury", JSON.stringify(value))
31 | })
32 |
33 | return state
34 | }
35 |
36 | function wireUpEvents(state, events) {
37 | events.toggleAll(Update.toggleAll.bind(null, state))
38 | events.add(Update.add.bind(null, state))
39 | events.setTodoField(Update.setTodoField.bind(null, state))
40 | events.toggle(Update.toggle.bind(null, state))
41 | events.destroy(Update.destroy.bind(null, state))
42 | events.startEdit(Update.startEdit.bind(null, state))
43 | events.finishEdit(Update.finishEdit.bind(null, state))
44 | events.cancelEdit(Update.cancelEdit.bind(null, state))
45 | events.clearCompleted(Update.clearCompleted.bind(null, state))
46 | events.setRoute(Update.setRoute.bind(null, state))
47 | }
48 |
--------------------------------------------------------------------------------
/todomvc/knockoutjs/readme.md:
--------------------------------------------------------------------------------
1 | # Knockout.js TodoMVC Example
2 |
3 | > Knockout.js helps you simplify dynamic JavaScript UIs using the Model-View-ViewModel (MVVM) pattern.
4 |
5 | > _[Knockout.js - knockoutjs.com](http://knockoutjs.com)_
6 |
7 |
8 | ## Learning Knockout.js
9 |
10 | The [Knockout.js website](http://knockoutjs.com) is a great resource for getting started.
11 |
12 | Here are some links you may find helpful:
13 |
14 | * [Documentation](http://knockoutjs.com/documentation/introduction.html)
15 | * [Tutorials](http://learn.knockoutjs.com)
16 | * [Live examples](http://knockoutjs.com/examples)
17 |
18 | Articles and guides from the community:
19 |
20 | * [Getting Started with Knockout.js](http://www.adobe.com/devnet/html5/articles/getting-started-with-knockoutjs.html)
21 | * [Into the Ring with Knockout.js](http://net.tutsplus.com/tutorials/javascript-ajax/into-the-ring-with-knockout-js)
22 | * [Beginners Guide to Knockout.js](http://www.sitepoint.com/beginners-guide-to-knockoutjs-part-1)
23 |
24 | Get help from other Knockout.js users:
25 |
26 | * [Knockout.js on StackOverflow](http://stackoverflow.com/questions/tagged/knockout)
27 | * [Mailing list on Google Groups](http://groups.google.com/group/knockoutjs)
28 | * [Knockout.js on Twitter](http://twitter.com/knockoutjs)
29 | * [Knockout.js on Google +](https://plus.google.com/communities/106789046312204355684/stream/c5bfcfdf-3690-44a6-b015-35aad4f4e42e)
30 |
31 | _If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._
32 |
33 |
34 | ## Credit
35 |
36 | This TodoMVC application was originally created by [ashish101](https://github.com/ashish01/knockoutjs-todos), then refactored by Addy Osmani and later rewritten by TodoMVC contributors.
37 |
--------------------------------------------------------------------------------
/todomvc/om/bower_components/director/lib/director/http/methods.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Express - router - methods
3 | * Copyright(c) 2010 TJ Holowaychuk
4 | * MIT Licensed
5 | *
6 | * Adapted for SS
7 | * (C) 2011 Nodejitsu Inc.
8 | *
9 | */
10 |
11 | /**
12 | * Hypertext Transfer Protocol -- HTTP/1.1
13 | * http://www.ietf.org/rfc/rfc2616.txt
14 | */
15 | var RFC2616 = ['OPTIONS', 'GET', 'POST', 'PUT', 'DELETE', 'TRACE', 'CONNECT'];
16 |
17 | /**
18 | * HTTP Extensions for Distributed Authoring -- WEBDAV
19 | * http://www.ietf.org/rfc/rfc2518.txt
20 | */
21 | var RFC2518 = ['PROPFIND', 'PROPPATCH', 'MKCOL', 'COPY', 'MOVE', 'LOCK', 'UNLOCK'];
22 |
23 | /**
24 | * Versioning Extensions to WebDAV
25 | * http://www.ietf.org/rfc/rfc3253.txt
26 | */
27 | var RFC3253 = ['VERSION-CONTROL', 'REPORT', 'CHECKOUT', 'CHECKIN', 'UNCHECKOUT', 'MKWORKSPACE', 'UPDATE', 'LABEL', 'MERGE', 'BASELINE-CONTROL', 'MKACTIVITY'];
28 |
29 | /**
30 | * Ordered Collections Protocol (WebDAV)
31 | * http://www.ietf.org/rfc/rfc3648.txt
32 | */
33 | var RFC3648 = ['ORDERPATCH'];
34 |
35 | /**
36 | * Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol
37 | * http://www.ietf.org/rfc/rfc3744.txt
38 | */
39 | var RFC3744 = ['ACL'];
40 |
41 | /**
42 | * Web Distributed Authoring and Versioning (WebDAV) SEARCH
43 | * http://www.ietf.org/rfc/rfc5323.txt
44 | */
45 | var RFC5323 = ['SEARCH'];
46 |
47 | /**
48 | * PATCH Method for HTTP
49 | * http://www.ietf.org/rfc/rfc5789.txt
50 | */
51 | var RFC5789 = ['PATCH'];
52 |
53 | /**
54 | * Expose the methods.
55 | */
56 | module.exports = [].concat(
57 | RFC2616,
58 | RFC2518,
59 | RFC3253,
60 | RFC3648,
61 | RFC3744,
62 | RFC5323,
63 | RFC5789
64 | ).map(function (method) {
65 | return method.toLowerCase();
66 | });
--------------------------------------------------------------------------------
/todomvc/vanilla-es6/dist/helpers.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.qs = qs;
7 | exports.qsa = qsa;
8 | exports.$on = $on;
9 | exports.$delegate = $delegate;
10 | exports.$parent = $parent;
11 | // Allow for looping on nodes by chaining:
12 | // qsa('.foo').forEach(function () {})
13 | NodeList.prototype.forEach = Array.prototype.forEach;
14 |
15 | // Get element(s) by CSS selector:
16 | function qs(selector, scope) {
17 | return (scope || document).querySelector(selector);
18 | }
19 |
20 | function qsa(selector, scope) {
21 | return (scope || document).querySelectorAll(selector);
22 | }
23 |
24 | // addEventListener wrapper:
25 | function $on(target, type, callback, useCapture) {
26 | target.addEventListener(type, callback, !!useCapture);
27 | }
28 |
29 | // Attach a handler to event for all elements that match the selector,
30 | // now or in the future, based on a root element
31 | function $delegate(target, selector, type, handler) {
32 | var dispatchEvent = function dispatchEvent(event) {
33 | var targetElement = event.target;
34 | var potentialElements = qsa(selector, target);
35 | var hasMatch = Array.from(potentialElements).includes(targetElement);
36 |
37 | if (hasMatch) {
38 | handler.call(targetElement, event);
39 | }
40 | };
41 |
42 | // https://developer.mozilla.org/en-US/docs/Web/Events/blur
43 | var useCapture = type === 'blur' || type === 'focus';
44 |
45 | $on(target, type, dispatchEvent, useCapture);
46 | }
47 |
48 | // Find the element's parent with the given tag name:
49 | // $parent(qs('a'), 'div')
50 | function $parent(element, tagName) {
51 | if (!element.parentNode) {
52 | return;
53 | }
54 |
55 | if (element.parentNode.tagName.toLowerCase() === tagName.toLowerCase()) {
56 | return element.parentNode;
57 | }
58 |
59 | return $parent(element.parentNode, tagName);
60 | }
--------------------------------------------------------------------------------
/todomvc/react/js/footer.js:
--------------------------------------------------------------------------------
1 | /*jshint quotmark:false */
2 | /*jshint white:false */
3 | /*jshint trailing:false */
4 | /*jshint newcap:false */
5 | /*global React */
6 | var app = app || {};
7 |
8 | (function () {
9 | 'use strict';
10 |
11 | app.TodoFooter = React.createClass({
12 | render: function () {
13 | var activeTodoWord = app.Utils.pluralize(this.props.count, 'item');
14 | var clearButton = null;
15 |
16 | if (this.props.completedCount > 0) {
17 | clearButton = (
18 | React.createElement('button', {
19 | className: "clear-completed",
20 | onClick: this.props.onClearCompleted}, [
21 | "Clear completed"
22 | ])
23 | );
24 | }
25 |
26 | var nowShowing = this.props.nowShowing;
27 | return (
28 | React.createElement('footer', {className: "footer"}, [
29 | React.createElement('span', {className: "todo-count"}, [
30 | React.createElement('strong', null, [this.props.count])," ", activeTodoWord, " left"
31 | ]),
32 | React.createElement('ul', {className: "filters"}, [
33 | React.createElement('li', null, [
34 | React.createElement('a', {
35 | href: "#/",
36 | className: classNames({selected: nowShowing === app.ALL_TODOS})}, [
37 | "All"
38 | ])
39 | ]),
40 | ' ',
41 | React.createElement('li', null, [
42 | React.createElement('a', {
43 | href: "#/active",
44 | className: classNames({selected: nowShowing === app.ACTIVE_TODOS})}, [
45 | "Active"
46 | ])
47 | ]),
48 | ' ',
49 | React.createElement('li', null, [
50 | React.createElement('a', {
51 | href: "#/completed",
52 | className: classNames({selected: nowShowing === app.COMPLETED_TODOS})}, [
53 | "Completed"
54 | ])
55 | ])
56 | ]),
57 | clearButton
58 | ])
59 | );
60 | }
61 | });
62 | })();
63 |
--------------------------------------------------------------------------------
/todomvc/mithril/js/controllers/todo.js:
--------------------------------------------------------------------------------
1 | var app = app || {};
2 |
3 | (function () {
4 | 'use strict';
5 |
6 | app.controller = function() {
7 |
8 | this.list = new app.TodoList(); // Todo collection
9 | this.title = m.prop(''); // Temp title placeholder
10 | this.filter = m.prop(m.route.param('filter') || ''); // TodoList filter
11 |
12 | // Add a Todo
13 | this.add = function(title) {
14 | if(this.title()) {
15 | this.list.push(new app.Todo({title: title()}));
16 | this.title('');
17 | }
18 | };
19 |
20 | //check whether a todo is visible
21 | this.isVisible = function(todo) {
22 | if(this.filter() == '')
23 | return true;
24 | if (this.filter() == 'active')
25 | return !todo.completed();
26 | if (this.filter() == 'completed')
27 | return todo.completed();
28 | }
29 |
30 | this.clearTitle = function() {
31 | this.title('')
32 | }
33 |
34 | // Removing a Todo from the list
35 | this.remove = function(key) {
36 | this.list.splice(key, 1)
37 | }
38 |
39 | // Remove all Todos where Completed == true
40 | this.clearCompleted = function() {
41 | for(var i = 0; i < this.list.length; i++) {
42 | if(this.list[i].completed())
43 | this.list.splice(i, 1)
44 | }
45 | }
46 |
47 | // Total amount of Todos completed
48 | this.amountCompleted = function() {
49 | var amount = 0;
50 |
51 | for(var i = 0; i < this.list.length; i++)
52 | if(this.list[i].completed())
53 | amount++;
54 |
55 | return amount;
56 | }
57 | };
58 |
59 | })();
60 |
--------------------------------------------------------------------------------
/todomvc/react/readme.md:
--------------------------------------------------------------------------------
1 | # React TodoMVC Example
2 |
3 | > React is a JavaScript library for creating user interfaces. Its core principles are declarative code, efficiency, and flexibility. Simply specify what your component looks like and React will keep it up-to-date when the underlying data changes.
4 |
5 | > _[React - facebook.github.io/react](http://facebook.github.io/react)_
6 |
7 |
8 | ## Learning React
9 |
10 | The [React getting started documentation](http://facebook.github.io/react/docs/getting-started.html) is a great way to get started.
11 |
12 | Here are some links you may find helpful:
13 |
14 | * [Documentation](http://facebook.github.io/react/docs/getting-started.html)
15 | * [API Reference](http://facebook.github.io/react/docs/reference.html)
16 | * [Blog](http://facebook.github.io/react/blog/)
17 | * [React on GitHub](https://github.com/facebook/react)
18 | * [Support](http://facebook.github.io/react/support.html)
19 |
20 | Articles and guides from the community:
21 |
22 | * [How is Facebook's React JavaScript library](http://www.quora.com/React-JS-Library/How-is-Facebooks-React-JavaScript-library)
23 | * [React: Under the hood](http://www.quora.com/Pete-Hunt/Posts/React-Under-the-Hood)
24 |
25 | Get help from other React users:
26 |
27 | * [React on StackOverflow](http://stackoverflow.com/questions/tagged/reactjs)
28 | * [Discussion Forum](https://discuss.reactjs.org/)
29 |
30 | _If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._
31 |
32 |
33 | ## Running
34 |
35 | The app is built with [JSX](http://facebook.github.io/react/docs/jsx-in-depth.html) and compiled at runtime for a lighter and more fun code reading experience. As stated in the link, JSX is not mandatory.
36 |
37 | To run the app, spin up an HTTP server (e.g. `python -m SimpleHTTPServer`) and visit http://localhost/.../myexample/.
38 |
--------------------------------------------------------------------------------
/todomvc/vanilla-es6/dist/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var _controller = require('./controller');
4 |
5 | var _controller2 = _interopRequireDefault(_controller);
6 |
7 | var _helpers = require('./helpers');
8 |
9 | var helpers = _interopRequireWildcard(_helpers);
10 |
11 | var _template = require('./template');
12 |
13 | var _template2 = _interopRequireDefault(_template);
14 |
15 | var _store = require('./store');
16 |
17 | var _store2 = _interopRequireDefault(_store);
18 |
19 | var _model = require('./model');
20 |
21 | var _model2 = _interopRequireDefault(_model);
22 |
23 | var _view = require('./view');
24 |
25 | var _view2 = _interopRequireDefault(_view);
26 |
27 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
28 |
29 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
30 |
31 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
32 |
33 | var $on = helpers.$on;
34 | var setView = function setView() {
35 | return todo.controller.setView(document.location.hash);
36 | };
37 |
38 | var Todo =
39 | /**
40 | * Init new Todo List
41 | * @param {string} The name of your list
42 | */
43 | function Todo(name) {
44 | _classCallCheck(this, Todo);
45 |
46 | this.storage = new _store2.default(name);
47 | this.model = new _model2.default(this.storage);
48 |
49 | this.template = new _template2.default();
50 | this.view = new _view2.default(this.template);
51 |
52 | this.controller = new _controller2.default(this.model, this.view);
53 | };
54 |
55 | var todo = new Todo('todos-vanillajs');
56 |
57 | $on(window, 'load', setView);
58 | $on(window, 'hashchange', setView);
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/mithril/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/lhorie/mithril.js)
2 |
3 | # Mithril
4 |
5 | A Javascript Framework for Building Brilliant Applications
6 |
7 | See the [website](http://lhorie.github.io/mithril) for documentation
8 |
9 | There's also a [blog](http://lhorie.github.io/mithril-blog) and a [mailing list](https://groups.google.com/forum/#!forum/mithriljs)
10 |
11 | ---
12 |
13 | ## What is Mithril?
14 |
15 | Mithril is a client-side MVC framework - a tool to organize code in a way that is easy to think about and to maintain.
16 |
17 | ### Light-weight
18 |
19 | - Only 4kb gzipped, no dependencies
20 | - Small API, small learning curve
21 |
22 | ### Robust
23 |
24 | - Safe-by-default templates
25 | - Hierarchical MVC via components
26 |
27 | ### Fast
28 |
29 | - Virtual DOM diffing and compilable templates
30 | - Intelligent auto-redrawing system
31 |
32 | ---
33 |
34 | ## Sample code
35 |
36 | ```javascript
37 | //namespace
38 | var app = {};
39 |
40 | //model
41 | app.PageList = function() {
42 | return m.request({method: "GET", url: "pages.json"});
43 | };
44 |
45 | //controller
46 | app.controller = function() {
47 | this.pages = app.PageList();
48 |
49 | this.rotate = function() {
50 | this.pages().push(this.pages().shift())
51 | }.bind(this)
52 | };
53 |
54 | //view
55 | app.view = function(ctrl) {
56 | return [
57 | ctrl.pages().map(function(page) {
58 | return m("a", {href: page.url}, page.title);
59 | }),
60 | m("a", {onclick: ctrl.rotate}, "Rotate links")
61 | ];
62 | };
63 |
64 | //initialize
65 | m.module(document.getElementById("example"), app);
66 | ```
67 |
68 | ---
69 |
70 | ### Learn more
71 |
72 | - [Tutorial](http://lhorie.github.io/mithril/getting-started.html)
73 | - [Differences from Other MVC Frameworks](http://lhorie.github.io/mithril/comparison.html)
74 | - [Benchmarks](http://lhorie.github.io/mithril/benchmarks.html)
--------------------------------------------------------------------------------
/todomvc/mithril/js/views/main-view.js:
--------------------------------------------------------------------------------
1 | var app = app || {};
2 |
3 | (function () {
4 | 'use strict';
5 |
6 | //view utility
7 | app.watchInput = function(ontype, onenter, onescape) {
8 | return function(e) {
9 | ontype(e)
10 | if (e.keyCode == app.ENTER_KEY) onenter()
11 | if (e.keyCode == app.ESC_KEY) onescape()
12 | }
13 | };
14 |
15 |
16 |
17 | app.view = function(ctrl) {
18 | return [
19 | m('header#header', [
20 | m('h1', 'todos'),
21 | m('input#new-todo[placeholder="What needs to be done?"]', {
22 | onkeypress: app.watchInput(
23 | m.withAttr('value', ctrl.title),
24 | ctrl.add.bind(ctrl, ctrl.title),
25 | ctrl.clearTitle.bind(ctrl)
26 | ),
27 | value: ctrl.title()
28 | })
29 | ]),
30 | m('section#main', [
31 | m('input#toggle-all[type=checkbox]'),
32 | m('ul#todo-list', [
33 | ctrl.list.filter(ctrl.isVisible.bind(ctrl)).map(function(task, index) {
34 | return m('li', { class: task.completed() ? 'completed' : ''}, [
35 | m('.view', [
36 | m('input.toggle[type=checkbox]', {
37 | onclick: m.withAttr('checked', task.completed),
38 | checked: task.completed()
39 | }),
40 | m('label', task.title()),
41 | m('button.destroy', { onclick: ctrl.remove.bind(ctrl, index)})
42 | ]),
43 | m('input.edit')
44 | ])
45 | })
46 | ])
47 | ]),
48 | ctrl.list.length == 0 ? '' : app.footer(ctrl)
49 | ];
50 | };
51 |
52 | })();
53 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | TodoMVC Benchmark
5 |
6 |
7 |
8 |
24 |
25 |
26 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/todomvc/ractive/readme.md:
--------------------------------------------------------------------------------
1 | # Ractive.js TodoMVC app
2 |
3 | > Ractive.js solves some of the biggest headaches in web development – data binding, efficient DOM updates, event handling – and does so with almost no learning curve.
4 |
5 | > _[Ractive.js - ractivejs.org](http://ractivejs.org)_
6 |
7 |
8 | ## Learning Ractive.js
9 |
10 | [Try the 60 second setup](https://github.com/Rich-Harris/Ractive/wiki/60-second-setup), or [follow the interactive tutorials](http://learn.ractivejs.org).
11 |
12 | You can find the [API documentation on GitHub](https://github.com/Rich-Harris/Ractive/wiki).
13 |
14 | If you have questions, try [Stack Overflow](http://stackoverflow.com/questions/tagged/ractivejs) or [@RactiveJS on Twitter](http://twitter.com/RactiveJS).
15 |
16 | _If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._
17 |
18 |
19 | ## Implementation
20 |
21 | Ractive.js isn't an MVC framework in the traditional sense. There are no Model classes, just a plain old array of task objects, and there is only one view object. The app lives in a single file, with two tiny extra files to handle persistence and routing.
22 |
23 | This is because Ractive is optimised for developer sanity (as well as performance!). It was initially developed to create interactive news apps at [theguardian.com](http://theguardian.com), which have to be built against punishing deadlines and moving goalposts. Because it embraces reactive programming principles, the developer has less to worry about. Ractive's API is totally straightforward - you can learn it in 5 minutes and master it in a few hours.
24 |
25 | It has a number of innovative features: animations, easier event handling, declarative transitions, first-class SVG support, logical expressions in templates with sophisticated dependency tracking. For many developers, it hits the sweet spot between the flexibility of a library like Backbone and the power of a framework like Angular.
26 |
27 |
28 | ## Credit
29 |
30 | This TodoMVC application was created by [Rich Harris](http://rich-harris.co.uk).
31 |
--------------------------------------------------------------------------------
/todomvc/om/bower_components/director/lib/director/cli.js:
--------------------------------------------------------------------------------
1 |
2 | var util = require('util'),
3 | director = require('../director');
4 |
5 | var Router = exports.Router = function (routes) {
6 | director.Router.call(this, routes);
7 | this.recurse = false;
8 | };
9 |
10 | //
11 | // Inherit from `director.Router`.
12 | //
13 | util.inherits(Router, director.Router);
14 |
15 | //
16 | // ### function configure (options)
17 | // #### @options {Object} **Optional** Options to configure this instance with
18 | // Configures this instance with the specified `options`.
19 | //
20 | Router.prototype.configure = function (options) {
21 | options = options || {};
22 | director.Router.prototype.configure.call(this, options);
23 |
24 | //
25 | // Delimiter must always be `\s` in CLI routing.
26 | // e.g. `jitsu users create`
27 | //
28 | this.delimiter = '\\s';
29 | return this;
30 | };
31 |
32 | //
33 | // ### function dispatch (method, path)
34 | // #### @method {string} Method to dispatch
35 | // #### @path {string} Path to dispatch
36 | // Finds a set of functions on the traversal towards
37 | // `method` and `path` in the core routing table then
38 | // invokes them based on settings in this instance.
39 | //
40 | Router.prototype.dispatch = function (method, path, tty, callback) {
41 | //
42 | // Prepend a single space onto the path so that the traversal
43 | // algorithm will recognize it. This is because we always assume
44 | // that the `path` begins with `this.delimiter`.
45 | //
46 | path = ' ' + path;
47 | var fns = this.traverse(method, path, this.routes, '');
48 | if (!fns || fns.length === 0) {
49 | if (typeof this.notfound === 'function') {
50 | this.notfound.call({ tty: tty, cmd: path }, callback);
51 | }
52 | else if (callback) {
53 | callback(new Error('Could not find path: ' + path));
54 | }
55 |
56 | return false;
57 | }
58 |
59 | if (this.recurse === 'forward') {
60 | fns = fns.reverse();
61 | }
62 |
63 | this.invoke(this.runlist(fns), { tty: tty, cmd: path }, callback);
64 | return true;
65 | };
66 |
--------------------------------------------------------------------------------
/todomvc/preact/src/item.js:
--------------------------------------------------------------------------------
1 | import { h, Component } from 'preact';
2 | import linkState from 'linkstate';
3 |
4 | const ESCAPE_KEY = 27;
5 | const ENTER_KEY = 13;
6 |
7 | export default class TodoItem extends Component {
8 | handleSubmit = () => {
9 | let val = this.state.editText.trim(),
10 | { todo, onSave, onDestroy } = this.props;
11 | if (val) {
12 | onSave(todo, val);
13 | this.setState({ editText: val });
14 | }
15 | else {
16 | onDestroy(todo);
17 | }
18 | };
19 |
20 | handleEdit = () => {
21 | let { todo, onEdit } = this.props;
22 | onEdit(todo);
23 | this.setState({ editText: todo.title });
24 | };
25 |
26 | toggle = e => {
27 | let { todo, onToggle } = this.props;
28 | onToggle(todo);
29 | e.preventDefault();
30 | };
31 |
32 | handleKeyDown = e => {
33 | let { todo, onCancel } = this.props;
34 | if (e.which===ESCAPE_KEY) {
35 | this.setState({ editText: todo.title });
36 | onCancel(todo);
37 | }
38 | else if (e.which===ENTER_KEY) {
39 | this.handleSubmit(todo);
40 | }
41 | };
42 |
43 | destroy = () => {
44 | let { todo, onDestroy } = this.props;
45 | onDestroy(todo);
46 | };
47 |
48 | focus(c) {
49 | if (c) setTimeout(() => c.focus(), 1);
50 | }
51 |
52 | // componentDidUpdate({ editing }) {
53 | // let node = editing && this.base && this.base.querySelector('.edit');
54 | // if (node) node.focus();
55 | // }
56 |
57 | render({ todo:{ title, completed }, editing }, { editText }) {
58 | return (
59 |
60 |
61 |
67 |
68 |
69 |
70 | { editing && (
71 |
79 | ) }
80 |
81 | );
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/mithril/mithril.d.ts:
--------------------------------------------------------------------------------
1 | //Mithril type definitions for Typescript
2 |
3 | interface MithrilStatic {
4 | (selector: string, attributes: Object, children?: any): MithrilVirtualElement;
5 | (selector: string, children?: any): MithrilVirtualElement;
6 | prop(value?: any): (value?: any) => any;
7 | withAttr(property: string, callback: (value: any) => void): (e: Event) => any;
8 | module(rootElement: Element, module: MithrilModule): void;
9 | trust(html: string): String;
10 | render(rootElement: Element, children?: any): void;
11 | render(rootElement: HTMLDocument, children?: any): void;
12 | redraw(): void;
13 | route(rootElement: Element, defaultRoute: string, routes: { [key: string]: MithrilModule }): void;
14 | route(rootElement: HTMLDocument, defaultRoute: string, routes: { [key: string]: MithrilModule }): void;
15 | route(path: string, params?: any, shouldReplaceHistory?: boolean): void;
16 | route(): string;
17 | route(element: Element, isInitialized: boolean): void;
18 | request(options: MithrilXHROptions): MithrilPromise;
19 | deferred(): MithrilDeferred;
20 | sync(promises: MithrilPromise[]): MithrilPromise;
21 | startComputation(): void;
22 | endComputation(): void;
23 | }
24 |
25 | interface MithrilVirtualElement {
26 | tag: string;
27 | attrs: Object;
28 | children: any;
29 | }
30 |
31 | interface MithrilModule {
32 | controller: Function;
33 | view: Function;
34 | }
35 |
36 | interface MithrilDeferred {
37 | resolve(value?: any): void;
38 | reject(value?: any): void;
39 | promise: MithrilPromise;
40 | }
41 |
42 | interface MithrilPromise {
43 | (value?: any): any;
44 | then(successCallback?: (value: any) => any, errorCallback?: (value: any) => any): MithrilPromise;
45 | }
46 |
47 | interface MithrilXHROptions {
48 | method: string;
49 | url: string;
50 | user?: string;
51 | password?: string;
52 | data?: any;
53 | background?: boolean;
54 | unwrapSuccess?(data: any): any;
55 | unwrapError?(data: any): any;
56 | serialize?(dataToSerialize: any): string;
57 | deserialize?(dataToDeserialize: string): any;
58 | extract?(xhr: XMLHttpRequest, options: MithrilXHROptions);
59 | type?(data: Object): void;
60 | config?(xhr: XMLHttpRequest, options: MithrilXHROptions)
61 | }
62 |
63 | declare var Mithril: MithrilStatic;
64 | declare var m: MithrilStatic;
--------------------------------------------------------------------------------
/todomvc/om/bower_components/director/lib/director/http/responses.js:
--------------------------------------------------------------------------------
1 | //
2 | // HTTP Error objectst
3 | //
4 | var util = require('util');
5 |
6 | exports.NotModified = function () {
7 | this.status = 304;
8 | this.options = {
9 | removeContentHeaders: true
10 | };
11 | };
12 |
13 | util.inherits(exports.NotModified, Error);
14 |
15 | exports.BadRequest = function (msg) {
16 | msg = msg || 'Bad request';
17 |
18 | this.status = 400;
19 | this.headers = {};
20 | this.message = msg;
21 | this.body = { error: msg };
22 | };
23 |
24 | util.inherits(exports.BadRequest, Error);
25 |
26 | exports.NotAuthorized = function (msg) {
27 | msg = msg || 'Not Authorized';
28 |
29 | this.status = 401;
30 | this.headers = {};
31 | this.message = msg;
32 | this.body = { error: msg };
33 | };
34 |
35 | util.inherits(exports.NotAuthorized, Error);
36 |
37 | exports.Forbidden = function (msg) {
38 | msg = msg || 'Not Authorized';
39 |
40 | this.status = 403;
41 | this.headers = {};
42 | this.message = msg;
43 | this.body = { error: msg };
44 | };
45 |
46 | util.inherits(exports.Forbidden, Error);
47 |
48 | exports.NotFound = function (msg) {
49 | msg = msg || 'Not Found';
50 |
51 | this.status = 404;
52 | this.headers = {};
53 | this.message = msg;
54 | this.body = { error: msg };
55 | };
56 |
57 | util.inherits(exports.NotFound, Error);
58 |
59 | exports.MethodNotAllowed = function (allowed) {
60 | var msg = 'method not allowed.';
61 |
62 | this.status = 405;
63 | this.headers = { allow: allowed };
64 | this.message = msg;
65 | this.body = { error: msg };
66 | };
67 |
68 | util.inherits(exports.MethodNotAllowed, Error);
69 |
70 | exports.NotAcceptable = function (accept) {
71 | var msg = 'cannot generate "' + accept + '" response';
72 |
73 | this.status = 406;
74 | this.headers = {};
75 | this.message = msg;
76 | this.body = {
77 | error: msg,
78 | only: 'application/json'
79 | };
80 | };
81 |
82 | util.inherits(exports.NotAcceptable, Error);
83 |
84 | exports.NotImplemented = function (msg) {
85 | msg = msg || 'Not Implemented';
86 |
87 | this.status = 501;
88 | this.headers = {};
89 | this.message = msg;
90 | this.body = { error: msg };
91 | };
92 |
93 | util.inherits(exports.NotImplemented, Error);
94 |
--------------------------------------------------------------------------------
/todomvc/mithril/README.md:
--------------------------------------------------------------------------------
1 | # Mithril TodoMVC Example
2 |
3 | > Mithril is a client-side Javascript MVC framework, i.e. it's a tool to make application code divided into a data layer (called "Model"), a UI layer (called View), and a glue layer (called Controller)
4 |
5 | > _[Mithril](http://lhorie.github.io/mithril/)_
6 |
7 |
8 | ## Learning Mithril
9 |
10 | The [Mithril website](http://lhorie.github.io/mithril/) is a great resource for getting started.
11 |
12 | Here are some links you may find helpful:
13 |
14 | * [Getting Started](http://lhorie.github.io/mithril/getting-started.html)
15 | * [API Reference](http://lhorie.github.io/mithril/mithril.html)
16 | * [Mithril on Github](https://github.com/lhorie/mithril.js)
17 |
18 | _If you have other helpful links to share, or find any of the links above no longer work, please [let me know](https://github.com/jpmonette/todomvc-mithril/issues)._
19 |
20 | ## Running
21 |
22 | 1. Clone the repo
23 | 2. Execute `bower install` in the repo (make sure yo install `npm`)
24 | 3. Open `index.html`!
25 |
26 | ## TODO
27 |
28 | * Proper routing support (fixed, waiting for latest Mithril version (v0.1.1))
29 | * Select all
30 | * Fix items left behaviour
31 |
32 | ## Credit
33 |
34 | This TodoMVC application was created by [Jean-Philippe Monette](http://blogue.jpmonette.net/)
35 |
36 | ## License
37 |
38 | Copyright (C) 2013, Jean-Philippe Monette
39 |
40 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
41 |
42 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
43 |
44 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
45 |
--------------------------------------------------------------------------------
/todomvc/backbone/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Backbone.js • TodoMVC
7 |
8 |
9 |
10 |
11 |
12 |
HTML string and returns it for placement in your app.
31 | *
32 | * NOTE: In real life you should be using a templating engine such as Mustache
33 | * or Handlebars, however, this is a vanilla JS example.
34 | *
35 | * @param {object} data The object containing keys you want to find in the
36 | * template to replace.
37 | * @returns {string} HTML String of an
101 | );
102 | }
103 | }
104 |
105 |
106 | // just a fake component we can feed to router. yay.
107 | const Noop = () => null;
108 |
--------------------------------------------------------------------------------
/todomvc/vue/js/app.js:
--------------------------------------------------------------------------------
1 | /*global Vue, todoStorage */
2 |
3 | (function (exports) {
4 |
5 | 'use strict';
6 |
7 | var filters = {
8 | all: function (todos) {
9 | return todos;
10 | },
11 | active: function (todos) {
12 | return todos.filter(function (todo) {
13 | return !todo.completed;
14 | });
15 | },
16 | completed: function (todos) {
17 | return todos.filter(function (todo) {
18 | return todo.completed;
19 | });
20 | }
21 | };
22 |
23 | exports.app = new Vue({
24 |
25 | // the root element that will be compiled
26 | el: '.todoapp',
27 |
28 | // app initial state
29 | data: {
30 | todos: todoStorage.fetch(),
31 | newTodo: '',
32 | editedTodo: null,
33 | visibility: 'all'
34 | },
35 |
36 | // watch todos change for localStorage persistence
37 | watch: {
38 | todos: {
39 | deep: true,
40 | handler: todoStorage.save
41 | }
42 | },
43 |
44 | // computed properties
45 | // http://vuejs.org/guide/computed.html
46 | computed: {
47 | filteredTodos: function () {
48 | return filters[this.visibility](this.todos);
49 | },
50 | remaining: function () {
51 | return filters.active(this.todos).length;
52 | },
53 | allDone: {
54 | get: function () {
55 | return this.remaining === 0;
56 | },
57 | set: function (value) {
58 | this.todos.forEach(function (todo) {
59 | todo.completed = value;
60 | });
61 | }
62 | }
63 | },
64 |
65 | // methods that implement data logic.
66 | // note there's no DOM manipulation here at all.
67 | methods: {
68 |
69 | addTodo: function () {
70 | var value = this.newTodo && this.newTodo.trim();
71 | if (!value) {
72 | return;
73 | }
74 | this.todos.push({ title: value, completed: false });
75 | this.newTodo = '';
76 | },
77 |
78 | removeTodo: function (todo) {
79 | this.todos.$remove(todo);
80 | },
81 |
82 | editTodo: function (todo) {
83 | this.beforeEditCache = todo.title;
84 | this.editedTodo = todo;
85 | },
86 |
87 | doneEdit: function (todo) {
88 | if (!this.editedTodo) {
89 | return;
90 | }
91 | this.editedTodo = null;
92 | todo.title = todo.title.trim();
93 | if (!todo.title) {
94 | this.removeTodo(todo);
95 | }
96 | },
97 |
98 | cancelEdit: function (todo) {
99 | this.editedTodo = null;
100 | todo.title = this.beforeEditCache;
101 | },
102 |
103 | removeCompleted: function () {
104 | this.todos = filters.active(this.todos);
105 | }
106 | },
107 |
108 | // a custom directive to wait for the DOM to be updated
109 | // before focusing on the input field.
110 | // http://vuejs.org/guide/custom-directive.html
111 | directives: {
112 | 'todo-focus': function (value) {
113 | if (!value) {
114 | return;
115 | }
116 | var el = this.el;
117 | Vue.nextTick(function () {
118 | el.focus();
119 | });
120 | }
121 | }
122 | });
123 |
124 | })(window);
125 |
--------------------------------------------------------------------------------
/todomvc/emberjs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ember.js • TodoMVC
6 |
7 |
8 |
9 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/todomvc/vanilla-es6/src/model.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Creates a new Model instance and hooks up the storage.
3 | * @constructor
4 | * @param {object} storage A reference to the client side storage class
5 | */
6 | export default class Model {
7 | constructor(storage) {
8 | this.storage = storage;
9 | }
10 |
11 | /**
12 | * Creates a new todo model
13 | *
14 | * @param {string} [title] The title of the task
15 | * @param {function} [callback] The callback to fire after the model is created
16 | */
17 | create(title, callback){
18 | title = title || '';
19 |
20 | const newItem = {
21 | title: title.trim(),
22 | completed: false
23 | };
24 |
25 | this.storage.save(newItem, callback);
26 | }
27 |
28 | /**
29 | * Finds and returns a model in storage. If no query is given it'll simply
30 | * return everything. If you pass in a string or number it'll look that up as
31 | * the ID of the model to find. Lastly, you can pass it an object to match
32 | * against.
33 | *
34 | * @param {string|number|object} [query] A query to match models against
35 | * @param {function} [callback] The callback to fire after the model is found
36 | *
37 | * @example
38 | * model.read(1, func) // Will find the model with an ID of 1
39 | * model.read('1') // Same as above
40 | * //Below will find a model with foo equalling bar and hello equalling world.
41 | * model.read({ foo: 'bar', hello: 'world' })
42 | */
43 | read(query, callback){
44 | const queryType = typeof query;
45 |
46 | if (queryType === 'function') {
47 | this.storage.findAll(query);
48 | } else if (queryType === 'string' || queryType === 'number') {
49 | query = parseInt(query, 10);
50 | this.storage.find({id: query}, callback);
51 | } else {
52 | this.storage.find(query, callback);
53 | }
54 | }
55 |
56 | /**
57 | * Updates a model by giving it an ID, data to update, and a callback to fire when
58 | * the update is complete.
59 | *
60 | * @param {number} id The id of the model to update
61 | * @param {object} data The properties to update and their new value
62 | * @param {function} callback The callback to fire when the update is complete.
63 | */
64 | update(id, data, callback){
65 | this.storage.save(data, callback, id);
66 | }
67 |
68 | /**
69 | * Removes a model from storage
70 | *
71 | * @param {number} id The ID of the model to remove
72 | * @param {function} callback The callback to fire when the removal is complete.
73 | */
74 | remove(id, callback){
75 | this.storage.remove(id, callback);
76 | }
77 |
78 | /**
79 | * WARNING: Will remove ALL data from storage.
80 | *
81 | * @param {function} callback The callback to fire when the storage is wiped.
82 | */
83 | removeAll(callback){
84 | this.storage.drop(callback);
85 | }
86 |
87 | /**
88 | * Returns a count of all todos
89 | */
90 | getCount(callback){
91 | const todos = {
92 | active: 0,
93 | completed: 0,
94 | total: 0
95 | };
96 |
97 | this.storage.findAll(data => {
98 | for (let todo of data) {
99 | if (todo.completed) {
100 | todos.completed++;
101 | } else {
102 | todos.active++;
103 | }
104 |
105 | todos.total++;
106 | }
107 |
108 | callback(todos);
109 | });
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/todomvc/angularjs-perf/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | AngularJS • TodoMVC
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
todos
14 |
17 |
18 |
19 |
20 |
21 |
22 |
24 |
25 |
26 |
27 |
28 |
29 |
37 |
38 |
39 |
40 |
57 |
58 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/todomvc/react/js/todoItem.jsx:
--------------------------------------------------------------------------------
1 | /*jshint quotmark: false */
2 | /*jshint white: false */
3 | /*jshint trailing: false */
4 | /*jshint newcap: false */
5 | /*global React */
6 | var app = app || {};
7 |
8 | (function () {
9 | 'use strict';
10 |
11 | var ESCAPE_KEY = 27;
12 | var ENTER_KEY = 13;
13 |
14 | app.TodoItem = React.createClass({
15 | handleSubmit: function (event) {
16 | var val = this.state.editText.trim();
17 | if (val) {
18 | this.props.onSave(val);
19 | this.setState({editText: val});
20 | } else {
21 | this.props.onDestroy();
22 | }
23 | },
24 |
25 | handleEdit: function () {
26 | this.props.onEdit();
27 | this.setState({editText: this.props.todo.title});
28 | },
29 |
30 | handleKeyDown: function (event) {
31 | if (event.which === ESCAPE_KEY) {
32 | this.setState({editText: this.props.todo.title});
33 | this.props.onCancel(event);
34 | } else if (event.which === ENTER_KEY) {
35 | this.handleSubmit(event);
36 | }
37 | },
38 |
39 | handleChange: function (event) {
40 | if (this.props.editing) {
41 | this.setState({editText: event.target.value});
42 | }
43 | },
44 |
45 | getInitialState: function () {
46 | return {editText: this.props.todo.title};
47 | },
48 |
49 | /**
50 | * This is a completely optional performance enhancement that you can
51 | * implement on any React component. If you were to delete this method
52 | * the app would still work correctly (and still be very performant!), we
53 | * just use it as an example of how little code it takes to get an order
54 | * of magnitude performance improvement.
55 | */
56 | shouldComponentUpdate: function (nextProps, nextState) {
57 | return (
58 | nextProps.todo !== this.props.todo ||
59 | nextProps.editing !== this.props.editing ||
60 | nextState.editText !== this.state.editText
61 | );
62 | },
63 |
64 | /**
65 | * Safely manipulate the DOM after updating the state when invoking
66 | * `this.props.onEdit()` in the `handleEdit` method above.
67 | * For more info refer to notes at https://facebook.github.io/react/docs/component-api.html#setstate
68 | * and https://facebook.github.io/react/docs/component-specs.html#updating-componentdidupdate
69 | */
70 | componentDidUpdate: function (prevProps) {
71 | if (!prevProps.editing && this.props.editing) {
72 | var node = React.findDOMNode(this.refs.editField);
73 | node.focus();
74 | node.setSelectionRange(node.value.length, node.value.length);
75 | }
76 | },
77 |
78 | render: function () {
79 | return (
80 |
84 |
85 |
91 |
94 |
95 |
96 |
104 |
105 | );
106 | }
107 | });
108 | })();
109 |
--------------------------------------------------------------------------------
/todomvc/react/js/todoItem.js:
--------------------------------------------------------------------------------
1 | /*jshint quotmark: false */
2 | /*jshint white: false */
3 | /*jshint trailing: false */
4 | /*jshint newcap: false */
5 | /*global React */
6 | var app = app || {};
7 |
8 | (function () {
9 | 'use strict';
10 |
11 | var ESCAPE_KEY = 27;
12 | var ENTER_KEY = 13;
13 |
14 | app.TodoItem = React.createClass({
15 | handleSubmit: function (event) {
16 | var val = this.state.editText.trim();
17 | if (val) {
18 | this.props.onSave(val);
19 | this.setState({editText: val});
20 | } else {
21 | this.props.onDestroy();
22 | }
23 | },
24 |
25 | handleEdit: function () {
26 | this.props.onEdit();
27 | this.setState({editText: this.props.todo.title});
28 | },
29 |
30 | handleKeyDown: function (event) {
31 | if (event.which === ESCAPE_KEY) {
32 | this.setState({editText: this.props.todo.title});
33 | this.props.onCancel(event);
34 | } else if (event.which === ENTER_KEY) {
35 | this.handleSubmit(event);
36 | }
37 | },
38 |
39 | handleChange: function (event) {
40 | if (this.props.editing) {
41 | this.setState({editText: event.target.value});
42 | }
43 | },
44 |
45 | getInitialState: function () {
46 | return {editText: this.props.todo.title};
47 | },
48 |
49 | /**
50 | * This is a completely optional performance enhancement that you can
51 | * implement on any React component. If you were to delete this method
52 | * the app would still work correctly (and still be very performant!), we
53 | * just use it as an example of how little code it takes to get an order
54 | * of magnitude performance improvement.
55 | */
56 | shouldComponentUpdate: function (nextProps, nextState) {
57 | return (
58 | nextProps.todo !== this.props.todo ||
59 | nextProps.editing !== this.props.editing ||
60 | nextState.editText !== this.state.editText
61 | );
62 | },
63 |
64 | /**
65 | * Safely manipulate the DOM after updating the state when invoking
66 | * `this.props.onEdit()` in the `handleEdit` method above.
67 | * For more info refer to notes at https://facebook.github.io/react/docs/component-api.html#setstate
68 | * and https://facebook.github.io/react/docs/component-specs.html#updating-componentdidupdate
69 | */
70 | componentDidUpdate: function (prevProps) {
71 | if (!prevProps.editing && this.props.editing) {
72 | var node = React.findDOMNode(this.refs.editField);
73 | node.focus();
74 | node.setSelectionRange(node.value.length, node.value.length);
75 | }
76 | },
77 |
78 | render: function () {
79 | return (
80 | React.createElement('li', {className: classNames({
81 | completed: this.props.todo.completed,
82 | editing: this.props.editing
83 | })}, [
84 | React.createElement('div', {className: "view"}, [
85 | React.createElement('input', {
86 | className: "toggle",
87 | type: "checkbox",
88 | checked: this.props.todo.completed,
89 | onChange: this.props.onToggle}
90 | ),
91 | React.createElement('label', {onDoubleClick: this.handleEdit}, [
92 | this.props.todo.title
93 | ]),
94 | React.createElement('button', {className: "destroy", onClick: this.props.onDestroy})
95 | ]),
96 | React.createElement('input', {
97 | ref: "editField",
98 | className: "edit",
99 | value: this.state.editText,
100 | onBlur: this.handleSubmit,
101 | onChange: this.handleChange,
102 | onKeyDown: this.handleKeyDown}
103 | )
104 | ])
105 | );
106 | }
107 | });
108 | })();
109 |
--------------------------------------------------------------------------------
/todomvc/vanilla-es6/dist/template.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
4 |
5 | Object.defineProperty(exports, "__esModule", {
6 | value: true
7 | });
8 |
9 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
10 |
11 | var htmlEscapes = {
12 | '&': '&',
13 | '<': '<',
14 | '>': '>',
15 | '"': '"',
16 | '\'': ''',
17 | '`': '`'
18 | };
19 |
20 | var reUnescapedHtml = /[&<>"'`]/g;
21 | var reHasUnescapedHtml = new RegExp(reUnescapedHtml.source);
22 |
23 | var escape = function escape(str) {
24 | return str && reHasUnescapedHtml.test(str) ? str.replace(reUnescapedHtml, escapeHtmlChar) : str;
25 | };
26 | var escapeHtmlChar = function escapeHtmlChar(chr) {
27 | return htmlEscapes[chr];
28 | };
29 |
30 | var Template = function () {
31 | function Template() {
32 | _classCallCheck(this, Template);
33 |
34 | this.defaultTemplate = '\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
\n\t\t\t
\n\t\t';
35 | }
36 |
37 | /**
38 | * Creates an
HTML string and returns it for placement in your app.
39 | *
40 | * NOTE: In real life you should be using a templating engine such as Mustache
41 | * or Handlebars, however, this is a vanilla JS example.
42 | *
43 | * @param {object} data The object containing keys you want to find in the
44 | * template to replace.
45 | * @returns {string} HTML String of an
element
46 | *
47 | * @example
48 | * view.show({
49 | * id: 1,
50 | * title: "Hello World",
51 | * completed: 0,
52 | * })
53 | */
54 |
55 | _createClass(Template, [{
56 | key: 'show',
57 | value: function show(data) {
58 | var _this = this;
59 |
60 | var view = data.map(function (d) {
61 | var template = _this.defaultTemplate;
62 | var completed = d.completed ? 'completed' : '';
63 | var checked = d.completed ? 'checked' : '';
64 |
65 | return _this.defaultTemplate.replace('{{id}}', d.id).replace('{{title}}', escape(d.title)).replace('{{completed}}', completed).replace('{{checked}}', checked);
66 | });
67 |
68 | return view.join('');
69 | }
70 |
71 | /**
72 | * Displays a counter of how many to dos are left to complete
73 | *
74 | * @param {number} activeTodos The number of active todos.
75 | * @returns {string} String containing the count
76 | */
77 |
78 | }, {
79 | key: 'itemCounter',
80 | value: function itemCounter(activeTodos) {
81 | var plural = activeTodos === 1 ? '' : 's';
82 | return '' + activeTodos + ' item' + plural + ' left';
83 | }
84 |
85 | /**
86 | * Updates the text within the "Clear completed" button
87 | *
88 | * @param {[type]} completedTodos The number of completed todos.
89 | * @returns {string} String containing the count
90 | */
91 |
92 | }, {
93 | key: 'clearCompletedButton',
94 | value: function clearCompletedButton(completedTodos) {
95 | return completedTodos > 0 ? 'Clear completed' : '';
96 | }
97 | }]);
98 |
99 | return Template;
100 | }();
101 |
102 | exports.default = Template;
--------------------------------------------------------------------------------
/todomvc/emberjs/bower_components/ember-localstorage-adapter/localstorage_adapter.js:
--------------------------------------------------------------------------------
1 | /*global Ember*/
2 | /*global DS*/
3 | 'use strict';
4 |
5 | DS.LSAdapter = DS.Adapter.extend(Ember.Evented, {
6 |
7 | init: function () {
8 | this._loadData();
9 | },
10 |
11 | generateIdForRecord: function () {
12 | return Math.random().toString(32).slice(2).substr(0, 5);
13 | },
14 |
15 | find: function (store, type, id) {
16 | var namespace = this._namespaceForType(type);
17 | return Ember.RSVP.resolve(Ember.copy(namespace.records[id]));
18 | },
19 |
20 | findMany: function (store, type, ids) {
21 | var namespace = this._namespaceForType(type);
22 | var results = [];
23 | for (var i = 0; i < ids.length; i++) {
24 | results.push(Ember.copy(namespace.records[ids[i]]));
25 | }
26 | return Ember.RSVP.resolve(results);
27 | },
28 |
29 | // Supports queries that look like this:
30 | //
31 | // {
32 | // : ,
33 | // ...
34 | // }
35 | //
36 | // Every property added to the query is an "AND" query, not "OR"
37 | //
38 | // Example:
39 | //
40 | // match records with "complete: true" and the name "foo" or "bar"
41 | //
42 | // { complete: true, name: /foo|bar/ }
43 | findQuery: function (store, type, query, recordArray) {
44 | var namespace = this._namespaceForType(type);
45 | var results = this.query(namespace.records, query);
46 | return Ember.RSVP.resolve(results);
47 | },
48 |
49 | query: function (records, query) {
50 | var results = [];
51 | var id, record, property, test, push;
52 | for (id in records) {
53 | record = records[id];
54 | for (property in query) {
55 | test = query[property];
56 | push = false;
57 | if (Object.prototype.toString.call(test) === '[object RegExp]') {
58 | push = test.test(record[property]);
59 | } else {
60 | push = record[property] === test;
61 | }
62 | }
63 | if (push) {
64 | results.push(record);
65 | }
66 | }
67 | return results;
68 | },
69 |
70 | findAll: function (store, type) {
71 | var namespace = this._namespaceForType(type);
72 | var results = [];
73 | for (var id in namespace.records) {
74 | results.push(Ember.copy(namespace.records[id]));
75 | }
76 | return Ember.RSVP.resolve(results);
77 | },
78 |
79 | createRecord: function (store, type, record) {
80 | var namespace = this._namespaceForType(type);
81 | this._addRecordToNamespace(namespace, record);
82 | this._saveData();
83 | return Ember.RSVP.resolve();
84 | },
85 |
86 | updateRecord: function (store, type, record) {
87 | var namespace = this._namespaceForType(type);
88 | var id = record.get('id');
89 | namespace.records[id] = record.toJSON({ includeId: true });
90 | this._saveData();
91 | return Ember.RSVP.resolve();
92 | },
93 |
94 | deleteRecord: function (store, type, record) {
95 | var namespace = this._namespaceForType(type);
96 | var id = record.get('id');
97 | delete namespace.records[id];
98 | this._saveData();
99 | return Ember.RSVP.resolve();
100 | },
101 |
102 | // private
103 |
104 | _getNamespace: function () {
105 | return this.namespace || 'DS.LSAdapter';
106 | },
107 |
108 | _loadData: function () {
109 | var storage = localStorage.getItem(this._getNamespace());
110 | this._data = storage ? JSON.parse(storage) : {};
111 | },
112 |
113 | _saveData: function () {
114 | localStorage.setItem(this._getNamespace(), JSON.stringify(this._data));
115 | },
116 |
117 | _namespaceForType: function (type) {
118 | var namespace = type.url || type.toString();
119 | return this._data[namespace] || (
120 | this._data[namespace] = {records: {}}
121 | );
122 | },
123 |
124 | _addRecordToNamespace: function (namespace, record) {
125 | var data = record.serialize({includeId: true});
126 | namespace.records[data.id] = data;
127 | }
128 | });
129 |
--------------------------------------------------------------------------------
/todomvc/vanilla-es6/src/store.js:
--------------------------------------------------------------------------------
1 | /*jshint eqeqeq:false */
2 |
3 | /**
4 | * Creates a new client side storage object and will create an empty
5 | * collection if no collection already exists.
6 | *
7 | * @param {string} name The name of our DB we want to use
8 | * @param {function} callback Our fake DB uses callbacks because in
9 | * real life you probably would be making AJAX calls
10 | */
11 | export default class Store {
12 | constructor(name, callback) {
13 | this._dbName = name;
14 |
15 | if (!localStorage[name]) {
16 | const data = {
17 | todos: []
18 | };
19 |
20 | localStorage[name] = JSON.stringify(data);
21 | }
22 |
23 | if (callback) {
24 | callback.call(this, JSON.parse(localStorage[name]));
25 | }
26 | }
27 |
28 | /**
29 | * Finds items based on a query given as a JS object
30 | *
31 | * @param {object} query The query to match against (i.e. {foo: 'bar'})
32 | * @param {function} callback The callback to fire when the query has
33 | * completed running
34 | *
35 | * @example
36 | * db.find({foo: 'bar', hello: 'world'}, function (data) {
37 | * // data will return any items that have foo: bar and
38 | * // hello: world in their properties
39 | * })
40 | */
41 | find(query, callback){
42 | const todos = JSON.parse(localStorage[this._dbName]).todos;
43 |
44 | callback.call(this, todos.filter(todo => {
45 | for (let q in query) {
46 | if (query[q] !== todo[q]) {
47 | return false;
48 | }
49 | }
50 | return true;
51 | }));
52 | }
53 |
54 | /**
55 | * Will retrieve all data from the collection
56 | *
57 | * @param {function} callback The callback to fire upon retrieving data
58 | */
59 | findAll(callback){
60 | if (callback) {
61 | callback.call(this, JSON.parse(localStorage[this._dbName]).todos);
62 | }
63 | }
64 |
65 | /**
66 | * Will save the given data to the DB. If no item exists it will create a new
67 | * item, otherwise it'll simply update an existing item's properties
68 | *
69 | * @param {object} updateData The data to save back into the DB
70 | * @param {function} callback The callback to fire after saving
71 | * @param {number} id An optional param to enter an ID of an item to update
72 | */
73 | save(updateData, callback, id){
74 | const data = JSON.parse(localStorage[this._dbName]);
75 | const todos = data.todos;
76 | const len = todos.length;
77 |
78 | // If an ID was actually given, find the item and update each property
79 | if (id) {
80 | for (let i = 0; i < len; i++) {
81 | if (todos[i].id === id) {
82 | for (let key in updateData) {
83 | todos[i][key] = updateData[key];
84 | }
85 | break;
86 | }
87 | }
88 |
89 | localStorage[this._dbName] = JSON.stringify(data);
90 |
91 | if (callback) {
92 | callback.call(this, JSON.parse(localStorage[this._dbName]).todos);
93 | }
94 | } else {
95 | // Generate an ID
96 | updateData.id = new Date().getTime();
97 |
98 | todos.push(updateData);
99 | localStorage[this._dbName] = JSON.stringify(data);
100 |
101 | if (callback) {
102 | callback.call(this, [updateData]);
103 | }
104 | }
105 | }
106 |
107 | /**
108 | * Will remove an item from the Store based on its ID
109 | *
110 | * @param {number} id The ID of the item you want to remove
111 | * @param {function} callback The callback to fire after saving
112 | */
113 | remove(id, callback){
114 | const data = JSON.parse(localStorage[this._dbName]);
115 | const todos = data.todos;
116 | const len = todos.length;
117 |
118 | for (let i = 0; i < todos.length; i++) {
119 | if (todos[i].id == id) {
120 | todos.splice(i, 1);
121 | break;
122 | }
123 | }
124 |
125 | localStorage[this._dbName] = JSON.stringify(data);
126 |
127 | if (callback) {
128 | callback.call(this, JSON.parse(localStorage[this._dbName]).todos);
129 | }
130 | }
131 |
132 | /**
133 | * Will drop all storage and start fresh
134 | *
135 | * @param {function} callback The callback to fire after dropping the data
136 | */
137 | drop(callback){
138 | localStorage[this._dbName] = JSON.stringify({todos: []});
139 |
140 | if (callback) {
141 | callback.call(this, JSON.parse(localStorage[this._dbName]).todos);
142 | }
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/todomvc/backbone/js/views/app-view.js:
--------------------------------------------------------------------------------
1 | /*global Backbone, jQuery, _, ENTER_KEY */
2 | var app = app || {};
3 |
4 | (function ($) {
5 | 'use strict';
6 |
7 | // The Application
8 | // ---------------
9 |
10 | // Our overall **AppView** is the top-level piece of UI.
11 | app.AppView = Backbone.View.extend({
12 |
13 | // Instead of generating a new element, bind to the existing skeleton of
14 | // the App already present in the HTML.
15 | el: '#todoapp',
16 |
17 | // Our template for the line of statistics at the bottom of the app.
18 | statsTemplate: _.template($('#stats-template').html()),
19 |
20 | // Delegated events for creating new items, and clearing completed ones.
21 | events: {
22 | 'keypress #new-todo': 'createOnEnter',
23 | 'click #clear-completed': 'clearCompleted',
24 | 'click #toggle-all': 'toggleAllComplete'
25 | },
26 |
27 | // At initialization we bind to the relevant events on the `Todos`
28 | // collection, when items are added or changed. Kick things off by
29 | // loading any preexisting todos that might be saved in *localStorage*.
30 | initialize: function () {
31 | this.allCheckbox = this.$('#toggle-all')[0];
32 | this.$input = this.$('#new-todo');
33 | this.$footer = this.$('#footer');
34 | this.$main = this.$('#main');
35 | this.$list = $('#todo-list');
36 |
37 | this.listenTo(app.todos, 'add', this.addOne);
38 | this.listenTo(app.todos, 'reset', this.addAll);
39 | this.listenTo(app.todos, 'change:completed', this.filterOne);
40 | this.listenTo(app.todos, 'filter', this.filterAll);
41 | this.listenTo(app.todos, 'all', this.render);
42 |
43 | // Suppresses 'add' events with {reset: true} and prevents the app view
44 | // from being re-rendered for every model. Only renders when the 'reset'
45 | // event is triggered at the end of the fetch.
46 | app.todos.fetch({reset: true});
47 | },
48 |
49 | // Re-rendering the App just means refreshing the statistics -- the rest
50 | // of the app doesn't change.
51 | render: function () {
52 | var completed = app.todos.completed().length;
53 | var remaining = app.todos.remaining().length;
54 |
55 | if (app.todos.length) {
56 | this.$main.show();
57 | this.$footer.show();
58 |
59 | this.$footer.html(this.statsTemplate({
60 | completed: completed,
61 | remaining: remaining
62 | }));
63 |
64 | this.$('#filters li a')
65 | .removeClass('selected')
66 | .filter('[href="#/' + (app.TodoFilter || '') + '"]')
67 | .addClass('selected');
68 | } else {
69 | this.$main.hide();
70 | this.$footer.hide();
71 | }
72 |
73 | this.allCheckbox.checked = !remaining;
74 | },
75 |
76 | // Add a single todo item to the list by creating a view for it, and
77 | // appending its element to the `
`.
78 | addOne: function (todo) {
79 | var view = new app.TodoView({ model: todo });
80 | this.$list.append(view.render().el);
81 | },
82 |
83 | // Add all items in the **Todos** collection at once.
84 | addAll: function () {
85 | this.$list.html('');
86 | app.todos.each(this.addOne, this);
87 | },
88 |
89 | filterOne: function (todo) {
90 | todo.trigger('visible');
91 | },
92 |
93 | filterAll: function () {
94 | app.todos.each(this.filterOne, this);
95 | },
96 |
97 | // Generate the attributes for a new Todo item.
98 | newAttributes: function () {
99 | return {
100 | title: this.$input.val().trim(),
101 | order: app.todos.nextOrder(),
102 | completed: false
103 | };
104 | },
105 |
106 | // If you hit return in the main input field, create new **Todo** model,
107 | // persisting it to *localStorage*.
108 | createOnEnter: function (e) {
109 | if (e.which === ENTER_KEY && this.$input.val().trim()) {
110 | app.todos.create(this.newAttributes());
111 | this.$input.val('');
112 | }
113 | },
114 |
115 | // Clear all completed todo items, destroying their models.
116 | clearCompleted: function () {
117 | _.invoke(app.todos.completed(), 'destroy');
118 | return false;
119 | },
120 |
121 | toggleAllComplete: function () {
122 | var completed = this.allCheckbox.checked;
123 |
124 | app.todos.each(function (todo) {
125 | todo.save({
126 | 'completed': completed
127 | });
128 | });
129 | }
130 | });
131 | })(jQuery);
132 |
--------------------------------------------------------------------------------
/todomvc/backbone/js/views/todo-view.js:
--------------------------------------------------------------------------------
1 | /*global Backbone, jQuery, _, ENTER_KEY, ESC_KEY */
2 | var app = app || {};
3 |
4 | (function ($) {
5 | 'use strict';
6 |
7 | // Todo Item View
8 | // --------------
9 |
10 | // The DOM element for a todo item...
11 | app.TodoView = Backbone.View.extend({
12 | //... is a list tag.
13 | tagName: 'li',
14 |
15 | // Cache the template function for a single item.
16 | template: _.template($('#item-template').html()),
17 |
18 | // The DOM events specific to an item.
19 | events: {
20 | 'click .toggle': 'toggleCompleted',
21 | 'dblclick label': 'edit',
22 | 'click .destroy': 'clear',
23 | 'keypress .edit': 'updateOnEnter',
24 | 'keydown .edit': 'revertOnEscape',
25 | 'blur .edit': 'close'
26 | },
27 |
28 | // The TodoView listens for changes to its model, re-rendering. Since there's
29 | // a one-to-one correspondence between a **Todo** and a **TodoView** in this
30 | // app, we set a direct reference on the model for convenience.
31 | initialize: function () {
32 | this.listenTo(this.model, 'change', this.render);
33 | this.listenTo(this.model, 'destroy', this.remove);
34 | this.listenTo(this.model, 'visible', this.toggleVisible);
35 | },
36 |
37 | // Re-render the titles of the todo item.
38 | render: function () {
39 | // Backbone LocalStorage is adding `id` attribute instantly after creating a model.
40 | // This causes our TodoView to render twice. Once after creating a model and once on `id` change.
41 | // We want to filter out the second redundant render, which is caused by this `id` change.
42 | // It's known Backbone LocalStorage bug, therefore we've to create a workaround.
43 | // https://github.com/tastejs/todomvc/issues/469
44 | if (this.model.changed.id !== undefined) {
45 | return;
46 | }
47 |
48 | this.$el.html(this.template(this.model.toJSON()));
49 | this.$el.toggleClass('completed', this.model.get('completed'));
50 | this.toggleVisible();
51 | this.$input = this.$('.edit');
52 | return this;
53 | },
54 |
55 | toggleVisible: function () {
56 | this.$el.toggleClass('hidden', this.isHidden());
57 | },
58 |
59 | isHidden: function () {
60 | var isCompleted = this.model.get('completed');
61 | return (// hidden cases only
62 | (!isCompleted && app.TodoFilter === 'completed') ||
63 | (isCompleted && app.TodoFilter === 'active')
64 | );
65 | },
66 |
67 | // Toggle the `"completed"` state of the model.
68 | toggleCompleted: function () {
69 | this.model.toggle();
70 | },
71 |
72 | // Switch this view into `"editing"` mode, displaying the input field.
73 | edit: function () {
74 | this.$el.addClass('editing');
75 | this.$input.focus();
76 | },
77 |
78 | // Close the `"editing"` mode, saving changes to the todo.
79 | close: function () {
80 | var value = this.$input.val();
81 | var trimmedValue = value.trim();
82 |
83 | // We don't want to handle blur events from an item that is no
84 | // longer being edited. Relying on the CSS class here has the
85 | // benefit of us not having to maintain state in the DOM and the
86 | // JavaScript logic.
87 | if (!this.$el.hasClass('editing')) {
88 | return;
89 | }
90 |
91 | if (trimmedValue) {
92 | this.model.save({ title: trimmedValue });
93 |
94 | if (value !== trimmedValue) {
95 | // Model values changes consisting of whitespaces only are not causing change to be triggered
96 | // Therefore we've to compare untrimmed version with a trimmed one to chech whether anything changed
97 | // And if yes, we've to trigger change event ourselves
98 | this.model.trigger('change');
99 | }
100 | } else {
101 | this.clear();
102 | }
103 |
104 | this.$el.removeClass('editing');
105 | },
106 |
107 | // If you hit `enter`, we're through editing the item.
108 | updateOnEnter: function (e) {
109 | if (e.which === ENTER_KEY) {
110 | this.close();
111 | }
112 | },
113 |
114 | // If you're pressing `escape` we revert your change by simply leaving
115 | // the `editing` state.
116 | revertOnEscape: function (e) {
117 | if (e.which === ESC_KEY) {
118 | this.$el.removeClass('editing');
119 | }
120 | },
121 |
122 | // Remove the item, destroy the model from *localStorage* and delete its view.
123 | clear: function () {
124 | this.model.destroy();
125 | }
126 | });
127 | })(jQuery);
128 |
--------------------------------------------------------------------------------
/todomvc/ractive/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Ractive.js • TodoMVC
7 |
8 |
9 |
10 |
11 |
12 |
17 |
18 |
19 |
72 |
73 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/todomvc/react/js/app.jsx:
--------------------------------------------------------------------------------
1 | /*jshint quotmark:false */
2 | /*jshint white:false */
3 | /*jshint trailing:false */
4 | /*jshint newcap:false */
5 | /*global React, Router, ReactDOM*/
6 | var app = app || {};
7 |
8 | (function () {
9 | 'use strict';
10 |
11 | app.ALL_TODOS = 'all';
12 | app.ACTIVE_TODOS = 'active';
13 | app.COMPLETED_TODOS = 'completed';
14 | var TodoFooter = app.TodoFooter;
15 | var TodoItem = app.TodoItem;
16 |
17 | var ENTER_KEY = 13;
18 |
19 | var TodoApp = React.createClass({
20 | getInitialState: function () {
21 | return {
22 | nowShowing: app.ALL_TODOS,
23 | editing: null,
24 | newTodo: ''
25 | };
26 | },
27 |
28 | componentDidMount: function () {
29 | var setState = this.setState;
30 | var router = Router({
31 | '/': setState.bind(this, {nowShowing: app.ALL_TODOS}),
32 | '/active': setState.bind(this, {nowShowing: app.ACTIVE_TODOS}),
33 | '/completed': setState.bind(this, {nowShowing: app.COMPLETED_TODOS})
34 | });
35 | router.init('/');
36 | },
37 |
38 | handleChange: function (event) {
39 | this.setState({newTodo: event.target.value});
40 | },
41 |
42 | handleNewTodoKeyDown: function (event) {
43 | if (event.keyCode !== ENTER_KEY) {
44 | return;
45 | }
46 |
47 | event.preventDefault();
48 |
49 | var val = this.state.newTodo.trim();
50 |
51 | if (val) {
52 | this.props.model.addTodo(val);
53 | this.setState({newTodo: ''});
54 | }
55 | },
56 |
57 | toggleAll: function (event) {
58 | var checked = event.target.checked;
59 | this.props.model.toggleAll(checked);
60 | },
61 |
62 | toggle: function (todoToToggle) {
63 | this.props.model.toggle(todoToToggle);
64 | },
65 |
66 | destroy: function (todo) {
67 | this.props.model.destroy(todo);
68 | },
69 |
70 | edit: function (todo) {
71 | this.setState({editing: todo.id});
72 | },
73 |
74 | save: function (todoToSave, text) {
75 | this.props.model.save(todoToSave, text);
76 | this.setState({editing: null});
77 | },
78 |
79 | cancel: function () {
80 | this.setState({editing: null});
81 | },
82 |
83 | clearCompleted: function () {
84 | this.props.model.clearCompleted();
85 | },
86 |
87 | render: function () {
88 | var footer;
89 | var main;
90 | var todos = this.props.model.todos;
91 |
92 | var shownTodos = todos.filter(function (todo) {
93 | switch (this.state.nowShowing) {
94 | case app.ACTIVE_TODOS:
95 | return !todo.completed;
96 | case app.COMPLETED_TODOS:
97 | return todo.completed;
98 | default:
99 | return true;
100 | }
101 | }, this);
102 |
103 | var todoItems = shownTodos.map(function (todo) {
104 | return (
105 |
115 | );
116 | }, this);
117 |
118 | var activeTodoCount = todos.reduce(function (accum, todo) {
119 | return todo.completed ? accum : accum + 1;
120 | }, 0);
121 |
122 | var completedCount = todos.length - activeTodoCount;
123 |
124 | if (activeTodoCount || completedCount) {
125 | footer =
126 | ;
132 | }
133 |
134 | if (todos.length) {
135 | main = (
136 |
137 |
143 |
144 | {todoItems}
145 |
146 |
147 | );
148 | }
149 |
150 | return (
151 |
152 |
153 |
todos
154 |
162 |
163 | {main}
164 | {footer}
165 |
166 | );
167 | }
168 | });
169 |
170 | var model = new app.TodoModel('react-todos');
171 |
172 | function render() {
173 | ReactDOM.render(
174 | ,
175 | document.getElementsByClassName('todoapp')[0]
176 | );
177 | }
178 |
179 | model.subscribe(render);
180 | render();
181 | })();
182 |
--------------------------------------------------------------------------------
/todomvc/react/js/app.js:
--------------------------------------------------------------------------------
1 | /*jshint quotmark:false */
2 | /*jshint white:false */
3 | /*jshint trailing:false */
4 | /*jshint newcap:false */
5 | /*global React, Router, ReactDOM*/
6 | var app = app || {};
7 |
8 | (function () {
9 | 'use strict';
10 |
11 | app.ALL_TODOS = 'all';
12 | app.ACTIVE_TODOS = 'active';
13 | app.COMPLETED_TODOS = 'completed';
14 | var TodoFooter = React.createFactory(app.TodoFooter);
15 | var TodoItem = React.createFactory(app.TodoItem);
16 |
17 | var ENTER_KEY = 13;
18 |
19 | var TodoApp = React.createClass({
20 | getInitialState: function () {
21 | return {
22 | nowShowing: app.ALL_TODOS,
23 | editing: null,
24 | newTodo: ''
25 | };
26 | },
27 |
28 | componentDidMount: function () {
29 | var setState = this.setState;
30 | var router = Router({
31 | '/': setState.bind(this, {nowShowing: app.ALL_TODOS}),
32 | '/active': setState.bind(this, {nowShowing: app.ACTIVE_TODOS}),
33 | '/completed': setState.bind(this, {nowShowing: app.COMPLETED_TODOS})
34 | });
35 | router.init('/');
36 | },
37 |
38 | handleChange: function (event) {
39 | this.setState({newTodo: event.target.value});
40 | },
41 |
42 | handleNewTodoKeyDown: function (event) {
43 | if (event.keyCode !== ENTER_KEY) {
44 | return;
45 | }
46 |
47 | event.preventDefault();
48 |
49 | var val = this.state.newTodo.trim();
50 |
51 | if (val) {
52 | this.props.model.addTodo(val);
53 | this.setState({newTodo: ''});
54 | }
55 | },
56 |
57 | toggleAll: function (event) {
58 | var checked = event.target.checked;
59 | this.props.model.toggleAll(checked);
60 | },
61 |
62 | toggle: function (todoToToggle) {
63 | this.props.model.toggle(todoToToggle);
64 | },
65 |
66 | destroy: function (todo) {
67 | this.props.model.destroy(todo);
68 | },
69 |
70 | edit: function (todo) {
71 | this.setState({editing: todo.id});
72 | },
73 |
74 | save: function (todoToSave, text) {
75 | this.props.model.save(todoToSave, text);
76 | this.setState({editing: null});
77 | },
78 |
79 | cancel: function () {
80 | this.setState({editing: null});
81 | },
82 |
83 | clearCompleted: function () {
84 | this.props.model.clearCompleted();
85 | },
86 |
87 | render: function () {
88 | var footer;
89 | var main;
90 | var todos = this.props.model.todos;
91 |
92 | var shownTodos = todos.filter(function (todo) {
93 | switch (this.state.nowShowing) {
94 | case app.ACTIVE_TODOS:
95 | return !todo.completed;
96 | case app.COMPLETED_TODOS:
97 | return todo.completed;
98 | default:
99 | return true;
100 | }
101 | }, this);
102 |
103 | var todoItems = shownTodos.map(function (todo) {
104 | return (
105 | TodoItem({
106 | key: todo.id,
107 | todo: todo,
108 | onToggle: this.toggle.bind(this, todo),
109 | onDestroy: this.destroy.bind(this, todo),
110 | onEdit: this.edit.bind(this, todo),
111 | editing: this.state.editing === todo.id,
112 | onSave: this.save.bind(this, todo),
113 | onCancel: this.cancel}
114 | )
115 | );
116 | }, this);
117 |
118 | var activeTodoCount = todos.reduce(function (accum, todo) {
119 | return todo.completed ? accum : accum + 1;
120 | }, 0);
121 |
122 | var completedCount = todos.length - activeTodoCount;
123 |
124 | if (activeTodoCount || completedCount) {
125 | footer =
126 | TodoFooter({
127 | count: activeTodoCount,
128 | completedCount: completedCount,
129 | nowShowing: this.state.nowShowing,
130 | onClearCompleted: this.clearCompleted}
131 | );
132 | }
133 |
134 | if (todos.length) {
135 | main = (
136 | React.createElement('section', {className: "main"}, [
137 | React.createElement('input', {
138 | className: "toggle-all",
139 | type: "checkbox",
140 | onChange: this.toggleAll,
141 | checked: activeTodoCount === 0}
142 | ),
143 | React.createElement('ul', {className: "todo-list"}, [
144 | todoItems
145 | ])
146 | ])
147 | );
148 | }
149 |
150 | return (
151 | React.createElement('div', null, [
152 | React.createElement('header', {className: "header"}, [
153 | React.createElement('h1', null, ["todos"]),
154 | React.createElement('input', {
155 | className: "new-todo",
156 | placeholder: "What needs to be done?",
157 | value: this.state.newTodo,
158 | onKeyDown: this.handleNewTodoKeyDown,
159 | onChange: this.handleChange,
160 | autoFocus: true}
161 | )
162 | ]),
163 | main,
164 | footer
165 | ])
166 | );
167 | }
168 | });
169 |
170 | var model = new app.TodoModel('react-todos');
171 |
172 | function render() {
173 | ReactDOM.render(
174 | React.createFactory(TodoApp)({model: model}),
175 | document.getElementsByClassName('todoapp')[0]
176 | );
177 | }
178 |
179 | window.Utils = app.Utils
180 | model.subscribe(render);
181 | render();
182 | })();
183 |
--------------------------------------------------------------------------------
/todomvc/ractive/js/app.js:
--------------------------------------------------------------------------------
1 | /*global window, Ractive */
2 | (function (window, Ractive) {
3 | 'use strict';
4 |
5 | // Create some filter functions, which we'll need later
6 | var filters = {
7 | completed: function (item) { return item.completed; },
8 | active: function (item) { return !item.completed; }
9 | };
10 |
11 | // The keycode for the 'enter' and 'escape' keys
12 | var ENTER_KEY = 13;
13 | var ESCAPE_KEY = 27;
14 |
15 | // Create our Ractive instance
16 | var todoList = new Ractive({
17 | // Specify a target element - an ID, a CSS selector, or the element itself
18 | el: 'todoapp',
19 |
20 | // Specify a template, or the ID of a script tag containing the template
21 | template: '#main',
22 |
23 | // This is our viewmodel - as well as our list of tasks (which gets added
24 | // later from localStorage - see persistence.js), it includes helper
25 | // functions and computed values
26 | data: {
27 | filter: function (item) {
28 | // Because we're doing `this.get('currentFilter')`, Ractive understands
29 | // that this function needs to be re-executed reactively when the value of
30 | // `currentFilter` changes
31 | var currentFilter = this.get('currentFilter');
32 |
33 | if (currentFilter === 'all') {
34 | return true;
35 | }
36 |
37 | return filters[currentFilter](item);
38 | },
39 |
40 | // completedTasks() and activeTasks() are computed values, that will update
41 | // our app view reactively whenever `items` changes (including changes to
42 | // child properties like `items[1].completed`)
43 | completedTasks: function () {
44 | return this.get('items').filter(filters.completed);
45 | },
46 |
47 | activeTasks: function () {
48 | return this.get('items').filter(filters.active);
49 | },
50 |
51 | // By default, show all tasks. This value changes when the route changes
52 | // (see routes.js)
53 | currentFilter: 'all'
54 | },
55 |
56 | // We can define custom events. Here, we're defining an `enter` event,
57 | // and an `escape` event, which fire when the user hits those keys while
58 | // an input is focused:
59 | //
60 | //
61 | events: (function () {
62 | var makeCustomEvent = function (keyCode) {
63 | return function (node, fire) {
64 | var keydownHandler = function (event) {
65 | if (event.which === keyCode) {
66 | fire({
67 | node: node,
68 | original: event
69 | });
70 | }
71 | };
72 |
73 | node.addEventListener('keydown', keydownHandler, false);
74 |
75 | return {
76 | teardown: function () {
77 | node.removeEventListener('keydown', keydownHandler, false);
78 | }
79 | };
80 | };
81 | };
82 |
83 | return {
84 | enter: makeCustomEvent(ENTER_KEY),
85 | escape: makeCustomEvent(ESCAPE_KEY)
86 | };
87 | }())
88 | });
89 |
90 |
91 | // Here, we're defining how to respond to user interactions. Unlike many
92 | // libraries, where you use CSS selectors to dictate what event corresponds
93 | // to what action, in Ractive the 'meaning' of the event is baked into the
94 | // template itself (e.g. ).
95 | todoList.on({
96 |
97 | // Removing a todo is as straightforward as splicing it out of the array -
98 | // Ractive intercepts calls to array mutator methods and updates the view
99 | // accordingly. The DOM is updated in the most efficient manner possible.
100 | remove: function (event, index) {
101 | this.get('items').splice(index, 1);
102 | },
103 |
104 | // The `event` object contains useful properties for (e.g.) retrieving
105 | // data from the DOM
106 | newTodo: function (event) {
107 | var description = event.node.value.trim();
108 |
109 | if (!description) {
110 | return;
111 | }
112 |
113 | this.get('items').push({
114 | description: description,
115 | completed: false
116 | });
117 |
118 | event.node.value = '';
119 | },
120 |
121 | edit: function (event) {
122 | this.set(event.keypath + '.editing', true);
123 | this.nodes.edit.value = event.context.description;
124 | },
125 |
126 | submit: function (event) {
127 | var description = event.node.value.trim();
128 |
129 | if (!description) {
130 | this.get('items').splice(event.index.i, 1);
131 | return;
132 | }
133 |
134 | this.set(event.keypath + '.description', description);
135 | this.set(event.keypath + '.editing', false);
136 | },
137 |
138 | cancel: function (event) {
139 | this.set(event.keypath + '.editing', false);
140 | },
141 |
142 | clearCompleted: function () {
143 | var items = this.get('items');
144 | var i = items.length;
145 |
146 | while (i--) {
147 | if (items[i].completed) {
148 | items.splice(i, 1);
149 | }
150 | }
151 | },
152 |
153 | toggleAll: function (event) {
154 | var i = this.get('items').length;
155 | var completed = event.node.checked;
156 | var changeHash = {};
157 |
158 | while (i--) {
159 | changeHash['items[' + i + '].completed'] = completed;
160 | }
161 |
162 | this.set(changeHash);
163 | }
164 | });
165 |
166 | window.todoList = todoList;
167 |
168 | })(window, Ractive);
169 |
--------------------------------------------------------------------------------
/todomvc/mercury/render.js:
--------------------------------------------------------------------------------
1 | var mercury = require("../../index.js")
2 | var h = require("../../index.js").h
3 |
4 | var doMutableFocus = require("./lib/do-mutable-focus.js")
5 |
6 | var ESCAPE = 27
7 | var footer = infoFooter()
8 |
9 | module.exports = render
10 |
11 | function render(state) {
12 | return h(".todomvc-wrapper", [
13 | h("link", {
14 | rel: "stylesheet",
15 | href: "https://rawgithub.com/raynos/mercury/master/examples/todomvc/style.css"
16 | }),
17 | h("section#todoapp.todoapp", [
18 | mercury.partial(header, state.field, state.events),
19 | mainSection(state.todos, state.route, state.events),
20 | mercury.partial(statsSection, state.todos, state.route, state.events)
21 | ]),
22 | footer
23 | ])
24 | }
25 |
26 | function header(field, events) {
27 | return h("header#header.header", {
28 | "data-event": [
29 | mercury.changeEvent(events.setTodoField),
30 | mercury.submitEvent(events.add)
31 | ]
32 | }, [
33 | h("h1", "Todos"),
34 | h("input#new-todo.new-todo", {
35 | placeholder: "What needs to be done?",
36 | autofocus: true,
37 | value: field.text,
38 | name: "newTodo"
39 | })
40 | ])
41 | }
42 |
43 | function mainSection(todos, route, events) {
44 | var allCompleted = todos.every(function (todo) {
45 | return todo.completed
46 | })
47 | var visibleTodos = todos.filter(function (todo) {
48 | return route === "completed" && todo.completed ||
49 | route === "active" && !todo.completed ||
50 | route === "all"
51 | })
52 |
53 | return h("section#main.main", { hidden: !todos.length }, [
54 | h("input#toggle-all.toggle-all", {
55 | type: "checkbox",
56 | name: "toggle",
57 | checked: allCompleted,
58 | "data-change": mercury.valueEvent(events.toggleAll)
59 | }),
60 | h("label", { htmlFor: "toggle-all" }, "Mark all as complete"),
61 | h("ul#todo-list.todolist", visibleTodos.map(function (todo) {
62 | return todoItem(todo, events)
63 | }))
64 | ])
65 | }
66 |
67 | function todoItem(todo, events) {
68 | var className = (todo.completed ? "completed " : "") +
69 | (todo.editing ? "editing" : "")
70 |
71 | return h("li", { className: className, key: todo.id }, [
72 | h(".view", [
73 | h("input.toggle", {
74 | type: "checkbox",
75 | checked: todo.completed,
76 | "data-change": mercury.event(events.toggle, {
77 | id: todo.id,
78 | completed: !todo.completed
79 | })
80 | }),
81 | h("label", {
82 | "data-dblclick": mercury.event(events.startEdit, { id: todo.id })
83 | }, todo.title),
84 | h("button.destroy", {
85 | "data-click": mercury.event(events.destroy, { id: todo.id })
86 | })
87 | ]),
88 | h("input.edit", {
89 | value: todo.title,
90 | name: "title",
91 | // when we need an RPC invocation we add a
92 | // custom mutable operation into the tree to be
93 | // invoked at patch time
94 | "data-focus": todo.editing ? doMutableFocus() : null,
95 | "data-keydown": mercury.keyEvent(events.cancelEdit, ESCAPE, { id: todo.id }),
96 | "data-event": mercury.submitEvent(events.finishEdit, { id: todo.id }),
97 | "data-blur": mercury.valueEvent(events.finishEdit, { id: todo.id })
98 | })
99 | ])
100 | }
101 |
102 | function statsSection(todos, route, events) {
103 | var todosLeft = todos.filter(function (todo) {
104 | return !todo.completed
105 | }).length
106 | var todosCompleted = todos.length - todosLeft
107 |
108 | return h("footer#footer.footer", { hidden: !todos.length }, [
109 | h("span#todo-count.todo-count", [
110 | h("strong", String(todosLeft)),
111 | todosLeft === 1 ? " item" : " items",
112 | " left"
113 | ]),
114 | h("ul#filters.filters", [
115 | link("#/", "All", route === "all"),
116 | link("#/active", "Active", route === "active"),
117 | link("#/completed", "Completed", route === "completed")
118 | ]),
119 | h("button.clear-completed#clear-completed", {
120 | hidden: todosCompleted === 0,
121 | "data-click": mercury.event(events.clearCompleted)
122 | }, "Clear completed (" + String(todosCompleted) + ")")
123 | ])
124 | }
125 |
126 | function link(uri, text, isSelected) {
127 | return h("li", [
128 | h("a", { className: isSelected ? "selected" : "", href: uri }, text)
129 | ])
130 | }
131 |
132 | function infoFooter() {
133 | return h("footer#info.info", [
134 | h("p", "Double-click to edit a todo"),
135 | h("p", [
136 | "Written by ",
137 | h("a", { href: "https://github.com/Raynos" }, "Raynos")
138 | ]),
139 | h("p", [
140 | "Part of ",
141 | h("a", { href: "http://todomvc.com" }, "TodoMVC")
142 | ])
143 | ])
144 | }
145 |
--------------------------------------------------------------------------------
/todomvc/vanilla-es6/dist/store.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
4 |
5 | Object.defineProperty(exports, "__esModule", {
6 | value: true
7 | });
8 |
9 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
10 |
11 | /*jshint eqeqeq:false */
12 |
13 | /**
14 | * Creates a new client side storage object and will create an empty
15 | * collection if no collection already exists.
16 | *
17 | * @param {string} name The name of our DB we want to use
18 | * @param {function} callback Our fake DB uses callbacks because in
19 | * real life you probably would be making AJAX calls
20 | */
21 |
22 | var Store = function () {
23 | function Store(name, callback) {
24 | _classCallCheck(this, Store);
25 |
26 | this._dbName = name;
27 |
28 | if (!localStorage[name]) {
29 | var data = {
30 | todos: []
31 | };
32 |
33 | localStorage[name] = JSON.stringify(data);
34 | }
35 |
36 | if (callback) {
37 | callback.call(this, JSON.parse(localStorage[name]));
38 | }
39 | }
40 |
41 | /**
42 | * Finds items based on a query given as a JS object
43 | *
44 | * @param {object} query The query to match against (i.e. {foo: 'bar'})
45 | * @param {function} callback The callback to fire when the query has
46 | * completed running
47 | *
48 | * @example
49 | * db.find({foo: 'bar', hello: 'world'}, function (data) {
50 | * // data will return any items that have foo: bar and
51 | * // hello: world in their properties
52 | * })
53 | */
54 |
55 | _createClass(Store, [{
56 | key: "find",
57 | value: function find(query, callback) {
58 | var todos = JSON.parse(localStorage[this._dbName]).todos;
59 |
60 | callback.call(this, todos.filter(function (todo) {
61 | for (var q in query) {
62 | if (query[q] !== todo[q]) {
63 | return false;
64 | }
65 | }
66 | return true;
67 | }));
68 | }
69 |
70 | /**
71 | * Will retrieve all data from the collection
72 | *
73 | * @param {function} callback The callback to fire upon retrieving data
74 | */
75 |
76 | }, {
77 | key: "findAll",
78 | value: function findAll(callback) {
79 | if (callback) {
80 | callback.call(this, JSON.parse(localStorage[this._dbName]).todos);
81 | }
82 | }
83 |
84 | /**
85 | * Will save the given data to the DB. If no item exists it will create a new
86 | * item, otherwise it'll simply update an existing item's properties
87 | *
88 | * @param {object} updateData The data to save back into the DB
89 | * @param {function} callback The callback to fire after saving
90 | * @param {number} id An optional param to enter an ID of an item to update
91 | */
92 |
93 | }, {
94 | key: "save",
95 | value: function save(updateData, callback, id) {
96 | var data = JSON.parse(localStorage[this._dbName]);
97 | var todos = data.todos;
98 | var len = todos.length;
99 |
100 | // If an ID was actually given, find the item and update each property
101 | if (id) {
102 | for (var i = 0; i < len; i++) {
103 | if (todos[i].id === id) {
104 | for (var key in updateData) {
105 | todos[i][key] = updateData[key];
106 | }
107 | break;
108 | }
109 | }
110 |
111 | localStorage[this._dbName] = JSON.stringify(data);
112 |
113 | if (callback) {
114 | callback.call(this, JSON.parse(localStorage[this._dbName]).todos);
115 | }
116 | } else {
117 | // Generate an ID
118 | updateData.id = new Date().getTime();
119 |
120 | todos.push(updateData);
121 | localStorage[this._dbName] = JSON.stringify(data);
122 |
123 | if (callback) {
124 | callback.call(this, [updateData]);
125 | }
126 | }
127 | }
128 |
129 | /**
130 | * Will remove an item from the Store based on its ID
131 | *
132 | * @param {number} id The ID of the item you want to remove
133 | * @param {function} callback The callback to fire after saving
134 | */
135 |
136 | }, {
137 | key: "remove",
138 | value: function remove(id, callback) {
139 | var data = JSON.parse(localStorage[this._dbName]);
140 | var todos = data.todos;
141 | var len = todos.length;
142 |
143 | for (var i = 0; i < todos.length; i++) {
144 | if (todos[i].id == id) {
145 | todos.splice(i, 1);
146 | break;
147 | }
148 | }
149 |
150 | localStorage[this._dbName] = JSON.stringify(data);
151 |
152 | if (callback) {
153 | callback.call(this, JSON.parse(localStorage[this._dbName]).todos);
154 | }
155 | }
156 |
157 | /**
158 | * Will drop all storage and start fresh
159 | *
160 | * @param {function} callback The callback to fire after dropping the data
161 | */
162 |
163 | }, {
164 | key: "drop",
165 | value: function drop(callback) {
166 | localStorage[this._dbName] = JSON.stringify({ todos: [] });
167 |
168 | if (callback) {
169 | callback.call(this, JSON.parse(localStorage[this._dbName]).todos);
170 | }
171 | }
172 | }]);
173 |
174 | return Store;
175 | }();
176 |
177 | exports.default = Store;
--------------------------------------------------------------------------------