Skip to content

Commit

Permalink
initial_commit
Browse files Browse the repository at this point in the history
  • Loading branch information
akeshavan committed Jun 30, 2016
0 parents commit 99f3904
Show file tree
Hide file tree
Showing 13 changed files with 377 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
126 changes: 126 additions & 0 deletions client/main.css
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;
}
}
3 changes: 3 additions & 0 deletions client/main.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<head>
<title>simple</title>
</head>
2 changes: 2 additions & 0 deletions client/main.js
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';
72 changes: 72 additions & 0 deletions imports/api/tasks.js
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 } });
},
});
41 changes: 41 additions & 0 deletions imports/api/tasks.tests.js
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);
});
});
});
}
5 changes: 5 additions & 0 deletions imports/startup/accounts-config.js
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',
});
26 changes: 26 additions & 0 deletions imports/ui/body.html
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>
48 changes: 48 additions & 0 deletions imports/ui/body.js
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);
},
});
19 changes: 19 additions & 0 deletions imports/ui/task.html
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">&times;</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>
23 changes: 23 additions & 0 deletions imports/ui/task.js
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);
},
});
10 changes: 10 additions & 0 deletions package.json
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"
}
}
1 change: 1 addition & 0 deletions server/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '../imports/api/tasks.js';

0 comments on commit 99f3904

Please sign in to comment.