mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Add simple-todos example apps
This commit is contained in:
12
History.md
12
History.md
@@ -230,13 +230,15 @@
|
||||
|
||||
### `meteor` command-line tool
|
||||
|
||||
* There are two new example apps that can be used as starting points for
|
||||
developing Meteor apps with React and Angular. They include the necessary
|
||||
packages for the relevant view layer and don't include Blaze. Use them with:
|
||||
* You can now create three new example apps with the command line tool. These
|
||||
are the apps from the official tutorials at http://meteor.com/tutorials, which
|
||||
demonstrate building the same app with Blaze, Angular, and React. Try these
|
||||
apps with:
|
||||
|
||||
```sh
|
||||
meteor create --example react
|
||||
meteor create --example angular
|
||||
meteor create --example simple-todos
|
||||
meteor create --example simple-todos-react
|
||||
meteor create --example simple-todos-angular
|
||||
```
|
||||
|
||||
* `meteor shell` no longer crashes when piped from another command.
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
# Meteor packages used by this project, one per line.
|
||||
# Check this file (and the other files in this directory) into your repository.
|
||||
#
|
||||
# 'meteor add' and 'meteor remove' will edit this file for you,
|
||||
# but you can also edit it by hand.
|
||||
|
||||
meteor-base # Packages every Meteor app needs to have
|
||||
mobile-experience # Packages for a great mobile UX
|
||||
mongo # The database Meteor supports right now
|
||||
session # Client-side reactive dictionary for your app
|
||||
jquery # Helpful client-side library
|
||||
tracker # Meteor's client-side reactive programming library
|
||||
|
||||
standard-minifiers # JS/CSS minifiers run for production mode
|
||||
es5-shim # ECMAScript 5 compatibility for older browsers.
|
||||
ecmascript # Enable ECMAScript2015+ syntax in app code
|
||||
|
||||
autopublish # Publish all data to the clients (for prototyping)
|
||||
insecure # Allow all DB writes from clients (for prototyping)
|
||||
|
||||
static-html # Render static HTML content
|
||||
react # Everything you need to use React with Meteor
|
||||
@@ -1 +0,0 @@
|
||||
METEOR@1.2-rc.15
|
||||
@@ -1,73 +0,0 @@
|
||||
autopublish@1.0.4-rc.0
|
||||
autoupdate@1.2.3-rc.1
|
||||
babel-compiler@5.8.22-rc.1
|
||||
babel-runtime@0.1.4-rc.0
|
||||
base64@1.0.4-rc.0
|
||||
binary-heap@1.0.4-rc.0
|
||||
blaze@2.1.3-rc.0
|
||||
blaze-tools@1.0.4-rc.0
|
||||
boilerplate-generator@1.0.4-rc.1
|
||||
caching-compiler@1.0.0-rc.0
|
||||
caching-html-compiler@1.0.1-rc.0
|
||||
callback-hook@1.0.4-rc.0
|
||||
check@1.0.6-rc.0
|
||||
coffeescript@1.0.8-rc.4
|
||||
cosmos:browserify@0.4.0
|
||||
ddp@1.2.1-rc.0
|
||||
ddp-client@1.2.1-rc.2
|
||||
ddp-common@1.2.1-rc.0
|
||||
ddp-server@1.2.1-rc.2
|
||||
deps@1.0.8-rc.0
|
||||
diff-sequence@1.0.1-rc.0
|
||||
ecmascript@0.1.3-rc.3
|
||||
ecmascript-collections@0.1.5-rc.1
|
||||
ejson@1.0.7-rc.0
|
||||
es5-shim@0.1.0-rc.0
|
||||
fastclick@1.0.7-rc.0
|
||||
geojson-utils@1.0.4-rc.0
|
||||
hot-code-push@1.0.0-rc.0
|
||||
html-tools@1.0.5-rc.0
|
||||
htmljs@1.0.5-rc.1
|
||||
http@1.1.1-rc.1
|
||||
id-map@1.0.4-rc.0
|
||||
insecure@1.0.4-rc.0
|
||||
jquery@1.11.4-rc.0
|
||||
jsx@0.2.1
|
||||
launch-screen@1.0.3-rc.1
|
||||
livedata@1.0.14-rc.0
|
||||
logging@1.0.8-rc.1
|
||||
meteor@1.1.7-rc.2
|
||||
meteor-base@1.0.1-rc.0
|
||||
minifiers@1.1.6-rc.1
|
||||
minimongo@1.0.9-rc.0
|
||||
mobile-experience@1.0.1-rc.0
|
||||
mobile-status-bar@1.0.5-rc.1
|
||||
mongo@1.1.1-rc.4
|
||||
mongo-id@1.0.1-rc.0
|
||||
npm-mongo@1.4.39-rc.0_1
|
||||
observe-sequence@1.0.7-rc.0
|
||||
ordered-dict@1.0.4-rc.0
|
||||
promise@0.4.8-rc.0
|
||||
random@1.0.4-rc.0
|
||||
react@0.1.12
|
||||
react-meteor-data@0.1.8
|
||||
react-runtime@0.13.3_6
|
||||
react-runtime-dev@0.13.3_5
|
||||
react-runtime-prod@0.13.3_4
|
||||
reactive-dict@1.1.1-rc.0
|
||||
reactive-var@1.0.6-rc.0
|
||||
reload@1.1.4-rc.0
|
||||
retry@1.0.4-rc.0
|
||||
routepolicy@1.0.6-rc.0
|
||||
session@1.1.1-rc.0
|
||||
spacebars@1.0.7-rc.0
|
||||
spacebars-compiler@1.0.7-rc.0
|
||||
standard-minifiers@1.0.0-rc.2
|
||||
static-html@1.0.0-rc.5
|
||||
templating-tools@1.0.0-rc.0
|
||||
tracker@1.0.8-rc.0
|
||||
ui@1.0.7-rc.0
|
||||
underscore@1.0.4-rc.0
|
||||
url@1.0.5-rc.0
|
||||
webapp@1.2.2-rc.3
|
||||
webapp-hashing@1.0.4-rc.0
|
||||
@@ -1,11 +0,0 @@
|
||||
<head>
|
||||
<title>react-skel</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Welcome to Meteor and React!</h1>
|
||||
|
||||
<p><a href="https://www.meteor.com/tutorials/react">Try the tutorial!</a></p>
|
||||
|
||||
<div id="react-container"></div>
|
||||
</body>
|
||||
@@ -1,65 +0,0 @@
|
||||
// A collection that is synchronized across client and server with the
|
||||
// 'autopublish' package. To control where the data is accessible from, remove
|
||||
// 'autopublish' and use Meteor.publish and Meteor.subscribe
|
||||
Items = new Mongo.Collection("items");
|
||||
|
||||
// A React component, defined in the normal way
|
||||
App = React.createClass({
|
||||
mixins: [ReactMeteorData],
|
||||
|
||||
// Load data from collections inside this special method enabled by the
|
||||
// ReactMeteorData mixin. The results are attached to this.data on the
|
||||
// component
|
||||
getMeteorData() {
|
||||
return {
|
||||
items: Items.find().fetch()
|
||||
};
|
||||
},
|
||||
|
||||
addItem() {
|
||||
const nextIndex = Items.find().count() + 1;
|
||||
|
||||
// We can insert from the client because we have the 'insecure' package
|
||||
// installed. Remove it and use Meteor methods for better security
|
||||
Items.insert({
|
||||
text: "Hello world! " + nextIndex
|
||||
});
|
||||
},
|
||||
|
||||
renderItems() {
|
||||
return this.data.items.map((item) => {
|
||||
return (
|
||||
<li key={item._id}>
|
||||
{item.text}
|
||||
</li>
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<ul>
|
||||
{this.renderItems()}
|
||||
</ul>
|
||||
|
||||
<button onClick={this.addItem}>
|
||||
Add item
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
if (Meteor.isClient) {
|
||||
// Code here runs on the client only
|
||||
|
||||
Meteor.startup(() => {
|
||||
// Make sure to render after startup so the DOM is ready
|
||||
React.render(<App />, document.getElementById("react-container"));
|
||||
});
|
||||
}
|
||||
|
||||
if (Meteor.isServer) {
|
||||
// Code inside here will run on the server only
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
/* CSS declarations go here */
|
||||
@@ -6,6 +6,3 @@ notices-for-0.9.0
|
||||
notices-for-0.9.1
|
||||
0.9.4-platform-file
|
||||
notices-for-facebook-graph-api-2
|
||||
1.2.0-standard-minifiers-package
|
||||
1.2.0-meteor-platform-split
|
||||
1.2.0-cordova-changes
|
||||
10
examples/simple-todos-angular/.meteor/packages
Normal file
10
examples/simple-todos-angular/.meteor/packages
Normal file
@@ -0,0 +1,10 @@
|
||||
# Meteor packages used by this project, one per line.
|
||||
# Check this file (and the other files in this directory) into your repository.
|
||||
#
|
||||
# 'meteor add' and 'meteor remove' will edit this file for you,
|
||||
# but you can also edit it by hand.
|
||||
|
||||
meteor-platform
|
||||
urigo:angular
|
||||
accounts-ui
|
||||
accounts-password
|
||||
1
examples/simple-todos-angular/.meteor/release
Normal file
1
examples/simple-todos-angular/.meteor/release
Normal file
@@ -0,0 +1 @@
|
||||
METEOR@1.1.0.2
|
||||
61
examples/simple-todos-angular/.meteor/versions
Normal file
61
examples/simple-todos-angular/.meteor/versions
Normal file
@@ -0,0 +1,61 @@
|
||||
accounts-base@1.2.0
|
||||
accounts-password@1.1.1
|
||||
accounts-ui@1.1.5
|
||||
accounts-ui-unstyled@1.1.7
|
||||
angular:angular@1.4.2
|
||||
autoupdate@1.2.1
|
||||
base64@1.0.3
|
||||
binary-heap@1.0.3
|
||||
blaze@2.1.2
|
||||
blaze-tools@1.0.3
|
||||
boilerplate-generator@1.0.3
|
||||
callback-hook@1.0.3
|
||||
check@1.0.5
|
||||
dburles:mongo-collection-instances@0.3.4
|
||||
ddp@1.1.0
|
||||
deps@1.0.7
|
||||
ejson@1.0.6
|
||||
email@1.0.6
|
||||
fastclick@1.0.3
|
||||
geojson-utils@1.0.3
|
||||
html-tools@1.0.4
|
||||
htmljs@1.0.4
|
||||
http@1.1.0
|
||||
id-map@1.0.3
|
||||
jquery@1.11.3_2
|
||||
json@1.0.3
|
||||
lai:collection-extensions@0.1.4
|
||||
launch-screen@1.0.2
|
||||
less@1.0.14
|
||||
livedata@1.0.13
|
||||
localstorage@1.0.3
|
||||
logging@1.0.7
|
||||
meteor@1.1.6
|
||||
meteor-platform@1.2.2
|
||||
minifiers@1.1.5
|
||||
minimongo@1.0.8
|
||||
mobile-status-bar@1.0.3
|
||||
mongo@1.1.0
|
||||
npm-bcrypt@0.7.8_2
|
||||
observe-sequence@1.0.6
|
||||
ordered-dict@1.0.3
|
||||
random@1.0.3
|
||||
reactive-dict@1.1.0
|
||||
reactive-var@1.0.5
|
||||
reload@1.1.3
|
||||
retry@1.0.3
|
||||
routepolicy@1.0.5
|
||||
service-configuration@1.0.4
|
||||
session@1.1.0
|
||||
sha@1.0.3
|
||||
spacebars@1.0.6
|
||||
spacebars-compiler@1.0.6
|
||||
srp@1.0.3
|
||||
templating@1.1.1
|
||||
tracker@1.0.7
|
||||
ui@1.0.6
|
||||
underscore@1.0.3
|
||||
urigo:angular@0.9.2
|
||||
url@1.0.4
|
||||
webapp@1.2.0
|
||||
webapp-hashing@1.0.3
|
||||
9
examples/simple-todos-angular/README.md
Normal file
9
examples/simple-todos-angular/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Simple Todo List
|
||||
|
||||
The Meteor Tutorial app, angular-meteor version.
|
||||
|
||||
Use it to share a single todo list with your friends. The list updates on everyone's screen in real time, and you can make tasks private if you don't want others to see them.
|
||||
|
||||
Learn how to build this app by following the [Meteor Tutorial - Angular version](https://www.meteor.com/tutorials/angular/creating-an-app).
|
||||
|
||||

|
||||
127
examples/simple-todos-angular/simple-todos-angular.css
Normal file
127
examples/simple-todos-angular/simple-todos-angular.css
Normal file
@@ -0,0 +1,127 @@
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
7
examples/simple-todos-angular/simple-todos-angular.html
Normal file
7
examples/simple-todos-angular/simple-todos-angular.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<head>
|
||||
<title>Todo List</title>
|
||||
</head>
|
||||
|
||||
<body ng-include="'todos-list.ng.html'"
|
||||
ng-controller="TodosListCtrl">
|
||||
</body>
|
||||
113
examples/simple-todos-angular/simple-todos-angular.js
Normal file
113
examples/simple-todos-angular/simple-todos-angular.js
Normal file
@@ -0,0 +1,113 @@
|
||||
Tasks = new Mongo.Collection('tasks');
|
||||
|
||||
if (Meteor.isClient) {
|
||||
|
||||
Accounts.ui.config({
|
||||
passwordSignupFields: "USERNAME_ONLY"
|
||||
});
|
||||
|
||||
// This code only runs on the client
|
||||
angular.module('simple-todos',['angular-meteor']);
|
||||
|
||||
function onReady() {
|
||||
angular.bootstrap(document, ['simple-todos']);
|
||||
}
|
||||
|
||||
if (Meteor.isCordova)
|
||||
angular.element(document).on('deviceready', onReady);
|
||||
else
|
||||
angular.element(document).ready(onReady);
|
||||
|
||||
angular.module('simple-todos').controller('TodosListCtrl', ['$scope', '$meteor',
|
||||
function ($scope, $meteor) {
|
||||
|
||||
$scope.$meteorSubscribe('tasks');
|
||||
|
||||
$scope.tasks = $meteor.collection(function() {
|
||||
return Tasks.find($scope.getReactively('query'), {sort: {createdAt: -1}})
|
||||
});
|
||||
|
||||
$scope.addTask = function (newTask) {
|
||||
$meteor.call('addTask', newTask);
|
||||
};
|
||||
|
||||
$scope.deleteTask = function (task) {
|
||||
$meteor.call('deleteTask', task._id);
|
||||
};
|
||||
|
||||
$scope.setChecked = function (task) {
|
||||
$meteor.call('setChecked', task._id, !task.checked);
|
||||
};
|
||||
|
||||
$scope.setPrivate = function (task) {
|
||||
$meteor.call('setPrivate', task._id, ! task.private);
|
||||
};
|
||||
|
||||
$scope.$watch('hideCompleted', function() {
|
||||
if ($scope.hideCompleted)
|
||||
$scope.query = {checked: {$ne: true}};
|
||||
else
|
||||
$scope.query = {};
|
||||
});
|
||||
|
||||
$scope.incompleteCount = function () {
|
||||
return Tasks.find({ checked: {$ne: true} }).count();
|
||||
};
|
||||
|
||||
}]);
|
||||
}
|
||||
|
||||
Meteor.methods({
|
||||
addTask: function (text) {
|
||||
// Make sure the user is logged in before inserting a task
|
||||
if (! Meteor.userId()) {
|
||||
throw new Meteor.Error('not-authorized');
|
||||
}
|
||||
|
||||
Tasks.insert({
|
||||
text: text,
|
||||
createdAt: new Date(),
|
||||
owner: Meteor.userId(),
|
||||
username: Meteor.user().username
|
||||
});
|
||||
},
|
||||
deleteTask: function (taskId) {
|
||||
var task = Tasks.findOne(taskId);
|
||||
if (task.private && task.owner !== Meteor.userId()) {
|
||||
// If the task is private, make sure only the owner can delete it
|
||||
throw new Meteor.Error('not-authorized');
|
||||
}
|
||||
|
||||
Tasks.remove(taskId);
|
||||
},
|
||||
setChecked: function (taskId, setChecked) {
|
||||
var task = Tasks.findOne(taskId);
|
||||
if (task.private && task.owner !== Meteor.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} });
|
||||
},
|
||||
setPrivate: function (taskId, setToPrivate) {
|
||||
var task = Tasks.findOne(taskId);
|
||||
|
||||
// Make sure only the task owner can make a task private
|
||||
if (task.owner !== Meteor.userId()) {
|
||||
throw new Meteor.Error('not-authorized');
|
||||
}
|
||||
|
||||
Tasks.update(taskId, { $set: { private: setToPrivate } });
|
||||
}
|
||||
});
|
||||
|
||||
if (Meteor.isServer) {
|
||||
Meteor.publish('tasks', function () {
|
||||
return Tasks.find({
|
||||
$or: [
|
||||
{ private: {$ne: true} },
|
||||
{ owner: this.userId }
|
||||
]
|
||||
});
|
||||
});
|
||||
}
|
||||
39
examples/simple-todos-angular/todos-list.ng.html
Normal file
39
examples/simple-todos-angular/todos-list.ng.html
Normal file
@@ -0,0 +1,39 @@
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>Todo List ( {{ incompleteCount() }} )</h1>
|
||||
|
||||
<label class="hide-completed">
|
||||
<input type="checkbox" ng-model="$parent.hideCompleted"/>
|
||||
Hide Completed Tasks
|
||||
</label>
|
||||
|
||||
<meteor-include src="loginButtons"></meteor-include>
|
||||
|
||||
<!-- add a form below the h1 -->
|
||||
<form class="new-task"
|
||||
ng-submit="addTask(newTask); newTask='';"
|
||||
ng-show="$root.currentUser">
|
||||
<input ng-model="newTask" type="text"
|
||||
name="text" placeholder="Type to add new tasks" />
|
||||
</form>
|
||||
</header>
|
||||
|
||||
<ul ng-repeat="task in tasks">
|
||||
<li ng-class="{'checked': task.checked, 'private': task.private}">
|
||||
<button class="delete" ng-click="deleteTask(task)">×</button>
|
||||
|
||||
<input type="checkbox" ng-checked="task.checked"
|
||||
ng-click="setChecked(task)" class="toggle-checked" />
|
||||
|
||||
<button class="toggle-private"
|
||||
ng-if="task.owner === $root.currentUser._id"
|
||||
ng-click="setPrivate(task)">
|
||||
{{task.private == true ? "Private" : "Public"}}
|
||||
</button>
|
||||
|
||||
<span class="text">
|
||||
<strong>{{task.username}}</strong> - {{task.text}}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
8
examples/simple-todos-react/.meteor/.finished-upgraders
Normal file
8
examples/simple-todos-react/.meteor/.finished-upgraders
Normal file
@@ -0,0 +1,8 @@
|
||||
# This file contains information which helps Meteor properly upgrade your
|
||||
# app when you run 'meteor update'. You should check it into version control
|
||||
# with your project.
|
||||
|
||||
notices-for-0.9.0
|
||||
notices-for-0.9.1
|
||||
0.9.4-platform-file
|
||||
notices-for-facebook-graph-api-2
|
||||
1
examples/simple-todos-react/.meteor/.gitignore
vendored
Normal file
1
examples/simple-todos-react/.meteor/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
local
|
||||
10
examples/simple-todos-react/.meteor/packages
Normal file
10
examples/simple-todos-react/.meteor/packages
Normal file
@@ -0,0 +1,10 @@
|
||||
# Meteor packages used by this project, one per line.
|
||||
# Check this file (and the other files in this directory) into your repository.
|
||||
#
|
||||
# 'meteor add' and 'meteor remove' will edit this file for you,
|
||||
# but you can also edit it by hand.
|
||||
|
||||
meteor-platform
|
||||
react
|
||||
accounts-ui
|
||||
accounts-password
|
||||
2
examples/simple-todos-react/.meteor/platforms
Normal file
2
examples/simple-todos-react/.meteor/platforms
Normal file
@@ -0,0 +1,2 @@
|
||||
server
|
||||
browser
|
||||
1
examples/simple-todos-react/.meteor/release
Normal file
1
examples/simple-todos-react/.meteor/release
Normal file
@@ -0,0 +1 @@
|
||||
METEOR@1.1.0.2
|
||||
67
examples/simple-todos-react/.meteor/versions
Normal file
67
examples/simple-todos-react/.meteor/versions
Normal file
@@ -0,0 +1,67 @@
|
||||
accounts-base@1.2.0
|
||||
accounts-password@1.1.1
|
||||
accounts-ui@1.1.5
|
||||
accounts-ui-unstyled@1.1.7
|
||||
autoupdate@1.2.1
|
||||
babel-compiler@5.6.15
|
||||
babel-runtime@0.1.1
|
||||
base64@1.0.3
|
||||
binary-heap@1.0.3
|
||||
blaze@2.1.2
|
||||
blaze-tools@1.0.3
|
||||
boilerplate-generator@1.0.3
|
||||
callback-hook@1.0.3
|
||||
check@1.0.5
|
||||
coffeescript@1.0.6
|
||||
cosmos:browserify@0.4.0
|
||||
ddp@1.1.0
|
||||
deps@1.0.7
|
||||
ejson@1.0.6
|
||||
email@1.0.6
|
||||
fastclick@1.0.3
|
||||
geojson-utils@1.0.3
|
||||
html-tools@1.0.4
|
||||
htmljs@1.0.4
|
||||
http@1.1.0
|
||||
id-map@1.0.3
|
||||
jquery@1.11.3_2
|
||||
json@1.0.3
|
||||
jsx@0.1.1
|
||||
launch-screen@1.0.2
|
||||
less@1.0.14
|
||||
livedata@1.0.13
|
||||
localstorage@1.0.3
|
||||
logging@1.0.7
|
||||
meteor@1.1.6
|
||||
meteor-platform@1.2.2
|
||||
minifiers@1.1.5
|
||||
minimongo@1.0.8
|
||||
mobile-status-bar@1.0.3
|
||||
mongo@1.1.0
|
||||
npm-bcrypt@0.7.8_2
|
||||
observe-sequence@1.0.6
|
||||
ordered-dict@1.0.3
|
||||
random@1.0.3
|
||||
react@0.1.2
|
||||
react-meteor-data@0.1.0
|
||||
react-runtime@0.13.3_2
|
||||
react-runtime-dev@0.13.3_2
|
||||
react-runtime-prod@0.13.3_1
|
||||
reactive-dict@1.1.0
|
||||
reactive-var@1.0.5
|
||||
reload@1.1.3
|
||||
retry@1.0.3
|
||||
routepolicy@1.0.5
|
||||
service-configuration@1.0.4
|
||||
session@1.1.0
|
||||
sha@1.0.3
|
||||
spacebars@1.0.6
|
||||
spacebars-compiler@1.0.6
|
||||
srp@1.0.3
|
||||
templating@1.1.1
|
||||
tracker@1.0.7
|
||||
ui@1.0.6
|
||||
underscore@1.0.3
|
||||
url@1.0.4
|
||||
webapp@1.2.0
|
||||
webapp-hashing@1.0.3
|
||||
15
examples/simple-todos-react/AccountsUIWrapper.jsx
Normal file
15
examples/simple-todos-react/AccountsUIWrapper.jsx
Normal file
@@ -0,0 +1,15 @@
|
||||
AccountsUIWrapper = React.createClass({
|
||||
componentDidMount() {
|
||||
// Use Meteor Blaze to render login buttons
|
||||
this.view = Blaze.render(Template.loginButtons,
|
||||
React.findDOMNode(this.refs.container));
|
||||
},
|
||||
componentWillUnmount() {
|
||||
// Clean up Blaze view
|
||||
Blaze.remove(this.view);
|
||||
},
|
||||
render() {
|
||||
// Just render a placeholder container that will be filled in
|
||||
return <span ref="container" />;
|
||||
}
|
||||
});
|
||||
93
examples/simple-todos-react/App.jsx
Normal file
93
examples/simple-todos-react/App.jsx
Normal file
@@ -0,0 +1,93 @@
|
||||
// App component - represents the whole app
|
||||
App = React.createClass({
|
||||
|
||||
// This mixin makes the getMeteorData method work
|
||||
mixins: [ReactMeteorData],
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
hideCompleted: false
|
||||
}
|
||||
},
|
||||
|
||||
// Loads items from the Tasks collection and puts them on this.data.tasks
|
||||
getMeteorData() {
|
||||
let query = {};
|
||||
|
||||
if (this.state.hideCompleted) {
|
||||
// If hide completed is checked, filter tasks
|
||||
query = {checked: {$ne: true}};
|
||||
}
|
||||
|
||||
return {
|
||||
tasks: Tasks.find(query, {sort: {createdAt: -1}}).fetch(),
|
||||
incompleteCount: Tasks.find({checked: {$ne: true}}).count(),
|
||||
currentUser: Meteor.user()
|
||||
};
|
||||
},
|
||||
|
||||
renderTasks() {
|
||||
// Get tasks from this.data.tasks
|
||||
return this.data.tasks.map((task) => {
|
||||
const currentUserId = this.data.currentUser && this.data.currentUser._id;
|
||||
const showPrivateButton = task.owner === currentUserId;
|
||||
|
||||
return <Task
|
||||
key={task._id}
|
||||
task={task}
|
||||
showPrivateButton={showPrivateButton} />;
|
||||
});
|
||||
},
|
||||
|
||||
handleSubmit(event) {
|
||||
event.preventDefault();
|
||||
|
||||
// Find the text field via the React ref
|
||||
var text = React.findDOMNode(this.refs.textInput).value.trim();
|
||||
|
||||
Meteor.call("addTask", text);
|
||||
|
||||
// Clear form
|
||||
React.findDOMNode(this.refs.textInput).value = "";
|
||||
},
|
||||
|
||||
toggleHideCompleted() {
|
||||
this.setState({
|
||||
hideCompleted: ! this.state.hideCompleted
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="container">
|
||||
<header>
|
||||
<h1>Todo List ({this.data.incompleteCount})</h1>
|
||||
|
||||
<label className="hide-completed">
|
||||
<input
|
||||
type="checkbox"
|
||||
readOnly={true}
|
||||
checked={this.state.hideCompleted}
|
||||
onClick={this.toggleHideCompleted} />
|
||||
Hide Completed Tasks
|
||||
</label>
|
||||
|
||||
<AccountsUIWrapper />
|
||||
|
||||
{ this.data.currentUser ?
|
||||
<form className="new-task" onSubmit={this.handleSubmit} >
|
||||
<input
|
||||
type="text"
|
||||
ref="textInput"
|
||||
placeholder="Type to add new tasks" />
|
||||
</form> : ''
|
||||
}
|
||||
</header>
|
||||
|
||||
<ul>
|
||||
{this.renderTasks()}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
22
examples/simple-todos-react/LICENSE
Normal file
22
examples/simple-todos-react/LICENSE
Normal file
@@ -0,0 +1,22 @@
|
||||
========================================
|
||||
Meteor is licensed under the MIT License
|
||||
========================================
|
||||
|
||||
Copyright (C) 2011--2015 Meteor Development Group
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
9
examples/simple-todos-react/README.md
Normal file
9
examples/simple-todos-react/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Simple Todo List
|
||||
|
||||
The Meteor Tutorial app.
|
||||
|
||||
Use it to share a single todo list with your friends. The list updates on everyone's screen in real time, and you can make tasks private if you don't want others to see them.
|
||||
|
||||
Learn how to build this app by following the [Meteor Tutorial](http://www.meteor.com/install).
|
||||
|
||||

|
||||
52
examples/simple-todos-react/Task.jsx
Normal file
52
examples/simple-todos-react/Task.jsx
Normal file
@@ -0,0 +1,52 @@
|
||||
// Task component - represents a single todo item
|
||||
Task = React.createClass({
|
||||
propTypes: {
|
||||
task: React.PropTypes.object.isRequired,
|
||||
showPrivateButton: React.PropTypes.bool.isRequired
|
||||
},
|
||||
|
||||
toggleChecked() {
|
||||
// Set the checked property to the opposite of its current value
|
||||
Meteor.call("setChecked", this.props.task._id, ! this.props.task.checked);
|
||||
},
|
||||
|
||||
deleteThisTask() {
|
||||
Meteor.call("removeTask", this.props.task._id);
|
||||
},
|
||||
|
||||
togglePrivate() {
|
||||
Meteor.call("setPrivate", this.props.task._id, ! this.props.task.private);
|
||||
},
|
||||
|
||||
render() {
|
||||
// Give tasks a different className when they are checked off,
|
||||
// so that we can style them nicely in CSS
|
||||
// Add "checked" and/or "private" to the className when needed
|
||||
const taskClassName = (this.props.task.checked ? "checked" : "") + " " +
|
||||
(this.props.task.private ? "private" : "");
|
||||
|
||||
return (
|
||||
<li className={taskClassName}>
|
||||
<button className="delete" onClick={this.deleteThisTask}>
|
||||
×
|
||||
</button>
|
||||
|
||||
<input
|
||||
type="checkbox"
|
||||
readOnly={true}
|
||||
checked={this.props.task.checked}
|
||||
onClick={this.toggleChecked} />
|
||||
|
||||
{ this.props.showPrivateButton ? (
|
||||
<button className="toggle-private" onClick={this.togglePrivate}>
|
||||
{ this.props.task.private ? "Private" : "Public" }
|
||||
</button>
|
||||
) : ''}
|
||||
|
||||
<span className="text">
|
||||
<strong>{this.props.task.username}</strong>: {this.props.task.text}
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
});
|
||||
BIN
examples/simple-todos-react/screenshot.png
Normal file
BIN
examples/simple-todos-react/screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 228 KiB |
126
examples/simple-todos-react/simple-todos-react.css
Normal file
126
examples/simple-todos-react/simple-todos-react.css
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
7
examples/simple-todos-react/simple-todos-react.html
Normal file
7
examples/simple-todos-react/simple-todos-react.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<head>
|
||||
<title>Todo List</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="render-target"></div>
|
||||
</body>
|
||||
75
examples/simple-todos-react/simple-todos-react.jsx
Normal file
75
examples/simple-todos-react/simple-todos-react.jsx
Normal file
@@ -0,0 +1,75 @@
|
||||
// Define a collection to hold our tasks
|
||||
Tasks = new Mongo.Collection("tasks");
|
||||
|
||||
if (Meteor.isClient) {
|
||||
// This code is executed on the client only
|
||||
Accounts.ui.config({
|
||||
passwordSignupFields: "USERNAME_ONLY"
|
||||
});
|
||||
|
||||
Meteor.subscribe("tasks");
|
||||
|
||||
Meteor.startup(function () {
|
||||
// Use Meteor.startup to render the component after the page is ready
|
||||
React.render(<App />, document.getElementById("render-target"));
|
||||
});
|
||||
}
|
||||
|
||||
if (Meteor.isServer) {
|
||||
// Only publish tasks that are public or belong to the current user
|
||||
Meteor.publish("tasks", function () {
|
||||
return Tasks.find({
|
||||
$or: [
|
||||
{ private: {$ne: true} },
|
||||
{ owner: this.userId }
|
||||
]
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Meteor.methods({
|
||||
addTask(text) {
|
||||
// Make sure the user is logged in before inserting a task
|
||||
if (! Meteor.userId()) {
|
||||
throw new Meteor.Error("not-authorized");
|
||||
}
|
||||
|
||||
Tasks.insert({
|
||||
text: text,
|
||||
createdAt: new Date(),
|
||||
owner: Meteor.userId(),
|
||||
username: Meteor.user().username
|
||||
});
|
||||
},
|
||||
|
||||
removeTask(taskId) {
|
||||
const task = Tasks.findOne(taskId);
|
||||
if (task.private && task.owner !== Meteor.userId()) {
|
||||
// If the task is private, make sure only the owner can delete it
|
||||
throw new Meteor.Error("not-authorized");
|
||||
}
|
||||
|
||||
Tasks.remove(taskId);
|
||||
},
|
||||
|
||||
setChecked(taskId, setChecked) {
|
||||
const task = Tasks.findOne(taskId);
|
||||
if (task.private && task.owner !== Meteor.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} });
|
||||
},
|
||||
|
||||
setPrivate(taskId, setToPrivate) {
|
||||
const task = Tasks.findOne(taskId);
|
||||
|
||||
// Make sure only the task owner can make a task private
|
||||
if (task.owner !== Meteor.userId()) {
|
||||
throw new Meteor.Error("not-authorized");
|
||||
}
|
||||
|
||||
Tasks.update(taskId, { $set: { private: setToPrivate } });
|
||||
}
|
||||
});
|
||||
8
examples/simple-todos/.meteor/.finished-upgraders
Normal file
8
examples/simple-todos/.meteor/.finished-upgraders
Normal file
@@ -0,0 +1,8 @@
|
||||
# This file contains information which helps Meteor properly upgrade your
|
||||
# app when you run 'meteor update'. You should check it into version control
|
||||
# with your project.
|
||||
|
||||
notices-for-0.9.0
|
||||
notices-for-0.9.1
|
||||
0.9.4-platform-file
|
||||
notices-for-facebook-graph-api-2
|
||||
1
examples/simple-todos/.meteor/.gitignore
vendored
Normal file
1
examples/simple-todos/.meteor/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
local
|
||||
9
examples/simple-todos/.meteor/packages
Normal file
9
examples/simple-todos/.meteor/packages
Normal file
@@ -0,0 +1,9 @@
|
||||
# Meteor packages used by this project, one per line.
|
||||
# Check this file (and the other files in this directory) into your repository.
|
||||
#
|
||||
# 'meteor add' and 'meteor remove' will edit this file for you,
|
||||
# but you can also edit it by hand.
|
||||
|
||||
meteor-platform
|
||||
accounts-ui
|
||||
accounts-password
|
||||
2
examples/simple-todos/.meteor/platforms
Normal file
2
examples/simple-todos/.meteor/platforms
Normal file
@@ -0,0 +1,2 @@
|
||||
server
|
||||
browser
|
||||
1
examples/simple-todos/.meteor/release
Normal file
1
examples/simple-todos/.meteor/release
Normal file
@@ -0,0 +1 @@
|
||||
METEOR@1.1.0.2
|
||||
57
examples/simple-todos/.meteor/versions
Normal file
57
examples/simple-todos/.meteor/versions
Normal file
@@ -0,0 +1,57 @@
|
||||
accounts-base@1.2.0
|
||||
accounts-password@1.1.1
|
||||
accounts-ui@1.1.5
|
||||
accounts-ui-unstyled@1.1.7
|
||||
autoupdate@1.2.1
|
||||
base64@1.0.3
|
||||
binary-heap@1.0.3
|
||||
blaze@2.1.2
|
||||
blaze-tools@1.0.3
|
||||
boilerplate-generator@1.0.3
|
||||
callback-hook@1.0.3
|
||||
check@1.0.5
|
||||
ddp@1.1.0
|
||||
deps@1.0.7
|
||||
ejson@1.0.6
|
||||
email@1.0.6
|
||||
fastclick@1.0.3
|
||||
geojson-utils@1.0.3
|
||||
html-tools@1.0.4
|
||||
htmljs@1.0.4
|
||||
http@1.1.0
|
||||
id-map@1.0.3
|
||||
jquery@1.11.3_2
|
||||
json@1.0.3
|
||||
launch-screen@1.0.2
|
||||
less@1.0.14
|
||||
livedata@1.0.13
|
||||
localstorage@1.0.3
|
||||
logging@1.0.7
|
||||
meteor@1.1.6
|
||||
meteor-platform@1.2.2
|
||||
minifiers@1.1.5
|
||||
minimongo@1.0.8
|
||||
mobile-status-bar@1.0.3
|
||||
mongo@1.1.0
|
||||
npm-bcrypt@0.7.8_2
|
||||
observe-sequence@1.0.6
|
||||
ordered-dict@1.0.3
|
||||
random@1.0.3
|
||||
reactive-dict@1.1.0
|
||||
reactive-var@1.0.5
|
||||
reload@1.1.3
|
||||
retry@1.0.3
|
||||
routepolicy@1.0.5
|
||||
service-configuration@1.0.4
|
||||
session@1.1.0
|
||||
sha@1.0.3
|
||||
spacebars@1.0.6
|
||||
spacebars-compiler@1.0.6
|
||||
srp@1.0.3
|
||||
templating@1.1.1
|
||||
tracker@1.0.7
|
||||
ui@1.0.6
|
||||
underscore@1.0.3
|
||||
url@1.0.4
|
||||
webapp@1.2.0
|
||||
webapp-hashing@1.0.3
|
||||
22
examples/simple-todos/LICENSE
Normal file
22
examples/simple-todos/LICENSE
Normal file
@@ -0,0 +1,22 @@
|
||||
========================================
|
||||
Meteor is licensed under the MIT License
|
||||
========================================
|
||||
|
||||
Copyright (C) 2011--2015 Meteor Development Group
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
9
examples/simple-todos/README.md
Normal file
9
examples/simple-todos/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Simple Todo List
|
||||
|
||||
The Meteor Tutorial app.
|
||||
|
||||
Use it to share a single todo list with your friends. The list updates on everyone's screen in real time, and you can make tasks private if you don't want others to see them.
|
||||
|
||||
Learn how to build this app by following the [Meteor Tutorial](http://www.meteor.com/install).
|
||||
|
||||

|
||||
BIN
examples/simple-todos/screenshot.png
Normal file
BIN
examples/simple-todos/screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 228 KiB |
126
examples/simple-todos/simple-todos.css
Normal file
126
examples/simple-todos/simple-todos.css
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
50
examples/simple-todos/simple-todos.html
Normal file
50
examples/simple-todos/simple-todos.html
Normal file
@@ -0,0 +1,50 @@
|
||||
<head>
|
||||
<title>Todo List</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>Todo List ({{incompleteCount}})</h1>
|
||||
|
||||
<label class="hide-completed">
|
||||
<input type="checkbox" checked="{{hideCompleted}}" />
|
||||
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>
|
||||
|
||||
<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>
|
||||
123
examples/simple-todos/simple-todos.js
Normal file
123
examples/simple-todos/simple-todos.js
Normal file
@@ -0,0 +1,123 @@
|
||||
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 () {
|
||||
return Tasks.find({
|
||||
$or: [
|
||||
{ private: {$ne: true} },
|
||||
{ owner: this.userId }
|
||||
]
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (Meteor.isClient) {
|
||||
// This code only runs on the client
|
||||
Meteor.subscribe("tasks");
|
||||
|
||||
Template.body.helpers({
|
||||
tasks: function () {
|
||||
if (Session.get("hideCompleted")) {
|
||||
// If hide completed is checked, filter tasks
|
||||
return Tasks.find({checked: {$ne: true}}, {sort: {createdAt: -1}});
|
||||
} else {
|
||||
// Otherwise, return all of the tasks
|
||||
return Tasks.find({}, {sort: {createdAt: -1}});
|
||||
}
|
||||
},
|
||||
hideCompleted: function () {
|
||||
return Session.get("hideCompleted");
|
||||
},
|
||||
incompleteCount: function () {
|
||||
return Tasks.find({checked: {$ne: true}}).count();
|
||||
}
|
||||
});
|
||||
|
||||
Template.body.events({
|
||||
"submit .new-task": function (event) {
|
||||
// Prevent default browser form submit
|
||||
event.preventDefault();
|
||||
|
||||
// Get value from form element
|
||||
var text = event.target.text.value;
|
||||
|
||||
// Insert a task into the collection
|
||||
Meteor.call("addTask", text);
|
||||
|
||||
// Clear form
|
||||
event.target.text.value = "";
|
||||
},
|
||||
"change .hide-completed input": function (event) {
|
||||
Session.set("hideCompleted", event.target.checked);
|
||||
}
|
||||
});
|
||||
|
||||
Template.task.helpers({
|
||||
isOwner: function () {
|
||||
return this.owner === Meteor.userId();
|
||||
}
|
||||
});
|
||||
|
||||
Template.task.events({
|
||||
"click .toggle-checked": function () {
|
||||
// Set the checked property to the opposite of its current value
|
||||
Meteor.call("setChecked", this._id, ! this.checked);
|
||||
},
|
||||
"click .delete": function () {
|
||||
Meteor.call("deleteTask", this._id);
|
||||
},
|
||||
"click .toggle-private": function () {
|
||||
Meteor.call("setPrivate", this._id, ! this.private);
|
||||
}
|
||||
});
|
||||
|
||||
Accounts.ui.config({
|
||||
passwordSignupFields: "USERNAME_ONLY"
|
||||
});
|
||||
}
|
||||
|
||||
Meteor.methods({
|
||||
addTask: function (text) {
|
||||
// Make sure the user is logged in before inserting a task
|
||||
if (! Meteor.userId()) {
|
||||
throw new Meteor.Error("not-authorized");
|
||||
}
|
||||
|
||||
Tasks.insert({
|
||||
text: text,
|
||||
createdAt: new Date(),
|
||||
owner: Meteor.userId(),
|
||||
username: Meteor.user().username
|
||||
});
|
||||
},
|
||||
deleteTask: function (taskId) {
|
||||
var task = Tasks.findOne(taskId);
|
||||
if (task.private && task.owner !== Meteor.userId()) {
|
||||
// If the task is private, make sure only the owner can delete it
|
||||
throw new Meteor.Error("not-authorized");
|
||||
}
|
||||
|
||||
Tasks.remove(taskId);
|
||||
},
|
||||
setChecked: function (taskId, setChecked) {
|
||||
var task = Tasks.findOne(taskId);
|
||||
if (task.private && task.owner !== Meteor.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} });
|
||||
},
|
||||
setPrivate: function (taskId, setToPrivate) {
|
||||
var task = Tasks.findOne(taskId);
|
||||
|
||||
// Make sure only the task owner can make a task private
|
||||
if (task.owner !== Meteor.userId()) {
|
||||
throw new Meteor.Error("not-authorized");
|
||||
}
|
||||
|
||||
Tasks.update(taskId, { $set: { private: setToPrivate } });
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user