Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Model impl #7

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
node_modules
js/result.js
.idea
7 changes: 7 additions & 0 deletions .idea/jsLibraryMappings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

84 changes: 49 additions & 35 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,68 +8,82 @@
<link rel="stylesheet" href="node_modules/todomvc-app-css/index.css">
<!-- CSS overrides - remove if you don't need it -->
<link rel="stylesheet" href="css/app.css">
<script src="js/view.js"></script>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Скрипт добавлен в страницу, а через browserify ты его не прогнал.
Нужно добавить его сборку в package.json/scripts, либо сделать require в app.js (recommended).

</head>
<body>
<section class="todoapp">
<header class="header">
<h1>todos</h1>
<input class="new-todo" placeholder="What needs to be done?" autofocus>
</header>


<!-- This section should be hidden by default and shown when there are todos -->
<section class="main">
<input class="toggle-all" type="checkbox">
<label for="toggle-all">Mark all as complete</label>
<ul class="todo-list">
<!-- These are here just to show the structure of the list items -->
<!-- List items should get the class `editing` when editing and `completed` when marked as completed -->
<li class="completed">
<div class="view">
<input class="toggle" type="checkbox" checked>
<label>Taste JavaScript</label>
<button class="destroy"></button>
</div>
<input class="edit" value="Create a TodoMVC template">
</li>
<li>
<div class="view">
<input class="toggle" type="checkbox">
<label>Buy a unicorn</label>
<button class="destroy"></button>
</div>
<input class="edit" value="Rule the web">
</li>
<script id="todo" type="text/x-handlebars-template">
{{#each todo}}
<li>
<div class="view">
<input class="toggle" type="checkbox">
<label>{{name}}</label>
<button class="destroy"></button>
</div>
<input class="edit" value="Create a TodoMVC template">
</li>
{{/each}}
</script>
<!--<li class="completed">-->
<!--<div class="view">-->
<!--<input class="toggle" type="checkbox" checked>-->
<!--<label>Taste JavaScript</label>-->
<!--<button class="destroy"></button>-->
<!--</div>-->
<!--<input class="edit" value="Create a TodoMVC template">-->
<!--</li>-->
<!--<li>-->
<!--<div class="view">-->
<!--<input class="toggle" type="checkbox">-->
<!--<label>Buy a unicorn</label>-->
<!--<button class="destroy"></button>-->
<!--</div>-->
<!--<input class="edit" value="Rule the web">-->
<!--</li>-->
</ul>
</section>
<!-- This footer should hidden by default and shown when there are todos -->
<footer class="footer">
<!-- This should be `0 items left` by default -->
<span class="todo-count"><strong>0</strong> item left</span>
<script id="item_left" type="text/x-handlebars-template">
<span class="todo-count"><strong>{{left}}</strong> item left</span>
</script>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Лучше описать все шаблоны в одном месте, не вкладывая их в другие элементы. Например в head.
Но лучше вынести их в скрипты. Так твое view станет независимым от документа.

<!-- Remove this if you don't implement routing -->
<ul class="filters">
<li>
<a class="selected" href="#/">All</a>
</li>
<li>
<a href="#/active">Active</a>
</li>
<li>
<a href="#/completed">Completed</a>
</li>
</ul>
<!--<ul class="filters">-->
<!--<li>-->
<!--<a class="selected" href="#/">All</a>-->
<!--</li>-->
<!--<li>-->
<!--<a href="#/active">Active</a>-->
<!--</li>-->
<!--<li>-->
<!--<a href="#/completed">Completed</a>-->
<!--</li>-->
<!--</ul>-->
<!-- Hidden if no completed items are left ↓ -->
<button class="clear-completed">Clear completed</button>
<!--<button class="clear-completed">Clear completed</button>-->
</footer>
</section>
<footer class="info">
<p>Double-click to edit a todo</p>
<!-- Remove the below line ↓ -->
<p>Template by <a href="http://sindresorhus.com">Sindre Sorhus</a></p>
<!--<p>Double-click to edit a todo</p>-->
<!-- Change this out with your name and url ↓ -->
<p>Created by <a href="http://todomvc.com">you</a></p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
<p>Created by <a href="https://github.com/EJohnF/">Evstropov Evgenii</a></p>
</footer>
<!-- Scripts here. Don't remove ↓ -->
<script src="node_modules/todomvc-common/base.js"></script>
<script src="js/app.js"></script>
<script src="js/result.js"></script>
</body>
</html>
67 changes: 67 additions & 0 deletions js/EventEmitter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
'use strict';
export default class EventEmitter {
listeners = {};
observables = {};

/*
methods for observable object
*/
// subscribe to event
on(eventName, handler) {
if (typeof this.listeners[eventName] === 'undefined') {
this.listeners[eventName] = [];
}
this.listeners[eventName].push(handler);
}
// rise the event
emit(eventName, ...args) {
if (typeof this.listeners[eventName] !== 'undefined') {
this.listeners[eventName].forEach(func => {
func(eventName, ...args);
});
}
}
//unsubscribe from event
off(eventName, handler) {
if (typeof this.listeners[eventName] !== 'undefined') {
this.listeners[eventName] = this.listeners[eventName].filter(listen => handler != listen);
}
}
//remove all subscribers
removeAll(eventName) {
delete this.listeners[eventName];
}

/*
methods for listener object
*/

// connect handler method to listen eventName of observable object
listenTo(observable, eventName, handler) {
if (typeof observable.on === 'undefined' ||
typeof observable.off === 'undefined') {
throw new Error('There are not "on" or "off" methods');
}
observable.on(eventName, handler);
if (typeof this.observables[eventName] === 'undefined') {
this.observables[eventName] = [];
}
this.observables[eventName].push({observable, handler});

}

unlistenFrom(observable, eventName) {
observable.off(eventName, this.observables[eventName].handler);
if (typeof this.observables[eventName] !== 'undefined') {
this.observables[eventName] = this.observables[eventName].filter(obs => obs.observable !== observable);
}
}

unlistenAll() {
for (let key in this.observables) {
this.observables[key].forEach(obs => obs.observable.off(key, obs.handler));
delete this.observables[key];
}
}

}
9 changes: 9 additions & 0 deletions js/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports={
save: (store)=>{
//TODO better to surround it by try-catch
localStorage.setItem('store', JSON.stringify(store));
},
load: ()=>{
return JSON.parse(localStorage.getItem('store'));
}
};
1 change: 1 addition & 0 deletions js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
'use strict';

// Your starting point. Enjoy the ride!
// Write npm run watch-js to start coding

})(window);
55 changes: 55 additions & 0 deletions js/model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
'use strict';
const api = require('./api');

class Model {
var store = {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В es6 нельзя так инициализировать поля. Их надо заполнять в конструкторе.

lastId: -1,
todo: [
{
id: 0,
name: 'task for test',
isCompleted: false
}
]
};
constructor(){
this.addTask = this.addTask.bind(this);
this.removeTask = this.removeTask.bind(this);
this.toggleTask = this.toggleTask.bind(this);
this.removeAll = this.removeAll.bind(this);
this.save = this.save.bind(this);
this.load = this.load.bind(this);
}
addTask(name, isCompleted = true) {
var id = this.store.lastId + 1;
this.store.todo.push({id:id, name: name, isCompleted: isCompleted});
this.store.lastId = id;
return id;
}
removeTask(id){
this.store.todo = this.store.todo.filter(todo => todo.id !== id);
}
toggleTask(id){
this.store.todo = this.store.map(todo =>{
if (todo!== id)
return todo;
else {
todo.isCompleted = !todo.isCompleted;
return todo;
}
});
}
removeAll(){
this.store.todo = [];
this.store.lastId = -1;
}
save(){
api.save(this.store);
}
load(){
this.store = api.load();
}

}

module.exports = Model;
7 changes: 7 additions & 0 deletions js/view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const Handlebars = require('handlebars');

var source = $("todo").html();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ты обращаешься к элементу по id, а не по тегу. Нужно писать $("#todo")

var template = Handlebars.compile(source);
var context = { todo: [{name: "first task"}, {name:"second task"}] };
var html = template(context);
$("document").append(html);
9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
{
"private": true,
"dependencies": {
"browserify": "^13.1.1",
"handlebars": "^4.0.6",
"todomvc-app-css": "^2.0.0",
"todomvc-common": "^1.0.0"
"todomvc-common": "^1.0.0",
"watchify": "^3.7.0"
},
"scripts": {
"build-js": "browserify js/app.js > js/result.js",
"watch-js": "watchify js/app.js -o js/result.js"
}
}
5 changes: 5 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@
## License

<a rel="license" href="http://creativecommons.org/licenses/by/4.0/deed.en_US"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by/4.0/80x15.png" /></a><br />This <span xmlns:dct="http://purl.org/dc/terms/" href="http://purl.org/dc/dcmitype/InteractiveResource" rel="dct:type">work</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="http://sindresorhus.com" property="cc:attributionName" rel="cc:attributionURL">TasteJS</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/deed.en_US">Creative Commons Attribution 4.0 International License</a>.

## Usage (build js)

`npm run build-js` (just build js file)
`npm run watch-js` (start watching your js file)