<!DOCTYPE html>
<html>
<head>
<link href="//cdn.jsdelivr.net/picnicss/5.1.0/picnic.min.css" rel="stylesheet" />
<link href="//cdn.jsdelivr.net/picnicss/5.1.0/plugins.min.css" rel="stylesheet" />
</head>
<body>
<h1>Hello Mag.JS - Redux Todos!</h1>
<a target="_tab" href="https://github.com/magnumjs/mag.js">GitHub</a>
<hr/> (based on <a href="https://github.com/chrisharrington/react-todo">React-Todo</a>)
<div class="container content">
<div id="app">
<div class="container">
<div class="row">
<div class="col-md-8">
<h2>Todo List</h2>
<status>Loading ..</status>
</div>
<div class="col-md-4">
<label for="modal_1" type="button" class="btn btn-primary pull-right spacing-top button">New Task</label>
</div>
</div>
<div class="row">
<div class="col-md-6">
<h3 class="spacing-bottom">Incomplete</h3>
<listIncomplete>
</listIncomplete>
</div>
<div class="col-md-6">
<h3 class="spacing-bottom">Complete</h3>
<listComplete>
</listComplete>
</div>
</div>
<div id="modal">
<div class="modal">
<input id="modal_1" type="checkbox" />
<label for="modal_1" class="overlay"></label>
<article>
<header>
<h3>New Task</h3>
<label for="modal_1" class="close">×</label>
</header>
<section class="content">
<input name="text" class="field" />
</section>
<footer>
<a class="button" href="#">Save</a>
<label for="modal_1" class="button dangerous">
Close
</label>
</footer>
</article>
</div>
</div>
</div>
</div>
</div>
<div style="display:none;">
<div id="lister">
<div class="list-group card">
<renderItems>
<item></item>
</renderItems>
</div>
</div>
</div>
<div style="display:none;">
<div id="item">
<header class="list-group-item pointer">
<span class="button stack icon-picture" data-bind="name">Home</span>
</header>
</div>
</div>
<script src="//rawgit.com/magnumjs/mag.js/master/dist/mag.0.21.3.min.js"></script>
<script src="//rawgit.com/magnumjs/mag.js/master/dist/mag.addons.0.21.min.js"></script>
<script src="//rawgit.com/magnumjs/mag.js/master/dist/mag-redux.0.22.min.js"></script>
<script src="//rawgit.com/magnumjs/mag.js/master/src/addons/redux-middleware.js"></script>
<script src="item.js"></script>
<script src="modal.js"></script>
<script src="list.js"></script>
<script src="app.js"></script>
<script src="redux.js"></script>
<script src="boot.js"></script>
</body>
</html>
//Component definition and instance creation - not executed
var app = mag.create('app', {
controller: function(props) {
// get all todos
props.getAllTodos()
modaler({
isVisible: props.isVisible,
onSave: function(data) {
props.createTodo({
name: data.name
});
}
});
},
view: function(state, props) {
mag.show(!props.todos.data.length, state.status = {});
if (props.todos.data.length) {
state.listIncomplete = this.renderList(props.todos.data, false, props.update);
state.listComplete = this.renderList(props.todos.data, true, props.update);
}
},
renderList: function(todos, complete, update) {
var filteredItems = todos.filter(function(x) {
return x.isComplete === complete;
});
return lister({
update: update,
key: Math.random(),
items: filteredItems
})
}
}, {
isVisible: null
});
var magRedux = (function() {
//Action types:
var constants = {
todo: {
GET_ALL_TODOS: "GET_ALL_TODOS",
ADD_TODO: "ADD_TODO",
UPDATE: "UPDATE"
}
};
//Redux State reducer:
var reducer = function(state, action) {
if (!state) {
return {
data: [],
text: "ZZZ"
};
}
function setState(state, change) {
return Object.assign({}, state, change);
}
switch (action.type) {
case constants.todo.UPDATE:
var found = state.data.findIndex(function(item) {
return item.id == action.todo.id;
});
state.data[found] = action.todo;
return setState(state, {
data: state.data
});
case constants.todo.GET_ALL_TODOS:
return setState(state, {
data: action.todos
});
case constants.todo.ADD_TODO:
action.todo.id = Math.max.apply(Math, state.data.map(function(o) {
return o.id;
})) + 1;
action.todo.isComplete = false;
state.data.push(action.todo);
return setState(state, {
text: action.todo.name,
data: state.data
});
default:
return state;
}
};
//Actions:
var actions = {
createTodo: function(todo) {
return {
type: constants.todo.ADD_TODO,
todo: todo
}
},
update: function(todo) {
return {
type: constants.todo.UPDATE,
todo: todo
}
},
getAllTodos: function() {
return function(dispatch) {
mag.request({
url: 'todos.json',
cache: false
}).then(function(data) {
// dispatch when completed
dispatch({
todos: data,
type: constants.todo.GET_ALL_TODOS
});
})
};
},
clickText: function(text) {
return {
type: constants.todo.ADD_TODO,
text: text
}
}
};
return {
constants: constants,
reducer: reducer,
actions: actions
}
})();
//Connect & run Component:
mag.reduxConnect({}, magRedux.actions, {
"todos": magRedux.reducer
}, [Redux.middle.logger, Redux.middle.readyStatePromise])(app);
var lister = mag.create('lister', {
view: function(state, props) {
state.renderItems =
props.items.map(function(item, i) {
return {
item: itemer({
key: props.key + i,
todo: item,
toggle: function(iteme) {
iteme.isComplete = !iteme.isComplete;
props.update(iteme);
}.bind({}, item)
})
}
})
}
})
var itemer = mag.create('item', {
view: function(state, props) {
state.header = {
name: props.todo.name,
_onClick: props.toggle
}
}
});
[
{
"id": 1,
"name": "Pick up milk",
"isComplete": false
},
{
"id": 2,
"name": "Pick up dry cleaning",
"isComplete": true
},
{
"id": 3,
"name": "Grocery shopping",
"isComplete": false
},
{
"id": 4,
"name": "Hem pants",
"isComplete": false
},
{
"id": 5,
"name": "Oil change",
"isComplete": true
}
]
var modaler = mag.create('modal', {
controller: function(props) {
this.text = '';
},
view: function(state, props) {
state.modal_1 = {
_checked: typeof props.isVisible != 'undefined' ? props.isVisible : null
}
state.a = {
_onClick: function() {
props.onSave({
name: state.text
});
state.text = '';
props.isVisible = false;
}
}
}
})