-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 99f3904
Showing
13 changed files
with
377 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
/* CSS declarations go here */ | ||
body { | ||
font-family: sans-serif; | ||
background-color: #315481; | ||
background-image: linear-gradient(to bottom, #315481, #918e82 100%); | ||
background-attachment: fixed; | ||
|
||
position: absolute; | ||
top: 0; | ||
bottom: 0; | ||
left: 0; | ||
right: 0; | ||
|
||
padding: 0; | ||
margin: 0; | ||
|
||
font-size: 14px; | ||
} | ||
|
||
.container { | ||
max-width: 600px; | ||
margin: 0 auto; | ||
min-height: 100%; | ||
background: white; | ||
} | ||
|
||
header { | ||
background: #d2edf4; | ||
background-image: linear-gradient(to bottom, #d0edf5, #e1e5f0 100%); | ||
padding: 20px 15px 15px 15px; | ||
position: relative; | ||
} | ||
|
||
#login-buttons { | ||
display: block; | ||
} | ||
|
||
h1 { | ||
font-size: 1.5em; | ||
margin: 0; | ||
margin-bottom: 10px; | ||
display: inline-block; | ||
margin-right: 1em; | ||
} | ||
|
||
form { | ||
margin-top: 10px; | ||
margin-bottom: -10px; | ||
position: relative; | ||
} | ||
|
||
.new-task input { | ||
box-sizing: border-box; | ||
padding: 10px 0; | ||
background: transparent; | ||
border: none; | ||
width: 100%; | ||
padding-right: 80px; | ||
font-size: 1em; | ||
} | ||
|
||
.new-task input:focus{ | ||
outline: 0; | ||
} | ||
|
||
ul { | ||
margin: 0; | ||
padding: 0; | ||
background: white; | ||
} | ||
|
||
.delete { | ||
float: right; | ||
font-weight: bold; | ||
background: none; | ||
font-size: 1em; | ||
border: none; | ||
position: relative; | ||
} | ||
|
||
li { | ||
position: relative; | ||
list-style: none; | ||
padding: 15px; | ||
border-bottom: #eee solid 1px; | ||
} | ||
|
||
li .text { | ||
margin-left: 10px; | ||
} | ||
|
||
li.checked { | ||
color: #888; | ||
} | ||
|
||
li.checked .text { | ||
text-decoration: line-through; | ||
} | ||
|
||
li.private { | ||
background: #eee; | ||
border-color: #ddd; | ||
} | ||
|
||
header .hide-completed { | ||
float: right; | ||
} | ||
|
||
.toggle-private { | ||
margin-left: 5px; | ||
} | ||
|
||
@media (max-width: 600px) { | ||
li { | ||
padding: 12px 15px; | ||
} | ||
|
||
.search { | ||
width: 150px; | ||
clear: both; | ||
} | ||
|
||
.new-task input { | ||
padding-bottom: 5px; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<head> | ||
<title>simple</title> | ||
</head> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
import '../imports/startup/accounts-config.js'; | ||
import '../imports/ui/body.js'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { Meteor } from 'meteor/meteor'; | ||
import { Mongo } from 'meteor/mongo'; | ||
import { check } from 'meteor/check'; | ||
|
||
export const Tasks = new Mongo.Collection('tasks'); | ||
|
||
if (Meteor.isServer) { | ||
// This code only runs on the server | ||
// Only publish tasks that are public or belong to the current user | ||
Meteor.publish('tasks', function tasksPublication() { | ||
return Tasks.find({ | ||
$or: [ | ||
{ private: { $ne: true } }, | ||
{ owner: this.userId }, | ||
], | ||
}); | ||
}); | ||
} | ||
|
||
Meteor.methods({ | ||
'tasks.insert'(text) { | ||
check(text, String); | ||
|
||
// Make sure the user is logged in before inserting a task | ||
if (! this.userId) { | ||
throw new Meteor.Error('not-authorized'); | ||
} | ||
|
||
Tasks.insert({ | ||
text, | ||
createdAt: new Date(), | ||
owner: this.userId, | ||
username: Meteor.users.findOne(this.userId).username, | ||
}); | ||
}, | ||
'tasks.remove'(taskId) { | ||
check(taskId, String); | ||
|
||
const task = Tasks.findOne(taskId); | ||
if (task.private && task.owner !== this.userId) { | ||
// If the task is private, make sure only the owner can delete it | ||
throw new Meteor.Error('not-authorized'); | ||
} | ||
|
||
Tasks.remove(taskId); | ||
}, | ||
'tasks.setChecked'(taskId, setChecked) { | ||
check(taskId, String); | ||
check(setChecked, Boolean); | ||
|
||
const task = Tasks.findOne(taskId); | ||
if (task.private && task.owner !== this.userId) { | ||
// If the task is private, make sure only the owner can check it off | ||
throw new Meteor.Error('not-authorized'); | ||
} | ||
|
||
Tasks.update(taskId, { $set: { checked: setChecked } }); | ||
}, | ||
'tasks.setPrivate'(taskId, setToPrivate) { | ||
check(taskId, String); | ||
check(setToPrivate, Boolean); | ||
|
||
const task = Tasks.findOne(taskId); | ||
|
||
// Make sure only the task owner can make a task private | ||
if (task.owner !== this.userId) { | ||
throw new Meteor.Error('not-authorized'); | ||
} | ||
|
||
Tasks.update(taskId, { $set: { private: setToPrivate } }); | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* eslint-env mocha */ | ||
|
||
import { Meteor } from 'meteor/meteor'; | ||
import { Random } from 'meteor/random'; | ||
import { assert } from 'meteor/practicalmeteor:chai'; | ||
|
||
import { Tasks } from './tasks.js'; | ||
|
||
if (Meteor.isServer) { | ||
describe('Tasks', () => { | ||
describe('methods', () => { | ||
const userId = Random.id(); | ||
let taskId; | ||
|
||
beforeEach(() => { | ||
Tasks.remove({}); | ||
taskId = Tasks.insert({ | ||
text: 'test task', | ||
createdAt: new Date(), | ||
owner: userId, | ||
username: 'tmeasday', | ||
}); | ||
}); | ||
|
||
it('can delete owned task', () => { | ||
// Find the internal implementation of the task method so we can | ||
// test it in isolation | ||
const deleteTask = Meteor.server.method_handlers['tasks.remove']; | ||
|
||
// Set up a fake method invocation that looks like what the method expects | ||
const invocation = { userId }; | ||
|
||
// Run the method with `this` set to the fake invocation | ||
deleteTask.apply(invocation, [taskId]); | ||
|
||
// Verify that the method does what we expected | ||
assert.equal(Tasks.find().count(), 0); | ||
}); | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { Accounts } from 'meteor/accounts-base'; | ||
|
||
Accounts.ui.config({ | ||
passwordSignupFields: 'USERNAME_ONLY', | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<body> | ||
<div class="container"> | ||
<header> | ||
<h1>Todo List ({{incompleteCount}})</h1> | ||
|
||
<label class="hide-completed"> | ||
<input type="checkbox" /> | ||
Hide Completed Tasks | ||
</label> | ||
|
||
{{> loginButtons}} | ||
|
||
{{#if currentUser}} | ||
<form class="new-task"> | ||
<input type="text" name="text" placeholder="Type to add new tasks" /> | ||
</form> | ||
{{/if}} | ||
</header> | ||
|
||
<ul> | ||
{{#each tasks}} | ||
{{> task}} | ||
{{/each}} | ||
</ul> | ||
</div> | ||
</body> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { Meteor } from 'meteor/meteor'; | ||
import { Template } from 'meteor/templating'; | ||
import { ReactiveDict } from 'meteor/reactive-dict'; | ||
|
||
import { Tasks } from '../api/tasks.js'; | ||
|
||
import './task.js'; | ||
import './body.html'; | ||
|
||
Template.body.onCreated(function bodyOnCreated() { | ||
this.state = new ReactiveDict(); | ||
Meteor.subscribe('tasks'); | ||
}); | ||
|
||
Template.body.helpers({ | ||
tasks() { | ||
const instance = Template.instance(); | ||
if (instance.state.get('hideCompleted')) { | ||
// If hide completed is checked, filter tasks | ||
return Tasks.find({ checked: { $ne: true } }, { sort: { createdAt: -1 } }); | ||
} | ||
// Otherwise, return all of the tasks | ||
return Tasks.find({}, { sort: { createdAt: -1 } }); | ||
}, | ||
incompleteCount() { | ||
return Tasks.find({ checked: { $ne: true } }).count(); | ||
}, | ||
}); | ||
|
||
Template.body.events({ | ||
'submit .new-task'(event) { | ||
// Prevent default browser form submit | ||
event.preventDefault(); | ||
|
||
// Get value from form element | ||
const target = event.target; | ||
const text = target.text.value; | ||
|
||
// Insert a task into the collection | ||
Meteor.call('tasks.insert', text); | ||
|
||
// Clear form | ||
target.text.value = ''; | ||
}, | ||
'change .hide-completed input'(event, instance) { | ||
instance.state.set('hideCompleted', event.target.checked); | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<template name="task"> | ||
<li class="{{#if checked}}checked{{/if}} {{#if private}}private{{/if}}"> | ||
<button class="delete">×</button> | ||
|
||
<input type="checkbox" checked="{{checked}}" class="toggle-checked" /> | ||
|
||
{{#if isOwner}} | ||
<button class="toggle-private"> | ||
{{#if private}} | ||
Private | ||
{{else}} | ||
Public | ||
{{/if}} | ||
</button> | ||
{{/if}} | ||
|
||
<span class="text"><strong>{{username}}</strong> - {{text}}</span> | ||
</li> | ||
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { Meteor } from 'meteor/meteor'; | ||
import { Template } from 'meteor/templating'; | ||
|
||
import './task.html'; | ||
|
||
Template.task.helpers({ | ||
isOwner() { | ||
return this.owner === Meteor.userId(); | ||
}, | ||
}); | ||
|
||
Template.task.events({ | ||
'click .toggle-checked'() { | ||
// Set the checked property to the opposite of its current value | ||
Meteor.call('tasks.setChecked', this._id, !this.checked); | ||
}, | ||
'click .delete'() { | ||
Meteor.call('tasks.remove', this._id); | ||
}, | ||
'click .toggle-private'() { | ||
Meteor.call('tasks.setPrivate', this._id, !this.private); | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"name": "mindcontrol2", | ||
"private": true, | ||
"scripts": { | ||
"start": "meteor run" | ||
}, | ||
"dependencies": { | ||
"meteor-node-stubs": "~0.2.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
import '../imports/api/tasks.js'; |