diff --git a/.gitignore b/.gitignore index 3c3629e6..f0449be1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ node_modules +js/result.js +.idea diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml new file mode 100644 index 00000000..a698bcc5 --- /dev/null +++ b/.idea/jsLibraryMappings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html index b092a0ab..b62f3fc2 100644 --- a/index.html +++ b/index.html @@ -8,6 +8,7 @@ +
@@ -15,6 +16,8 @@

todos

+ +
@@ -22,54 +25,65 @@

todos

- + diff --git a/js/EventEmitter.js b/js/EventEmitter.js new file mode 100644 index 00000000..dbdd27f7 --- /dev/null +++ b/js/EventEmitter.js @@ -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]; + } + } + +} diff --git a/js/api.js b/js/api.js new file mode 100644 index 00000000..348de285 --- /dev/null +++ b/js/api.js @@ -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')); + } +}; diff --git a/js/app.js b/js/app.js index c2c7396c..776e66cd 100644 --- a/js/app.js +++ b/js/app.js @@ -2,5 +2,6 @@ 'use strict'; // Your starting point. Enjoy the ride! + // Write npm run watch-js to start coding })(window); diff --git a/js/model.js b/js/model.js new file mode 100644 index 00000000..b72910e2 --- /dev/null +++ b/js/model.js @@ -0,0 +1,55 @@ +'use strict'; +const api = require('./api'); + +class Model { + var store = { + 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; diff --git a/js/view.js b/js/view.js new file mode 100644 index 00000000..6c3c87a3 --- /dev/null +++ b/js/view.js @@ -0,0 +1,7 @@ +const Handlebars = require('handlebars'); + +var source = $("todo").html(); +var template = Handlebars.compile(source); +var context = { todo: [{name: "first task"}, {name:"second task"}] }; +var html = template(context); +$("document").append(html); diff --git a/package.json b/package.json index e939a50f..614dc4c7 100644 --- a/package.json +++ b/package.json @@ -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" } } diff --git a/readme.md b/readme.md index 2d139eb8..bab3d966 100644 --- a/readme.md +++ b/readme.md @@ -17,3 +17,8 @@ ## License Creative Commons License
This work by TasteJS is licensed under a Creative Commons Attribution 4.0 International License. + +## Usage (build js) + +`npm run build-js` (just build js file) +`npm run watch-js` (start watching your js file)