Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Use immutable data structures#9

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Closed
jorinvo wants to merge2 commits intocyclejs:masterfromjorinvo:immutable
Closed
Show file tree
Hide file tree
Changes fromall 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
12 changes: 6 additions & 6 deletionspackage.json
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,16 +9,16 @@
"license": "MIT",
"private": true,
"devDependencies": {
"babelify": "^6.0.2",
"browserify": "^10.0.0",
"cyclejs": "0.21.1",
"immutable": "^3.7.3",
"todomvc-app-css": "^1.0.0",
"todomvc-common": "^1.0.1",
"babel": "^5.1.13",
"babelify": "^6.0.2",
"browserify": "^10.0.0"
"uglifyjs": "^2.4.10"
},
"scripts": {
"build-debug": "mkdir -p js && browserify src/app.js -t babelify --outfile js/app.js",
"uglify": "uglifyjs js/app.js -o js/app.min.js",
"build": "npm run build-debug && npm run uglify"
"build-debug": "browserify src/app.js -d -t babelify > js/app.js",
"build": "browserify src/app.js -t babelify | uglifyjs -c > js/app.js"
}
}
99 changes: 42 additions & 57 deletionssrc/models/todos.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,73 @@
import Cycle from 'cyclejs';
import {Map} from 'immutable';
Copy link
Author

Choose a reason for hiding this comment

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

Not sure if it's good practice to haveMap conflicting with the native one in new JS engines ...

Choose a reason for hiding this comment

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

there's no conflict, a module is a new scope: it's not overwritten


function getFilterFn(route) {
switch (route) {
case '/active': return (task =>task.completed === false);
case '/completed': return (task =>task.completed === true);
case '/active': return (x =>!x.get('completed'));
case '/completed': return (x =>x.get('completed'));
default: return () => true; // allow anything
}
}

function determineFilter(todosData, route) {
todosData.filter = route.replace('/', '').trim();
todosData.filterFn = getFilterFn(route);
return todosData;
}

function searchTodoIndex(todosList, todoid) {
let top = todosList.length;
let bottom = 0;
let pointerId;
let index;
while (true) { // binary search
index = bottom + ((top - bottom) >> 1);
pointerId = todosList[index].id;
if (pointerId === todoid) {
return index;
} else if (pointerId < todoid) {
bottom = index;
} else if (pointerId > todoid) {
top = index;
}
}
return todosData
.set('filter', route.replace('/', '').trim())
.set('filterFn', getFilterFn(route));
}

function makeModification$(intent) {
let clearInputMod$ = intent.clearInput$.map(() => (todosData) => {
todosData.input = '';
return todosData;
let clearInputMod$ = intent.clearInput$.map(() => todosData => {
return todosData.set('input', '');
});

let insertTodoMod$ = intent.insertTodo$.map((todoTitle) =>(todosData) => {
letlastId = todosData.list.length > 0 ?
todosData.list[todosData.list.length - 1].id :
0;
todosData.list.push({
let insertTodoMod$ = intent.insertTodo$.map(todoTitle => todosData => {
letlist = todosData.get('list');
let lastId =list.size ? list.last().get('id') : 0;

let todo = Map({
id: lastId + 1,
title: todoTitle,
completed: false
});
todosData.input = '';
return todosData;

return todosData.update('list', list => list.push(todo).set('input', ''));
});

let editTodoMod$ = intent.editTodo$.map((evdata) => (todosData) => {
let todoIndex = searchTodoIndex(todosData.list, evdata.id);
todosData.list[todoIndex].title = evdata.content;
return todosData;
let editTodoMod$ = intent.editTodo$.map(evdata => todosData => {
let todoIndex = todosData.get('list')
.findIndex(x => x.get('id') === evdata.id);

return todosData.update('list', list =>
list.update(todoIndex, x => x.set('title', evdata.content))
);
});

let toggleTodoMod$ = intent.toggleTodo$.map((todoid) => (todosData) => {
let todoIndex = searchTodoIndex(todosData.list, todoid);
let previousCompleted = todosData.list[todoIndex].completed;
todosData.list[todoIndex].completed = !previousCompleted;
return todosData;
let toggleTodoMod$ = intent.toggleTodo$.map(todoId => todosData => {
let todoIndex = todosData.get('list')
.findIndex(x => x.get('id') === todoId);

return todosData.update('list', list =>
list.update(todoIndex, x => x.set('completed', !x.get('completed')))
);
});

let toggleAllMod$ = intent.toggleAll$.map(() => (todosData) => {
let allAreCompleted = todosData.list
.reduce((x, y) => x && y.completed, true);
todosData.list.forEach((todoData) => {
todoData.completed = allAreCompleted ? false : true;
});
return todosData;
let toggleAllMod$ = intent.toggleAll$.map(() => todosData => {
let state = todosData.get('list').some(x => !x.get('completed'));
return todosData.update('list', list =>
list.map(x => x.set('completed', state))
);
});

let deleteTodoMod$ = intent.deleteTodo$.map((todoid) =>(todosData) => {
let todoIndex = searchTodoIndex(todosData.list, todoid);
todosData.list.splice(todoIndex, 1);
return todosData;
let deleteTodoMod$ = intent.deleteTodo$.map(todoId => todosData => {
returntodosData.update('list', list =>
list.filter(x => x.get('id') !== todoId)
);
});

let deleteCompletedsMod$ = intent.deleteCompleteds$.map(() =>(todosData) => {
todosData.list = todosData.list
.filter(todoData =>todoData.completed === false);
return todosData
let deleteCompletedsMod$ = intent.deleteCompleteds$.map(() => todosData => {
returntodosData.update('list',list =>
list.filter(x =>!x.get('completed'))
);
});

return Cycle.Rx.Observable.merge(
Expand Down
10 changes: 3 additions & 7 deletionssrc/sinks/local-storage.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
export default function localStorageSink(todosData) {

// Observe all todos data and save them to localStorage
let savedTodosData = {
list: todosData.list.map(todoData =>
({
title: todoData.title,
completed: todoData.completed,
id: todoData.id
})
)
list: todosData.get('list').filter(x => x ).toJS()
Copy link
Author

Choose a reason for hiding this comment

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

Sometimes I gotnull values in the list. Don't know if this was a testing issue or something about immutable.js I haven't discovered yet..
That's why I filter the values here ...

};

localStorage.setItem('todos-cycle', JSON.stringify(savedTodosData))
};
20 changes: 4 additions & 16 deletionssrc/sources/todos.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,16 @@
import Cycle from 'cyclejs';
import {fromJS} from 'immutable';

function merge() {
let result = {};
for (let i = 0; i < arguments.length; i++) {
let object = arguments[i];
for (let key in object) {
if (object.hasOwnProperty(key)) {
result[key] = object[key];
}
}
}
return result;
}

let defaultTodosData = {
let defaultTodosData = fromJS({
list: [],
input: '',
filter: '',
filterFn: () => true // allow anything
};
});

let storedTodosData = JSON.parse(localStorage.getItem('todos-cycle')) || {};

let initialTodosData = merge(defaultTodosData,storedTodosData);
let initialTodosData =defaultTodosData.merge(storedTodosData);

export default {
todosData$: Cycle.Rx.Observable.just(initialTodosData)
Expand Down
30 changes: 17 additions & 13 deletionssrc/views/todos.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,7 +7,7 @@ function vrenderHeader(todosData) {
h('h1', 'todos'),
h('input#new-todo', {
type: 'text',
value: propHook(elem =>{elem.value = todosData.input; }),
value: propHook(elem => elem.value = todosData.get('input')),
attributes: {
placeholder: 'What needs to be done?'
},
Expand All@@ -18,16 +18,19 @@ function vrenderHeader(todosData) {
}

function vrenderMainSection(todosData) {
let allCompleted = todosData.list.reduce((x, y) => x && y.completed, true);
let list = todosData.get('list');
let allCompleted = list.every(x => x.get('completed'));

return h('section#main', {
style: {'display':todosData.list.length ? '' : 'none'}
style: {'display': list.size ? '' : 'none'}
}, [
h('input#toggle-all', {
type: 'checkbox',
checked: allCompleted
}),
h('ul#todo-list', todosData.list
.filter(todosData.filterFn)
h('ul#todo-list', list
.filter(todosData.get('filterFn'))
.toJS()
Copy link
Author

Choose a reason for hiding this comment

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

I don't know if it is better to case to JS before the map or after.
Doesn't matter that much I guess. My thought was that it might be more performant this way.

.map(todoData =>
h('todo-item.todo-item', {
key: todoData.id,
Expand All@@ -41,30 +44,31 @@ function vrenderMainSection(todosData) {
}

function vrenderFooter(todosData) {
let amountCompleted = todosData.list
.filter(todoData => todoData.completed)
.length;
let amountActive = todosData.list.length - amountCompleted;
let list = todosData.get('list');
let filter = todosData.get('filter');
let amountCompleted = list.count(x => x.get('completed'));
let amountActive = list.size - amountCompleted;

return h('footer#footer', {
style: {'display':todosData.list.length ? '' : 'none'}
style: {'display': list.size ? '' : 'none'}
}, [
h('span#todo-count', [
h('strong', String(amountActive)),
' item' + (amountActive !== 1 ? 's' : '') + ' left'
]),
h('ul#filters', [
h('li', [
h('a' + (todosData.filter === '' ? '.selected' : ''), {
h('a' + (filter === '' ? '.selected' : ''), {
attributes: {'href': '#/'}
}, 'All')
]),
h('li', [
h('a' + (todosData.filter === 'active' ? '.selected' : ''), {
h('a' + (filter === 'active' ? '.selected' : ''), {
attributes: {'href': '#/active'}
}, 'Active')
]),
h('li', [
h('a' + (todosData.filter === 'completed' ? '.selected' : ''), {
h('a' + (filter === 'completed' ? '.selected' : ''), {
attributes: {'href': '#/completed'}
}, 'Completed')
])
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp