├── .eslintignore
├── .gitignore
├── .gitmodules
├── .nvmrc
├── .prettierignore
├── README.md
├── _config.yml
├── assets
└── theme-colors.less
├── netlify.toml
├── package-lock.json
├── package.json
├── prettier.config.js
├── scripts
└── dl.js
├── src
└── simple-todos
│ ├── step01
│ ├── .gitignore
│ ├── .meteor
│ │ ├── .finished-upgraders
│ │ ├── .gitignore
│ │ ├── .id
│ │ ├── packages
│ │ ├── platforms
│ │ ├── release
│ │ └── versions
│ ├── client
│ │ ├── main.css
│ │ ├── main.html
│ │ └── main.js
│ ├── imports
│ │ └── ui
│ │ │ ├── App.html
│ │ │ └── App.js
│ ├── package-lock.json
│ ├── package.json
│ ├── server
│ │ └── main.js
│ └── tests
│ │ └── main.js
│ ├── step02
│ ├── .gitignore
│ ├── .meteor
│ │ ├── .finished-upgraders
│ │ ├── .gitignore
│ │ ├── .id
│ │ ├── packages
│ │ ├── platforms
│ │ ├── release
│ │ └── versions
│ ├── client
│ │ ├── main.css
│ │ ├── main.html
│ │ └── main.js
│ ├── imports
│ │ ├── api
│ │ │ └── TasksCollection.js
│ │ └── ui
│ │ │ ├── App.html
│ │ │ └── App.js
│ ├── package-lock.json
│ ├── package.json
│ ├── server
│ │ └── main.js
│ └── tests
│ │ └── main.js
│ ├── step03
│ ├── .gitignore
│ ├── .meteor
│ │ ├── .finished-upgraders
│ │ ├── .gitignore
│ │ ├── .id
│ │ ├── packages
│ │ ├── platforms
│ │ ├── release
│ │ └── versions
│ ├── client
│ │ ├── main.css
│ │ ├── main.html
│ │ └── main.js
│ ├── imports
│ │ ├── api
│ │ │ └── TasksCollection.js
│ │ └── ui
│ │ │ ├── App.html
│ │ │ └── App.js
│ ├── package-lock.json
│ ├── package.json
│ ├── server
│ │ └── main.js
│ └── tests
│ │ └── main.js
│ ├── step04
│ ├── .gitignore
│ ├── .meteor
│ │ ├── .finished-upgraders
│ │ ├── .gitignore
│ │ ├── .id
│ │ ├── packages
│ │ ├── platforms
│ │ ├── release
│ │ └── versions
│ ├── client
│ │ ├── main.css
│ │ ├── main.html
│ │ └── main.js
│ ├── imports
│ │ ├── api
│ │ │ └── TasksCollection.js
│ │ └── ui
│ │ │ ├── App.html
│ │ │ ├── App.js
│ │ │ ├── Task.html
│ │ │ └── Task.js
│ ├── package-lock.json
│ ├── package.json
│ ├── server
│ │ └── main.js
│ └── tests
│ │ └── main.js
│ ├── step05
│ ├── .gitignore
│ ├── .meteor
│ │ ├── .finished-upgraders
│ │ ├── .gitignore
│ │ ├── .id
│ │ ├── packages
│ │ ├── platforms
│ │ ├── release
│ │ └── versions
│ ├── client
│ │ ├── main.css
│ │ ├── main.html
│ │ └── main.js
│ ├── imports
│ │ ├── api
│ │ │ └── TasksCollection.js
│ │ └── ui
│ │ │ ├── App.html
│ │ │ ├── App.js
│ │ │ ├── Task.html
│ │ │ └── Task.js
│ ├── package-lock.json
│ ├── package.json
│ ├── server
│ │ └── main.js
│ └── tests
│ │ └── main.js
│ ├── step06
│ ├── .gitignore
│ ├── .meteor
│ │ ├── .finished-upgraders
│ │ ├── .gitignore
│ │ ├── .id
│ │ ├── packages
│ │ ├── platforms
│ │ ├── release
│ │ └── versions
│ ├── client
│ │ ├── main.css
│ │ ├── main.html
│ │ └── main.js
│ ├── imports
│ │ ├── api
│ │ │ └── TasksCollection.js
│ │ └── ui
│ │ │ ├── App.html
│ │ │ ├── App.js
│ │ │ ├── Task.html
│ │ │ └── Task.js
│ ├── package-lock.json
│ ├── package.json
│ ├── server
│ │ └── main.js
│ └── tests
│ │ └── main.js
│ ├── step07
│ ├── .gitignore
│ ├── .meteor
│ │ ├── .finished-upgraders
│ │ ├── .gitignore
│ │ ├── .id
│ │ ├── packages
│ │ ├── platforms
│ │ ├── release
│ │ └── versions
│ ├── client
│ │ ├── main.css
│ │ ├── main.html
│ │ └── main.js
│ ├── imports
│ │ ├── api
│ │ │ └── TasksCollection.js
│ │ └── ui
│ │ │ ├── App.html
│ │ │ ├── App.js
│ │ │ ├── Login.html
│ │ │ ├── Login.js
│ │ │ ├── Task.html
│ │ │ └── Task.js
│ ├── package-lock.json
│ ├── package.json
│ ├── server
│ │ └── main.js
│ └── tests
│ │ └── main.js
│ ├── step08
│ ├── .gitignore
│ ├── .meteor
│ │ ├── .finished-upgraders
│ │ ├── .gitignore
│ │ ├── .id
│ │ ├── packages
│ │ ├── platforms
│ │ ├── release
│ │ └── versions
│ ├── client
│ │ ├── main.css
│ │ ├── main.html
│ │ └── main.js
│ ├── imports
│ │ ├── api
│ │ │ └── tasksMethods.js
│ │ ├── db
│ │ │ └── TasksCollection.js
│ │ └── ui
│ │ │ ├── App.html
│ │ │ ├── App.js
│ │ │ ├── Login.html
│ │ │ ├── Login.js
│ │ │ ├── Task.html
│ │ │ └── Task.js
│ ├── package-lock.json
│ ├── package.json
│ ├── server
│ │ └── main.js
│ └── tests
│ │ └── main.js
│ ├── step09
│ ├── .gitignore
│ ├── .meteor
│ │ ├── .finished-upgraders
│ │ ├── .gitignore
│ │ ├── .id
│ │ ├── packages
│ │ ├── platforms
│ │ ├── release
│ │ └── versions
│ ├── client
│ │ ├── main.css
│ │ ├── main.html
│ │ └── main.js
│ ├── imports
│ │ ├── api
│ │ │ ├── tasksMethods.js
│ │ │ └── tasksPublications.js
│ │ ├── db
│ │ │ └── TasksCollection.js
│ │ └── ui
│ │ │ ├── App.html
│ │ │ ├── App.js
│ │ │ ├── Login.html
│ │ │ ├── Login.js
│ │ │ ├── Task.html
│ │ │ └── Task.js
│ ├── package-lock.json
│ ├── package.json
│ ├── server
│ │ └── main.js
│ └── tests
│ │ └── main.js
│ ├── step10
│ ├── .gitignore
│ ├── .meteor
│ │ ├── .finished-upgraders
│ │ ├── .gitignore
│ │ ├── .id
│ │ ├── packages
│ │ ├── platforms
│ │ ├── release
│ │ └── versions
│ ├── client
│ │ ├── main.css
│ │ ├── main.html
│ │ └── main.js
│ ├── imports
│ │ ├── api
│ │ │ ├── tasksMethods.js
│ │ │ └── tasksPublications.js
│ │ ├── db
│ │ │ └── TasksCollection.js
│ │ └── ui
│ │ │ ├── App.html
│ │ │ ├── App.js
│ │ │ ├── Login.html
│ │ │ ├── Login.js
│ │ │ ├── Task.html
│ │ │ └── Task.js
│ ├── package-lock.json
│ ├── package.json
│ ├── server
│ │ └── main.js
│ └── tests
│ │ └── main.js
│ ├── step11
│ ├── .gitignore
│ ├── .meteor
│ │ ├── .finished-upgraders
│ │ ├── .gitignore
│ │ ├── .id
│ │ ├── packages
│ │ ├── platforms
│ │ ├── release
│ │ └── versions
│ ├── client
│ │ ├── main.css
│ │ ├── main.html
│ │ └── main.js
│ ├── imports
│ │ ├── api
│ │ │ ├── tasksMethods.js
│ │ │ ├── tasksMethods.tests.js
│ │ │ └── tasksPublications.js
│ │ ├── db
│ │ │ └── TasksCollection.js
│ │ └── ui
│ │ │ ├── App.html
│ │ │ ├── App.js
│ │ │ ├── Login.html
│ │ │ ├── Login.js
│ │ │ ├── Task.html
│ │ │ └── Task.js
│ ├── package-lock.json
│ ├── package.json
│ ├── server
│ │ └── main.js
│ └── tests
│ │ └── main.js
│ ├── step12
│ ├── .gitignore
│ ├── .meteor
│ │ ├── .finished-upgraders
│ │ ├── .gitignore
│ │ ├── .id
│ │ ├── packages
│ │ ├── platforms
│ │ ├── release
│ │ └── versions
│ ├── client
│ │ ├── main.css
│ │ ├── main.html
│ │ └── main.js
│ ├── imports
│ │ ├── api
│ │ │ ├── tasksMethods.js
│ │ │ ├── tasksMethods.tests.js
│ │ │ └── tasksPublications.js
│ │ ├── db
│ │ │ └── TasksCollection.js
│ │ └── ui
│ │ │ ├── App.html
│ │ │ ├── App.js
│ │ │ ├── Login.html
│ │ │ ├── Login.js
│ │ │ ├── Task.html
│ │ │ └── Task.js
│ ├── package-lock.json
│ ├── package.json
│ ├── server
│ │ └── main.js
│ └── tests
│ │ └── main.js
│ └── step13
│ ├── .gitignore
│ ├── .meteor
│ ├── .finished-upgraders
│ ├── .gitignore
│ ├── .id
│ ├── packages
│ ├── platforms
│ ├── release
│ └── versions
│ ├── client
│ ├── main.css
│ ├── main.html
│ └── main.js
│ ├── imports
│ ├── api
│ │ ├── tasksMethods.js
│ │ ├── tasksMethods.tests.js
│ │ └── tasksPublications.js
│ ├── db
│ │ └── TasksCollection.js
│ └── ui
│ │ ├── App.html
│ │ ├── App.js
│ │ ├── Login.html
│ │ ├── Login.js
│ │ ├── Task.html
│ │ └── Task.js
│ ├── package-lock.json
│ ├── package.json
│ ├── server
│ └── main.js
│ └── tests
│ └── main.js
└── tutorial
├── changelog.md
├── index.md
└── simple-todos
├── 01-creating-app.md
├── 02-collections.md
├── 03-forms-and-events.md
├── 04-update-and-remove.md
├── 05-styles.md
├── 06-filter-tasks.md
├── 07-adding-user-accounts.md
├── 08-methods.md
├── 09-publications.md
├── 10-running-on-mobile.md
├── 11-testing.md
├── 12-deploying.md
├── 13-next-steps.md
├── assets
├── step01-dev-tools-mobile-toggle.png
├── step01-mobile-with-meta-tags.png
├── step01-mobile-without-meta-tags.png
├── step02-connect-mongo.png
├── step02-see-your-collection.png
├── step02-see-your-db.png
├── step02-tasks-list.png
├── step03-form-new-task.png
├── step03-new-task-on-list.png
├── step04-checkbox.png
├── step04-delete-button.png
├── step05-styles.png
├── step06-all.png
├── step06-ddp-messages.png
├── step06-extension.png
├── step06-filtered.png
├── step07-login.png
├── step07-logout.png
├── step10-android-emulator.png
├── step10-ios-simulator.png
├── step11-test-report.png
└── step12-sign-up.png
└── index.md
/.eslintignore:
--------------------------------------------------------------------------------
1 | # general
2 | **/.meteor/local/*
3 | **/node_modules/*
4 |
5 | # specific for tutorial repo
6 | public/script/*
7 | scripts/*
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | Thumbs.db
3 | db.json
4 | *.log
5 | node_modules/
6 | public/
7 | .deploy*/
8 | data/
9 | _multiconfig.yml
10 | .idea/
11 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "themes/meteor"]
2 | path = themes/meteor
3 | url = https://github.com/meteor/hexo-theme-meteor.git
4 | [submodule "code"]
5 | path = code
6 | url = https://github.com/meteor/meteor.git
7 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 8.11.2
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | **/.meteor/local/*
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Meteor Blaze Tutorial
2 |
3 | If you are looking for the tutorial, please go to [https://blaze-tutorial.meteor.com](https://blaze-tutorial.meteor.com) and check it there.
4 |
5 | This repository is the place to check the code (`src` folder) and to make contributions.
6 |
7 | Read in the tutorial home page where you should ask questions (spoiler: [Forums](https://forums.meteor.com) or [Slack](https://join.slack.com/t/meteor-community/shared_invite/enQtODA0NTU2Nzk5MTA3LWY5NGMxMWRjZDgzYWMyMTEyYTQ3MTcwZmU2YjM5MTY3MjJkZjQ0NWRjOGZlYmIxZjFlYTA5Mjg4OTk3ODRiOTc)).
8 |
9 | This is a [hexo](https://hexo.io) static site used to generate the [Meteor Blaze Tutorial Docs](https://blaze-tutorial.meteor.com).
10 |
11 | ## Contributing
12 |
13 | We'd love your contributions! Please send us Pull Requests or open issues on [github](https://github.com/meteor/blaze-tutorial). Also, read the [contribution guidelines](https://github.com/meteor/docs/blob/master/Contributing.md).
14 |
15 | If you are making a larger contribution, you may need to run the site locally:
16 |
17 | ### Running locally
18 |
19 | - Install [nvm](https://github.com/nvm-sh/nvm) to manage your Node.js (yes, this is an hexo project and not Meteor, in Meteor you don't need to worry about Node.js versions at all)
20 |
21 | `curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash`
22 | - Install Node.js 8.11.2:
23 |
24 | `nvm install 8.11.2`
25 |
26 | - Install the project
27 |
28 | `npm install`
29 |
30 | - Run it
31 |
32 | `npm start`
33 |
34 | ### Styles and Lint
35 |
36 | Make sure your changes are not breaking styles and lint rules, in the root project, run:
37 |
38 | - `npm install`
39 | - `npm run quave-check`
40 |
41 | `quave-check` should not return any error or warning. If it does you need to fix them before sending a PR.
42 |
43 | If you get an error because some npm modules are not resolved (`import/no-unresolved`) you need to run `npm install` inside the Meteor project that is throwing this error so you generate the `node_modules` folder for it.
44 |
45 | We have a git hook to prevent commits that are not passing these rules but it's good to double-check as maybe your hooks set up can be messed up.
46 |
47 | ### Making a Pull Request
48 |
49 | - Create a fork and make your changes on it.
50 |
51 | - Test your changes and make sure you sync your code changes (`src` folder) with your text changes (`tutorial` folder).
52 |
53 | - Build your changes:
54 |
55 | `npm run build`
56 |
57 | - Create your Pull Request against `master` branch.
58 |
59 | - Sign the CLA.
60 |
61 | - Wait for feedback or approval.
62 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | title: Meteor Blaze Tutorial
2 | subtitle: Blaze Tutorial
3 | versions:
4 | - '1'
5 | versioned-netlify-redirects:
6 | netlify_site_id: meteor-blaze-tutorial
7 |
8 | logo:
9 | title:
10 | subtitle: Blaze Tutorial
11 |
12 | sidebar_categories:
13 | null:
14 | - index
15 | - changelog
16 | Simple Todos:
17 | - simple-todos/index
18 | - simple-todos/01-creating-app
19 | - simple-todos/02-collections
20 | - simple-todos/03-forms-and-events
21 | - simple-todos/04-update-and-remove
22 | - simple-todos/05-styles
23 | - simple-todos/06-filter-tasks
24 | - simple-todos/07-adding-user-accounts
25 | - simple-todos/08-methods
26 | - simple-todos/09-publications
27 | - simple-todos/10-running-on-mobile
28 | - simple-todos/11-testing
29 | - simple-todos/12-deploying
30 | - simple-todos/13-next-steps
31 | github_repo: 'meteor/blaze-tutorial'
32 |
33 | url: http://blaze-tutorial.meteor.com/
34 | root: /
35 |
36 | source_dir: tutorial
37 | content_root: tutorial
38 |
39 | highlight:
40 | enable: false
41 |
--------------------------------------------------------------------------------
/assets/theme-colors.less:
--------------------------------------------------------------------------------
1 | // Haven't made any changes as we want the default Meteor colors
2 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | publish = "public"
3 | command = "npm install && npm run build"
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hexo-site",
3 | "version": "0.0.0",
4 | "private": true,
5 | "hexo": {
6 | "version": "3.9.0"
7 | },
8 | "devDependencies": {
9 | "@quave/eslint-config-quave": "^1.0.3",
10 | "canonical-json": "0.0.4",
11 | "chexo": "1.0.7",
12 | "handlebars": "4.4.3",
13 | "hexo": "3.9.0",
14 | "hexo-prism-plus": "^1.1.0",
15 | "hexo-renderer-ejs": "^1.0.0",
16 | "hexo-renderer-less": "0.2.0",
17 | "hexo-renderer-marked": "^3.2.0",
18 | "hexo-server": "1.0.0",
19 | "hexo-versioned-netlify-redirects": "1.1.0",
20 | "@meteorjs/meteor-hexo-config": "1.0.14",
21 | "@meteorjs/meteor-theme-hexo": "2.0.8",
22 | "showdown": "1.9.0",
23 | "underscore": "1.9.1"
24 | },
25 | "scripts": {
26 | "build": "chexo @meteorjs/meteor-hexo-config -- generate",
27 | "clean": "hexo clean",
28 | "test": "npm run clean; npm run build",
29 | "predeploy": "npm run build",
30 | "deploy": "hexo-s3-deploy",
31 | "start": "npm run build && chexo @meteorjs/meteor-hexo-config -- server",
32 | "quave-eslint": "eslint . --fix",
33 | "quave-prettier": "prettier --write \"**/*.js\" \"**/*.jsx\"",
34 | "quave-check": "npm run quave-eslint && npm run quave-prettier"
35 | },
36 | "eslintConfig": {
37 | "extends": [
38 | "@quave/quave"
39 | ]
40 | },
41 | "husky": {
42 | "hooks": {
43 | "pre-commit": "meteor npm test && lint-staged",
44 | "post-commit": "git update-index --again"
45 | }
46 | },
47 | "lint-staged": {
48 | "*.{js|jsx}": [
49 | "eslint --fix",
50 | "prettier --write",
51 | "git add"
52 | ]
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require('@quave/eslint-config-quave/prettier.config');
2 |
--------------------------------------------------------------------------------
/scripts/dl.js:
--------------------------------------------------------------------------------
1 | /* global hexo */
2 |
3 | hexo.extend.tag.register(
4 | 'dtdd',
5 | function(args, content) {
6 | const options = parseTagOptions(args);
7 |
8 | let typespan = '';
9 | if (options.type) {
10 | typespan = `${options.type} `;
11 | }
12 |
13 | let idstr = '';
14 | if (options.id) {
15 | idstr = `id="${options.id}"`;
16 | }
17 | const namespan = `${options.name} `;
18 |
19 | return hexo.render
20 | .render({ text: content, engine: 'md' })
21 | .then(function(markdownContent) {
22 | return `
${namespan}${typespan} ${markdownContent} `;
23 | });
24 | },
25 | { ends: true, async: true }
26 | );
27 |
--------------------------------------------------------------------------------
/src/simple-todos/step01/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step01/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | 0.9.4-platform-file
8 | notices-for-facebook-graph-api-2
9 | 1.2.0-standard-minifiers-package
10 | 1.2.0-meteor-platform-split
11 | 1.2.0-cordova-changes
12 | 1.2.0-breaking-changes
13 | 1.3.0-split-minifiers-package
14 | 1.4.0-remove-old-dev-bundle-link
15 | 1.4.1-add-shell-server-package
16 | 1.4.3-split-account-service-packages
17 | 1.5-add-dynamic-import-package
18 | 1.7-split-underscore-from-meteor-base
19 | 1.8.3-split-jquery-from-blaze
20 |
--------------------------------------------------------------------------------
/src/simple-todos/step01/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step01/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | nlvom1n4rsd.t6xtf6i5fdy
8 |
--------------------------------------------------------------------------------
/src/simple-todos/step01/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | meteor-base@1.5.1 # Packages every Meteor app needs to have
8 | mobile-experience@1.1.0 # Packages for a great mobile UX
9 | mongo@1.15.0 # The database Meteor supports right now
10 | blaze-html-templates # Compile .html files into Meteor Blaze views
11 | jquery # Wrapper package for npm-installed jquery
12 | reactive-var@1.0.11 # Reactive variable for tracker
13 | tracker@1.2.0 # Meteor's client-side reactive programming library
14 |
15 | standard-minifier-css@1.8.1 # CSS minifier run for production mode
16 | standard-minifier-js@2.8.0 # JS minifier run for production mode
17 | es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers
18 | ecmascript@0.16.2 # Enable ECMAScript2015+ syntax in app code
19 | typescript@4.5.4 # Enable TypeScript syntax in .ts and .tsx modules
20 | shell-server@0.5.0 # Server-side component of the `meteor shell` command
21 |
22 | autopublish@1.0.7 # Publish all data to the clients (for prototyping)
23 | insecure@1.0.7 # Allow all DB writes from clients (for prototyping)
24 | hot-module-replacement@0.5.1
25 | blaze-hot
26 | dev-error-overlay@0.1.1
27 |
--------------------------------------------------------------------------------
/src/simple-todos/step01/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 |
--------------------------------------------------------------------------------
/src/simple-todos/step01/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@2.7.2
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step01/.meteor/versions:
--------------------------------------------------------------------------------
1 | allow-deny@1.1.1
2 | autopublish@1.0.7
3 | autoupdate@1.8.0
4 | babel-compiler@7.9.0
5 | babel-runtime@1.5.0
6 | base64@1.0.12
7 | binary-heap@1.0.11
8 | blaze@2.6.0
9 | blaze-hot@1.1.1
10 | blaze-html-templates@2.0.0
11 | blaze-tools@1.1.3
12 | boilerplate-generator@1.7.1
13 | caching-compiler@1.2.2
14 | caching-html-compiler@1.2.1
15 | callback-hook@1.4.0
16 | check@1.3.1
17 | ddp@1.4.0
18 | ddp-client@2.5.0
19 | ddp-common@1.4.0
20 | ddp-server@2.5.0
21 | dev-error-overlay@0.1.1
22 | diff-sequence@1.1.1
23 | dynamic-import@0.7.2
24 | ecmascript@0.16.2
25 | ecmascript-runtime@0.8.0
26 | ecmascript-runtime-client@0.12.1
27 | ecmascript-runtime-server@0.11.0
28 | ejson@1.1.2
29 | es5-shim@4.8.0
30 | fetch@0.1.1
31 | geojson-utils@1.0.10
32 | hot-code-push@1.0.4
33 | hot-module-replacement@0.5.1
34 | html-tools@1.1.3
35 | htmljs@1.1.1
36 | id-map@1.1.1
37 | insecure@1.0.7
38 | inter-process-messaging@0.1.1
39 | jquery@3.0.0
40 | launch-screen@1.3.0
41 | logging@1.3.1
42 | meteor@1.10.0
43 | meteor-base@1.5.1
44 | minifier-css@1.6.0
45 | minifier-js@2.7.4
46 | minimongo@1.8.0
47 | mobile-experience@1.1.0
48 | mobile-status-bar@1.1.0
49 | modern-browsers@0.1.8
50 | modules@0.18.0
51 | modules-runtime@0.13.0
52 | modules-runtime-hot@0.14.0
53 | mongo@1.15.0
54 | mongo-decimal@0.1.3
55 | mongo-dev-server@1.1.0
56 | mongo-id@1.0.8
57 | npm-mongo@4.3.1
58 | observe-sequence@1.0.20
59 | ordered-dict@1.1.0
60 | promise@0.12.0
61 | random@1.2.0
62 | react-fast-refresh@0.2.3
63 | reactive-var@1.0.11
64 | reload@1.3.1
65 | retry@1.1.0
66 | routepolicy@1.1.1
67 | shell-server@0.5.0
68 | socket-stream-client@0.5.0
69 | spacebars@1.3.0
70 | spacebars-compiler@1.3.1
71 | standard-minifier-css@1.8.1
72 | standard-minifier-js@2.8.0
73 | templating@1.4.2
74 | templating-compiler@1.4.1
75 | templating-runtime@1.6.0
76 | templating-tools@1.2.2
77 | tracker@1.2.0
78 | typescript@4.5.4
79 | underscore@1.0.10
80 | webapp@1.13.1
81 | webapp-hashing@1.1.0
82 |
--------------------------------------------------------------------------------
/src/simple-todos/step01/client/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 10px;
3 | font-family: sans-serif;
4 | }
5 |
--------------------------------------------------------------------------------
/src/simple-todos/step01/client/main.html:
--------------------------------------------------------------------------------
1 |
2 | step01
3 |
4 |
5 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/simple-todos/step01/client/main.js:
--------------------------------------------------------------------------------
1 | import '../imports/ui/App.js';
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step01/imports/ui/App.html:
--------------------------------------------------------------------------------
1 |
2 | {{> mainContainer}}
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
13 | {{#each tasks}}
14 | {{> task}}
15 | {{/each}}
16 |
17 |
18 |
19 |
20 |
21 | {{text}}
22 |
23 |
--------------------------------------------------------------------------------
/src/simple-todos/step01/imports/ui/App.js:
--------------------------------------------------------------------------------
1 | import { Template } from 'meteor/templating';
2 |
3 | import './App.html';
4 |
5 | Template.mainContainer.helpers({
6 | tasks: [
7 | { text: 'This is task 1' },
8 | { text: 'This is task 2' },
9 | { text: 'This is task 3' },
10 | ],
11 | });
12 |
--------------------------------------------------------------------------------
/src/simple-todos/step01/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "step01",
3 | "private": true,
4 | "scripts": {
5 | "start": "meteor run",
6 | "test": "meteor test --once --driver-package meteortesting:mocha",
7 | "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
8 | "visualize": "meteor --production --extra-packages bundle-visualizer"
9 | },
10 | "dependencies": {
11 | "@babel/runtime": "^7.15.4",
12 | "jquery": "^3.6",
13 | "meteor-node-stubs": "^1.2.3"
14 | },
15 | "meteor": {
16 | "mainModule": {
17 | "client": "client/main.js",
18 | "server": "server/main.js"
19 | },
20 | "testModule": "tests/main.js"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/simple-todos/step01/server/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 |
3 | Meteor.startup(() => {
4 | // code to run on server at startup
5 | });
6 |
--------------------------------------------------------------------------------
/src/simple-todos/step01/tests/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import assert from 'assert';
3 |
4 | describe('step01', function() {
5 | it('package.json has correct name', async function() {
6 | const { name } = await import('../package.json');
7 | assert.strictEqual(name, 'step01');
8 | });
9 |
10 | if (Meteor.isClient) {
11 | it('client is not server', function() {
12 | assert.strictEqual(Meteor.isServer, false);
13 | });
14 | }
15 |
16 | if (Meteor.isServer) {
17 | it('server is not client', function() {
18 | assert.strictEqual(Meteor.isClient, false);
19 | });
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/src/simple-todos/step02/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step02/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | 0.9.4-platform-file
8 | notices-for-facebook-graph-api-2
9 | 1.2.0-standard-minifiers-package
10 | 1.2.0-meteor-platform-split
11 | 1.2.0-cordova-changes
12 | 1.2.0-breaking-changes
13 | 1.3.0-split-minifiers-package
14 | 1.4.0-remove-old-dev-bundle-link
15 | 1.4.1-add-shell-server-package
16 | 1.4.3-split-account-service-packages
17 | 1.5-add-dynamic-import-package
18 | 1.7-split-underscore-from-meteor-base
19 | 1.8.3-split-jquery-from-blaze
20 |
--------------------------------------------------------------------------------
/src/simple-todos/step02/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step02/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | nlvom1n4rsd.t6xtf6i5fdy
8 |
--------------------------------------------------------------------------------
/src/simple-todos/step02/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | meteor-base@1.5.1 # Packages every Meteor app needs to have
8 | mobile-experience@1.1.0 # Packages for a great mobile UX
9 | mongo@1.15.0 # The database Meteor supports right now
10 | blaze-html-templates # Compile .html files into Meteor Blaze views
11 | jquery # Wrapper package for npm-installed jquery
12 | reactive-var@1.0.11 # Reactive variable for tracker
13 | tracker@1.2.0 # Meteor's client-side reactive programming library
14 |
15 | standard-minifier-css@1.8.1 # CSS minifier run for production mode
16 | standard-minifier-js@2.8.0 # JS minifier run for production mode
17 | es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers
18 | ecmascript@0.16.2 # Enable ECMAScript2015+ syntax in app code
19 | typescript@4.5.4 # Enable TypeScript syntax in .ts and .tsx modules
20 | shell-server@0.5.0 # Server-side component of the `meteor shell` command
21 |
22 | autopublish@1.0.7 # Publish all data to the clients (for prototyping)
23 | insecure@1.0.7 # Allow all DB writes from clients (for prototyping)
24 | hot-module-replacement@0.5.1
25 | blaze-hot
26 | dev-error-overlay@0.1.1
27 |
--------------------------------------------------------------------------------
/src/simple-todos/step02/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 |
--------------------------------------------------------------------------------
/src/simple-todos/step02/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@2.7.2
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step02/.meteor/versions:
--------------------------------------------------------------------------------
1 | allow-deny@1.1.1
2 | autopublish@1.0.7
3 | autoupdate@1.8.0
4 | babel-compiler@7.9.0
5 | babel-runtime@1.5.0
6 | base64@1.0.12
7 | binary-heap@1.0.11
8 | blaze@2.6.0
9 | blaze-hot@1.1.1
10 | blaze-html-templates@2.0.0
11 | blaze-tools@1.1.3
12 | boilerplate-generator@1.7.1
13 | caching-compiler@1.2.2
14 | caching-html-compiler@1.2.1
15 | callback-hook@1.4.0
16 | check@1.3.1
17 | ddp@1.4.0
18 | ddp-client@2.5.0
19 | ddp-common@1.4.0
20 | ddp-server@2.5.0
21 | dev-error-overlay@0.1.1
22 | diff-sequence@1.1.1
23 | dynamic-import@0.7.2
24 | ecmascript@0.16.2
25 | ecmascript-runtime@0.8.0
26 | ecmascript-runtime-client@0.12.1
27 | ecmascript-runtime-server@0.11.0
28 | ejson@1.1.2
29 | es5-shim@4.8.0
30 | fetch@0.1.1
31 | geojson-utils@1.0.10
32 | hot-code-push@1.0.4
33 | hot-module-replacement@0.5.1
34 | html-tools@1.1.3
35 | htmljs@1.1.1
36 | id-map@1.1.1
37 | insecure@1.0.7
38 | inter-process-messaging@0.1.1
39 | jquery@3.0.0
40 | launch-screen@1.3.0
41 | logging@1.3.1
42 | meteor@1.10.0
43 | meteor-base@1.5.1
44 | minifier-css@1.6.0
45 | minifier-js@2.7.4
46 | minimongo@1.8.0
47 | mobile-experience@1.1.0
48 | mobile-status-bar@1.1.0
49 | modern-browsers@0.1.8
50 | modules@0.18.0
51 | modules-runtime@0.13.0
52 | modules-runtime-hot@0.14.0
53 | mongo@1.15.0
54 | mongo-decimal@0.1.3
55 | mongo-dev-server@1.1.0
56 | mongo-id@1.0.8
57 | npm-mongo@4.3.1
58 | observe-sequence@1.0.20
59 | ordered-dict@1.1.0
60 | promise@0.12.0
61 | random@1.2.0
62 | react-fast-refresh@0.2.3
63 | reactive-var@1.0.11
64 | reload@1.3.1
65 | retry@1.1.0
66 | routepolicy@1.1.1
67 | shell-server@0.5.0
68 | socket-stream-client@0.5.0
69 | spacebars@1.3.0
70 | spacebars-compiler@1.3.1
71 | standard-minifier-css@1.8.1
72 | standard-minifier-js@2.8.0
73 | templating@1.4.2
74 | templating-compiler@1.4.1
75 | templating-runtime@1.6.0
76 | templating-tools@1.2.2
77 | tracker@1.2.0
78 | typescript@4.5.4
79 | underscore@1.0.10
80 | webapp@1.13.1
81 | webapp-hashing@1.1.0
82 |
--------------------------------------------------------------------------------
/src/simple-todos/step02/client/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 10px;
3 | font-family: sans-serif;
4 | }
5 |
--------------------------------------------------------------------------------
/src/simple-todos/step02/client/main.html:
--------------------------------------------------------------------------------
1 |
2 | step02
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/simple-todos/step02/client/main.js:
--------------------------------------------------------------------------------
1 | import '../imports/ui/App.js';
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step02/imports/api/TasksCollection.js:
--------------------------------------------------------------------------------
1 | import { Mongo } from 'meteor/mongo';
2 |
3 | export const TasksCollection = new Mongo.Collection('tasks');
4 |
--------------------------------------------------------------------------------
/src/simple-todos/step02/imports/ui/App.html:
--------------------------------------------------------------------------------
1 |
2 | {{> mainContainer}}
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
13 | {{#each tasks}}
14 | {{> task}}
15 | {{/each}}
16 |
17 |
18 |
19 |
20 |
21 | {{text}}
22 |
23 |
--------------------------------------------------------------------------------
/src/simple-todos/step02/imports/ui/App.js:
--------------------------------------------------------------------------------
1 | import { Template } from 'meteor/templating';
2 | import { TasksCollection } from '../api/TasksCollection';
3 | import './App.html';
4 |
5 | Template.mainContainer.helpers({
6 | tasks() {
7 | return TasksCollection.find({});
8 | },
9 | });
10 |
--------------------------------------------------------------------------------
/src/simple-todos/step02/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "step01",
3 | "private": true,
4 | "scripts": {
5 | "start": "meteor run",
6 | "test": "meteor test --once --driver-package meteortesting:mocha",
7 | "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
8 | "visualize": "meteor --production --extra-packages bundle-visualizer"
9 | },
10 | "dependencies": {
11 | "@babel/runtime": "^7.15.4",
12 | "jquery": "^3.6",
13 | "meteor-node-stubs": "^1.2.3"
14 | },
15 | "meteor": {
16 | "mainModule": {
17 | "client": "client/main.js",
18 | "server": "server/main.js"
19 | },
20 | "testModule": "tests/main.js"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/simple-todos/step02/server/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { TasksCollection } from '/imports/api/TasksCollection';
3 |
4 | const insertTask = taskText => TasksCollection.insert({ text: taskText });
5 |
6 | Meteor.startup(() => {
7 | if (TasksCollection.find().count() === 0) {
8 | [
9 | 'First Task',
10 | 'Second Task',
11 | 'Third Task',
12 | 'Fourth Task',
13 | 'Fifth Task',
14 | 'Sixth Task',
15 | 'Seventh Task',
16 | ].forEach(insertTask);
17 | }
18 | });
19 |
--------------------------------------------------------------------------------
/src/simple-todos/step02/tests/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import assert from 'assert';
3 |
4 | describe('step01', function() {
5 | it('package.json has correct name', async function() {
6 | const { name } = await import('../package.json');
7 | assert.strictEqual(name, 'step01');
8 | });
9 |
10 | if (Meteor.isClient) {
11 | it('client is not server', function() {
12 | assert.strictEqual(Meteor.isServer, false);
13 | });
14 | }
15 |
16 | if (Meteor.isServer) {
17 | it('server is not client', function() {
18 | assert.strictEqual(Meteor.isClient, false);
19 | });
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/src/simple-todos/step03/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step03/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | 0.9.4-platform-file
8 | notices-for-facebook-graph-api-2
9 | 1.2.0-standard-minifiers-package
10 | 1.2.0-meteor-platform-split
11 | 1.2.0-cordova-changes
12 | 1.2.0-breaking-changes
13 | 1.3.0-split-minifiers-package
14 | 1.4.0-remove-old-dev-bundle-link
15 | 1.4.1-add-shell-server-package
16 | 1.4.3-split-account-service-packages
17 | 1.5-add-dynamic-import-package
18 | 1.7-split-underscore-from-meteor-base
19 | 1.8.3-split-jquery-from-blaze
20 |
--------------------------------------------------------------------------------
/src/simple-todos/step03/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step03/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | nlvom1n4rsd.t6xtf6i5fdy
8 |
--------------------------------------------------------------------------------
/src/simple-todos/step03/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | meteor-base@1.5.1 # Packages every Meteor app needs to have
8 | mobile-experience@1.1.0 # Packages for a great mobile UX
9 | mongo@1.15.0 # The database Meteor supports right now
10 | blaze-html-templates # Compile .html files into Meteor Blaze views
11 | jquery # Wrapper package for npm-installed jquery
12 | reactive-var@1.0.11 # Reactive variable for tracker
13 | tracker@1.2.0 # Meteor's client-side reactive programming library
14 |
15 | standard-minifier-css@1.8.1 # CSS minifier run for production mode
16 | standard-minifier-js@2.8.0 # JS minifier run for production mode
17 | es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers
18 | ecmascript@0.16.2 # Enable ECMAScript2015+ syntax in app code
19 | typescript@4.5.4 # Enable TypeScript syntax in .ts and .tsx modules
20 | shell-server@0.5.0 # Server-side component of the `meteor shell` command
21 |
22 | autopublish@1.0.7 # Publish all data to the clients (for prototyping)
23 | insecure@1.0.7 # Allow all DB writes from clients (for prototyping)
24 | hot-module-replacement@0.5.1
25 | blaze-hot
26 | dev-error-overlay@0.1.1
27 |
--------------------------------------------------------------------------------
/src/simple-todos/step03/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 |
--------------------------------------------------------------------------------
/src/simple-todos/step03/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@2.7.2
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step03/.meteor/versions:
--------------------------------------------------------------------------------
1 | allow-deny@1.1.1
2 | autopublish@1.0.7
3 | autoupdate@1.8.0
4 | babel-compiler@7.9.0
5 | babel-runtime@1.5.0
6 | base64@1.0.12
7 | binary-heap@1.0.11
8 | blaze@2.6.0
9 | blaze-hot@1.1.1
10 | blaze-html-templates@2.0.0
11 | blaze-tools@1.1.3
12 | boilerplate-generator@1.7.1
13 | caching-compiler@1.2.2
14 | caching-html-compiler@1.2.1
15 | callback-hook@1.4.0
16 | check@1.3.1
17 | ddp@1.4.0
18 | ddp-client@2.5.0
19 | ddp-common@1.4.0
20 | ddp-server@2.5.0
21 | dev-error-overlay@0.1.1
22 | diff-sequence@1.1.1
23 | dynamic-import@0.7.2
24 | ecmascript@0.16.2
25 | ecmascript-runtime@0.8.0
26 | ecmascript-runtime-client@0.12.1
27 | ecmascript-runtime-server@0.11.0
28 | ejson@1.1.2
29 | es5-shim@4.8.0
30 | fetch@0.1.1
31 | geojson-utils@1.0.10
32 | hot-code-push@1.0.4
33 | hot-module-replacement@0.5.1
34 | html-tools@1.1.3
35 | htmljs@1.1.1
36 | id-map@1.1.1
37 | insecure@1.0.7
38 | inter-process-messaging@0.1.1
39 | jquery@3.0.0
40 | launch-screen@1.3.0
41 | logging@1.3.1
42 | meteor@1.10.0
43 | meteor-base@1.5.1
44 | minifier-css@1.6.0
45 | minifier-js@2.7.4
46 | minimongo@1.8.0
47 | mobile-experience@1.1.0
48 | mobile-status-bar@1.1.0
49 | modern-browsers@0.1.8
50 | modules@0.18.0
51 | modules-runtime@0.13.0
52 | modules-runtime-hot@0.14.0
53 | mongo@1.15.0
54 | mongo-decimal@0.1.3
55 | mongo-dev-server@1.1.0
56 | mongo-id@1.0.8
57 | npm-mongo@4.3.1
58 | observe-sequence@1.0.20
59 | ordered-dict@1.1.0
60 | promise@0.12.0
61 | random@1.2.0
62 | react-fast-refresh@0.2.3
63 | reactive-var@1.0.11
64 | reload@1.3.1
65 | retry@1.1.0
66 | routepolicy@1.1.1
67 | shell-server@0.5.0
68 | socket-stream-client@0.5.0
69 | spacebars@1.3.0
70 | spacebars-compiler@1.3.1
71 | standard-minifier-css@1.8.1
72 | standard-minifier-js@2.8.0
73 | templating@1.4.2
74 | templating-compiler@1.4.1
75 | templating-runtime@1.6.0
76 | templating-tools@1.2.2
77 | tracker@1.2.0
78 | typescript@4.5.4
79 | underscore@1.0.10
80 | webapp@1.13.1
81 | webapp-hashing@1.1.0
82 |
--------------------------------------------------------------------------------
/src/simple-todos/step03/client/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 10px;
3 | font-family: sans-serif;
4 | }
5 |
6 | .task-form {
7 | margin-top: 1rem;
8 | }
--------------------------------------------------------------------------------
/src/simple-todos/step03/client/main.html:
--------------------------------------------------------------------------------
1 |
2 | step03
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/simple-todos/step03/client/main.js:
--------------------------------------------------------------------------------
1 | import '../imports/ui/App.js';
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step03/imports/api/TasksCollection.js:
--------------------------------------------------------------------------------
1 | import { Mongo } from 'meteor/mongo';
2 |
3 | export const TasksCollection = new Mongo.Collection('tasks');
4 |
--------------------------------------------------------------------------------
/src/simple-todos/step03/imports/ui/App.html:
--------------------------------------------------------------------------------
1 |
2 | {{> mainContainer}}
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 | {{> form }}
13 |
14 |
15 | {{#each tasks}}
16 | {{> task}}
17 | {{/each}}
18 |
19 |
20 |
21 |
22 |
23 | {{text}}
24 |
25 |
26 |
27 |
31 |
32 |
--------------------------------------------------------------------------------
/src/simple-todos/step03/imports/ui/App.js:
--------------------------------------------------------------------------------
1 | import { Template } from 'meteor/templating';
2 | import { TasksCollection } from '../api/TasksCollection';
3 | import './App.html';
4 |
5 | Template.mainContainer.helpers({
6 | tasks() {
7 | return TasksCollection.find({}, { sort: { createdAt: -1 } });
8 | },
9 | });
10 |
11 | Template.form.events({
12 | 'submit .task-form'(event) {
13 | // Prevent default browser form submit
14 | event.preventDefault();
15 |
16 | // Get value from form element
17 | const { target } = event;
18 | const text = target.text.value;
19 |
20 | // Insert a task into the collection
21 | TasksCollection.insert({
22 | text,
23 | createdAt: new Date(), // current time
24 | });
25 |
26 | // Clear form
27 | target.text.value = '';
28 | },
29 | });
30 |
--------------------------------------------------------------------------------
/src/simple-todos/step03/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "step01",
3 | "private": true,
4 | "scripts": {
5 | "start": "meteor run",
6 | "test": "meteor test --once --driver-package meteortesting:mocha",
7 | "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
8 | "visualize": "meteor --production --extra-packages bundle-visualizer"
9 | },
10 | "dependencies": {
11 | "@babel/runtime": "^7.15.4",
12 | "jquery": "^3.6",
13 | "meteor-node-stubs": "^1.2.3"
14 | },
15 | "meteor": {
16 | "mainModule": {
17 | "client": "client/main.js",
18 | "server": "server/main.js"
19 | },
20 | "testModule": "tests/main.js"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/simple-todos/step03/server/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { TasksCollection } from '/imports/api/TasksCollection';
3 |
4 | const insertTask = taskText => TasksCollection.insert({ text: taskText });
5 |
6 | Meteor.startup(() => {
7 | if (TasksCollection.find().count() === 0) {
8 | [
9 | 'First Task',
10 | 'Second Task',
11 | 'Third Task',
12 | 'Fourth Task',
13 | 'Fifth Task',
14 | 'Sixth Task',
15 | 'Seventh Task',
16 | ].forEach(insertTask);
17 | }
18 | });
19 |
--------------------------------------------------------------------------------
/src/simple-todos/step03/tests/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import assert from 'assert';
3 |
4 | describe('step01', function() {
5 | it('package.json has correct name', async function() {
6 | const { name } = await import('../package.json');
7 | assert.strictEqual(name, 'step01');
8 | });
9 |
10 | if (Meteor.isClient) {
11 | it('client is not server', function() {
12 | assert.strictEqual(Meteor.isServer, false);
13 | });
14 | }
15 |
16 | if (Meteor.isServer) {
17 | it('server is not client', function() {
18 | assert.strictEqual(Meteor.isClient, false);
19 | });
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | 0.9.4-platform-file
8 | notices-for-facebook-graph-api-2
9 | 1.2.0-standard-minifiers-package
10 | 1.2.0-meteor-platform-split
11 | 1.2.0-cordova-changes
12 | 1.2.0-breaking-changes
13 | 1.3.0-split-minifiers-package
14 | 1.4.0-remove-old-dev-bundle-link
15 | 1.4.1-add-shell-server-package
16 | 1.4.3-split-account-service-packages
17 | 1.5-add-dynamic-import-package
18 | 1.7-split-underscore-from-meteor-base
19 | 1.8.3-split-jquery-from-blaze
20 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | nlvom1n4rsd.t6xtf6i5fdy
8 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | meteor-base@1.5.1 # Packages every Meteor app needs to have
8 | mobile-experience@1.1.0 # Packages for a great mobile UX
9 | mongo@1.15.0 # The database Meteor supports right now
10 | blaze-html-templates # Compile .html files into Meteor Blaze views
11 | jquery # Wrapper package for npm-installed jquery
12 | reactive-var@1.0.11 # Reactive variable for tracker
13 | tracker@1.2.0 # Meteor's client-side reactive programming library
14 |
15 | standard-minifier-css@1.8.1 # CSS minifier run for production mode
16 | standard-minifier-js@2.8.0 # JS minifier run for production mode
17 | es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers
18 | ecmascript@0.16.2 # Enable ECMAScript2015+ syntax in app code
19 | typescript@4.5.4 # Enable TypeScript syntax in .ts and .tsx modules
20 | shell-server@0.5.0 # Server-side component of the `meteor shell` command
21 |
22 | autopublish@1.0.7 # Publish all data to the clients (for prototyping)
23 | insecure@1.0.7 # Allow all DB writes from clients (for prototyping)
24 | hot-module-replacement@0.5.1
25 | blaze-hot
26 | dev-error-overlay@0.1.1
27 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@2.7.2
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/.meteor/versions:
--------------------------------------------------------------------------------
1 | allow-deny@1.1.1
2 | autopublish@1.0.7
3 | autoupdate@1.8.0
4 | babel-compiler@7.9.0
5 | babel-runtime@1.5.0
6 | base64@1.0.12
7 | binary-heap@1.0.11
8 | blaze@2.6.0
9 | blaze-hot@1.1.1
10 | blaze-html-templates@2.0.0
11 | blaze-tools@1.1.3
12 | boilerplate-generator@1.7.1
13 | caching-compiler@1.2.2
14 | caching-html-compiler@1.2.1
15 | callback-hook@1.4.0
16 | check@1.3.1
17 | ddp@1.4.0
18 | ddp-client@2.5.0
19 | ddp-common@1.4.0
20 | ddp-server@2.5.0
21 | dev-error-overlay@0.1.1
22 | diff-sequence@1.1.1
23 | dynamic-import@0.7.2
24 | ecmascript@0.16.2
25 | ecmascript-runtime@0.8.0
26 | ecmascript-runtime-client@0.12.1
27 | ecmascript-runtime-server@0.11.0
28 | ejson@1.1.2
29 | es5-shim@4.8.0
30 | fetch@0.1.1
31 | geojson-utils@1.0.10
32 | hot-code-push@1.0.4
33 | hot-module-replacement@0.5.1
34 | html-tools@1.1.3
35 | htmljs@1.1.1
36 | id-map@1.1.1
37 | insecure@1.0.7
38 | inter-process-messaging@0.1.1
39 | jquery@3.0.0
40 | launch-screen@1.3.0
41 | logging@1.3.1
42 | meteor@1.10.0
43 | meteor-base@1.5.1
44 | minifier-css@1.6.0
45 | minifier-js@2.7.4
46 | minimongo@1.8.0
47 | mobile-experience@1.1.0
48 | mobile-status-bar@1.1.0
49 | modern-browsers@0.1.8
50 | modules@0.18.0
51 | modules-runtime@0.13.0
52 | modules-runtime-hot@0.14.0
53 | mongo@1.15.0
54 | mongo-decimal@0.1.3
55 | mongo-dev-server@1.1.0
56 | mongo-id@1.0.8
57 | npm-mongo@4.3.1
58 | observe-sequence@1.0.20
59 | ordered-dict@1.1.0
60 | promise@0.12.0
61 | random@1.2.0
62 | react-fast-refresh@0.2.3
63 | reactive-var@1.0.11
64 | reload@1.3.1
65 | retry@1.1.0
66 | routepolicy@1.1.1
67 | shell-server@0.5.0
68 | socket-stream-client@0.5.0
69 | spacebars@1.3.0
70 | spacebars-compiler@1.3.1
71 | standard-minifier-css@1.8.1
72 | standard-minifier-js@2.8.0
73 | templating@1.4.2
74 | templating-compiler@1.4.1
75 | templating-runtime@1.6.0
76 | templating-tools@1.2.2
77 | tracker@1.2.0
78 | typescript@4.5.4
79 | underscore@1.0.10
80 | webapp@1.13.1
81 | webapp-hashing@1.1.0
82 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/client/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 10px;
3 | font-family: sans-serif;
4 | }
5 |
6 | .task-form {
7 | margin-top: 1rem;
8 | }
--------------------------------------------------------------------------------
/src/simple-todos/step04/client/main.html:
--------------------------------------------------------------------------------
1 |
2 | step04
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/client/main.js:
--------------------------------------------------------------------------------
1 | import '../imports/ui/App.js';
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/imports/api/TasksCollection.js:
--------------------------------------------------------------------------------
1 | import { Mongo } from 'meteor/mongo';
2 |
3 | export const TasksCollection = new Mongo.Collection('tasks');
4 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/imports/ui/App.html:
--------------------------------------------------------------------------------
1 |
2 | {{> mainContainer}}
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 | {{> form }}
13 |
14 |
15 | {{#each tasks}}
16 | {{> task}}
17 | {{/each}}
18 |
19 |
20 |
21 |
22 |
23 |
27 |
28 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/imports/ui/App.js:
--------------------------------------------------------------------------------
1 | import { Template } from 'meteor/templating';
2 | import { TasksCollection } from '../api/TasksCollection';
3 | import './App.html';
4 | import './Task.js';
5 |
6 | Template.mainContainer.helpers({
7 | tasks() {
8 | return TasksCollection.find({}, { sort: { createdAt: -1 } });
9 | },
10 | });
11 |
12 | Template.form.events({
13 | 'submit .task-form'(event) {
14 | // Prevent default browser form submit
15 | event.preventDefault();
16 |
17 | // Get value from form element
18 | const { target } = event;
19 | const text = target.text.value;
20 |
21 | // Insert a task into the collection
22 | TasksCollection.insert({
23 | text,
24 | createdAt: new Date(), // current time
25 | });
26 |
27 | // Clear form
28 | target.text.value = '';
29 | },
30 | });
31 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/imports/ui/Task.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{text}}
5 | ×
6 |
7 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/imports/ui/Task.js:
--------------------------------------------------------------------------------
1 | import { Template } from 'meteor/templating';
2 |
3 | import { TasksCollection } from '../api/TasksCollection';
4 |
5 | import './Task.html';
6 |
7 | Template.task.events({
8 | 'click .toggle-checked'() {
9 | // Set the checked property to the opposite of its current value
10 | TasksCollection.update(this._id, {
11 | $set: { isChecked: !this.isChecked },
12 | });
13 | },
14 | 'click .delete'() {
15 | TasksCollection.remove(this._id);
16 | },
17 | });
18 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "step01",
3 | "private": true,
4 | "scripts": {
5 | "start": "meteor run",
6 | "test": "meteor test --once --driver-package meteortesting:mocha",
7 | "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
8 | "visualize": "meteor --production --extra-packages bundle-visualizer"
9 | },
10 | "dependencies": {
11 | "@babel/runtime": "^7.15.4",
12 | "jquery": "^3.6",
13 | "meteor-node-stubs": "^1.2.3"
14 | },
15 | "meteor": {
16 | "mainModule": {
17 | "client": "client/main.js",
18 | "server": "server/main.js"
19 | },
20 | "testModule": "tests/main.js"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/server/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { TasksCollection } from '/imports/api/TasksCollection';
3 |
4 | const insertTask = taskText => TasksCollection.insert({ text: taskText });
5 |
6 | Meteor.startup(() => {
7 | if (TasksCollection.find().count() === 0) {
8 | [
9 | 'First Task',
10 | 'Second Task',
11 | 'Third Task',
12 | 'Fourth Task',
13 | 'Fifth Task',
14 | 'Sixth Task',
15 | 'Seventh Task',
16 | ].forEach(insertTask);
17 | }
18 | });
19 |
--------------------------------------------------------------------------------
/src/simple-todos/step04/tests/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import assert from 'assert';
3 |
4 | describe('step01', function() {
5 | it('package.json has correct name', async function() {
6 | const { name } = await import('../package.json');
7 | assert.strictEqual(name, 'step01');
8 | });
9 |
10 | if (Meteor.isClient) {
11 | it('client is not server', function() {
12 | assert.strictEqual(Meteor.isServer, false);
13 | });
14 | }
15 |
16 | if (Meteor.isServer) {
17 | it('server is not client', function() {
18 | assert.strictEqual(Meteor.isClient, false);
19 | });
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | 0.9.4-platform-file
8 | notices-for-facebook-graph-api-2
9 | 1.2.0-standard-minifiers-package
10 | 1.2.0-meteor-platform-split
11 | 1.2.0-cordova-changes
12 | 1.2.0-breaking-changes
13 | 1.3.0-split-minifiers-package
14 | 1.4.0-remove-old-dev-bundle-link
15 | 1.4.1-add-shell-server-package
16 | 1.4.3-split-account-service-packages
17 | 1.5-add-dynamic-import-package
18 | 1.7-split-underscore-from-meteor-base
19 | 1.8.3-split-jquery-from-blaze
20 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | nlvom1n4rsd.t6xtf6i5fdy
8 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | meteor-base@1.5.1 # Packages every Meteor app needs to have
8 | mobile-experience@1.1.0 # Packages for a great mobile UX
9 | mongo@1.15.0 # The database Meteor supports right now
10 | blaze-html-templates # Compile .html files into Meteor Blaze views
11 | jquery # Wrapper package for npm-installed jquery
12 | reactive-var@1.0.11 # Reactive variable for tracker
13 | tracker@1.2.0 # Meteor's client-side reactive programming library
14 |
15 | standard-minifier-css@1.8.1 # CSS minifier run for production mode
16 | standard-minifier-js@2.8.0 # JS minifier run for production mode
17 | es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers
18 | ecmascript@0.16.2 # Enable ECMAScript2015+ syntax in app code
19 | typescript@4.5.4 # Enable TypeScript syntax in .ts and .tsx modules
20 | shell-server@0.5.0 # Server-side component of the `meteor shell` command
21 |
22 | autopublish@1.0.7 # Publish all data to the clients (for prototyping)
23 | insecure@1.0.7 # Allow all DB writes from clients (for prototyping)
24 | hot-module-replacement@0.5.1
25 | blaze-hot
26 | dev-error-overlay@0.1.1
27 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@2.7.2
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/.meteor/versions:
--------------------------------------------------------------------------------
1 | allow-deny@1.1.1
2 | autopublish@1.0.7
3 | autoupdate@1.8.0
4 | babel-compiler@7.9.0
5 | babel-runtime@1.5.0
6 | base64@1.0.12
7 | binary-heap@1.0.11
8 | blaze@2.6.0
9 | blaze-hot@1.1.1
10 | blaze-html-templates@2.0.0
11 | blaze-tools@1.1.3
12 | boilerplate-generator@1.7.1
13 | caching-compiler@1.2.2
14 | caching-html-compiler@1.2.1
15 | callback-hook@1.4.0
16 | check@1.3.1
17 | ddp@1.4.0
18 | ddp-client@2.5.0
19 | ddp-common@1.4.0
20 | ddp-server@2.5.0
21 | dev-error-overlay@0.1.1
22 | diff-sequence@1.1.1
23 | dynamic-import@0.7.2
24 | ecmascript@0.16.2
25 | ecmascript-runtime@0.8.0
26 | ecmascript-runtime-client@0.12.1
27 | ecmascript-runtime-server@0.11.0
28 | ejson@1.1.2
29 | es5-shim@4.8.0
30 | fetch@0.1.1
31 | geojson-utils@1.0.10
32 | hot-code-push@1.0.4
33 | hot-module-replacement@0.5.1
34 | html-tools@1.1.3
35 | htmljs@1.1.1
36 | id-map@1.1.1
37 | insecure@1.0.7
38 | inter-process-messaging@0.1.1
39 | jquery@3.0.0
40 | launch-screen@1.3.0
41 | logging@1.3.1
42 | meteor@1.10.0
43 | meteor-base@1.5.1
44 | minifier-css@1.6.0
45 | minifier-js@2.7.4
46 | minimongo@1.8.0
47 | mobile-experience@1.1.0
48 | mobile-status-bar@1.1.0
49 | modern-browsers@0.1.8
50 | modules@0.18.0
51 | modules-runtime@0.13.0
52 | modules-runtime-hot@0.14.0
53 | mongo@1.15.0
54 | mongo-decimal@0.1.3
55 | mongo-dev-server@1.1.0
56 | mongo-id@1.0.8
57 | npm-mongo@4.3.1
58 | observe-sequence@1.0.20
59 | ordered-dict@1.1.0
60 | promise@0.12.0
61 | random@1.2.0
62 | react-fast-refresh@0.2.3
63 | reactive-var@1.0.11
64 | reload@1.3.1
65 | retry@1.1.0
66 | routepolicy@1.1.1
67 | shell-server@0.5.0
68 | socket-stream-client@0.5.0
69 | spacebars@1.3.0
70 | spacebars-compiler@1.3.1
71 | standard-minifier-css@1.8.1
72 | standard-minifier-js@2.8.0
73 | templating@1.4.2
74 | templating-compiler@1.4.1
75 | templating-runtime@1.6.0
76 | templating-tools@1.2.2
77 | tracker@1.2.0
78 | typescript@4.5.4
79 | underscore@1.0.10
80 | webapp@1.13.1
81 | webapp-hashing@1.1.0
82 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/client/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: sans-serif;
3 | background-color: #315481;
4 | background-image: linear-gradient(to bottom, #315481, #918e82 100%);
5 | background-attachment: fixed;
6 |
7 | position: absolute;
8 | top: 0;
9 | bottom: 0;
10 | left: 0;
11 | right: 0;
12 |
13 | padding: 0;
14 | margin: 0;
15 |
16 | font-size: 14px;
17 | }
18 |
19 | button {
20 | font-weight: bold;
21 | font-size: 1em;
22 | border: none;
23 | color: white;
24 | box-shadow: 0 3px 3px rgba(34, 25, 25, 0.4);
25 | padding: 5px;
26 | cursor: pointer;
27 | }
28 |
29 | button:focus {
30 | outline: 0;
31 | }
32 |
33 | .app {
34 | display: flex;
35 | flex-direction: column;
36 | height: 100vh;
37 | }
38 |
39 | .app-header {
40 | flex-grow: 1;
41 | white-space: nowrap;
42 | overflow: hidden;
43 | text-overflow: ellipsis;
44 | }
45 |
46 | .main {
47 | display: flex;
48 | flex-direction: column;
49 | flex-grow: 1;
50 | overflow: auto;
51 | background: white;
52 | }
53 |
54 | .main::-webkit-scrollbar {
55 | width: 0;
56 | height: 0;
57 | background: inherit;
58 | }
59 |
60 | header {
61 | background: #d2edf4;
62 | background-image: linear-gradient(to bottom, #d0edf5, #e1e5f0 100%);
63 | padding: 20px 15px 15px 15px;
64 | position: relative;
65 | box-shadow: 0 3px 3px rgba(34, 25, 25, 0.4);
66 | }
67 |
68 | .app-bar {
69 | display: flex;
70 | justify-content: space-between;
71 | }
72 |
73 | .app-bar h1 {
74 | font-size: 1.5em;
75 | margin: 0;
76 | display: inline-block;
77 | margin-right: 1em;
78 | }
79 |
80 | .task-form {
81 | display: flex;
82 | margin: 16px;
83 | }
84 |
85 | .task-form > input {
86 | flex-grow: 1;
87 | box-sizing: border-box;
88 | padding: 10px 6px;
89 | background: transparent;
90 | border: 1px solid #aaa;
91 | width: 100%;
92 | font-size: 1em;
93 | margin-right: 16px;
94 | }
95 |
96 | .task-form > input:focus {
97 | outline: 0;
98 | }
99 |
100 | .task-form > button {
101 | min-width: 100px;
102 | height: 95%;
103 | background-color: #315481;
104 | }
105 |
106 | .tasks {
107 | list-style-type: none;
108 | padding-inline-start: 0;
109 | padding-left: 16px;
110 | padding-right: 16px;
111 | margin-block-start: 0;
112 | margin-block-end: 0;
113 | }
114 |
115 | .tasks > li {
116 | display: flex;
117 | padding: 16px;
118 | border-bottom: #eee solid 1px;
119 | }
120 |
121 | .tasks > li > span {
122 | flex-grow: 1;
123 | }
124 |
125 | .tasks > li > button {
126 | justify-self: flex-end;
127 | background-color: #ff3046;
128 | }
--------------------------------------------------------------------------------
/src/simple-todos/step05/client/main.html:
--------------------------------------------------------------------------------
1 |
2 | step05
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/client/main.js:
--------------------------------------------------------------------------------
1 | import '../imports/ui/App.js';
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/imports/api/TasksCollection.js:
--------------------------------------------------------------------------------
1 | import { Mongo } from 'meteor/mongo';
2 |
3 | export const TasksCollection = new Mongo.Collection('tasks');
4 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/imports/ui/App.html:
--------------------------------------------------------------------------------
1 |
2 | {{> mainContainer}}
3 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
17 | {{> form }}
18 |
19 |
20 | {{#each tasks}}
21 | {{> task}}
22 | {{/each}}
23 |
24 |
25 |
26 |
27 |
28 |
29 |
33 |
34 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/imports/ui/App.js:
--------------------------------------------------------------------------------
1 | import { Template } from 'meteor/templating';
2 | import { TasksCollection } from '../api/TasksCollection';
3 | import './App.html';
4 | import './Task.js';
5 |
6 | Template.mainContainer.helpers({
7 | tasks() {
8 | return TasksCollection.find({}, { sort: { createdAt: -1 } });
9 | },
10 | });
11 |
12 | Template.form.events({
13 | 'submit .task-form'(event) {
14 | // Prevent default browser form submit
15 | event.preventDefault();
16 |
17 | // Get value from form element
18 | const { target } = event;
19 | const text = target.text.value;
20 |
21 | // Insert a task into the collection
22 | TasksCollection.insert({
23 | text,
24 | createdAt: new Date(), // current time
25 | });
26 |
27 | // Clear form
28 | target.text.value = '';
29 | },
30 | });
31 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/imports/ui/Task.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{text}}
5 | ×
6 |
7 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/imports/ui/Task.js:
--------------------------------------------------------------------------------
1 | import { Template } from 'meteor/templating';
2 |
3 | import { TasksCollection } from '../api/TasksCollection';
4 |
5 | import './Task.html';
6 |
7 | Template.task.events({
8 | 'click .toggle-checked'() {
9 | // Set the checked property to the opposite of its current value
10 | TasksCollection.update(this._id, {
11 | $set: { isChecked: !this.isChecked },
12 | });
13 | },
14 | 'click .delete'() {
15 | TasksCollection.remove(this._id);
16 | },
17 | });
18 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "step01",
3 | "private": true,
4 | "scripts": {
5 | "start": "meteor run",
6 | "test": "meteor test --once --driver-package meteortesting:mocha",
7 | "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
8 | "visualize": "meteor --production --extra-packages bundle-visualizer"
9 | },
10 | "dependencies": {
11 | "@babel/runtime": "^7.15.4",
12 | "jquery": "^3.6",
13 | "meteor-node-stubs": "^1.2.3"
14 | },
15 | "meteor": {
16 | "mainModule": {
17 | "client": "client/main.js",
18 | "server": "server/main.js"
19 | },
20 | "testModule": "tests/main.js"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/server/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { TasksCollection } from '/imports/api/TasksCollection';
3 |
4 | const insertTask = taskText => TasksCollection.insert({ text: taskText });
5 |
6 | Meteor.startup(() => {
7 | if (TasksCollection.find().count() === 0) {
8 | [
9 | 'First Task',
10 | 'Second Task',
11 | 'Third Task',
12 | 'Fourth Task',
13 | 'Fifth Task',
14 | 'Sixth Task',
15 | 'Seventh Task',
16 | ].forEach(insertTask);
17 | }
18 | });
19 |
--------------------------------------------------------------------------------
/src/simple-todos/step05/tests/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import assert from 'assert';
3 |
4 | describe('step01', function() {
5 | it('package.json has correct name', async function() {
6 | const { name } = await import('../package.json');
7 | assert.strictEqual(name, 'step01');
8 | });
9 |
10 | if (Meteor.isClient) {
11 | it('client is not server', function() {
12 | assert.strictEqual(Meteor.isServer, false);
13 | });
14 | }
15 |
16 | if (Meteor.isServer) {
17 | it('server is not client', function() {
18 | assert.strictEqual(Meteor.isClient, false);
19 | });
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | 0.9.4-platform-file
8 | notices-for-facebook-graph-api-2
9 | 1.2.0-standard-minifiers-package
10 | 1.2.0-meteor-platform-split
11 | 1.2.0-cordova-changes
12 | 1.2.0-breaking-changes
13 | 1.3.0-split-minifiers-package
14 | 1.4.0-remove-old-dev-bundle-link
15 | 1.4.1-add-shell-server-package
16 | 1.4.3-split-account-service-packages
17 | 1.5-add-dynamic-import-package
18 | 1.7-split-underscore-from-meteor-base
19 | 1.8.3-split-jquery-from-blaze
20 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | nlvom1n4rsd.t6xtf6i5fdy
8 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | meteor-base@1.5.1 # Packages every Meteor app needs to have
8 | mobile-experience@1.1.0 # Packages for a great mobile UX
9 | mongo@1.15.0 # The database Meteor supports right now
10 | blaze-html-templates # Compile .html files into Meteor Blaze views
11 | jquery # Wrapper package for npm-installed jquery
12 | reactive-var@1.0.11 # Reactive variable for tracker
13 | tracker@1.2.0 # Meteor's client-side reactive programming library
14 |
15 | standard-minifier-css@1.8.1 # CSS minifier run for production mode
16 | standard-minifier-js@2.8.0 # JS minifier run for production mode
17 | es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers
18 | ecmascript@0.16.2 # Enable ECMAScript2015+ syntax in app code
19 | typescript@4.5.4 # Enable TypeScript syntax in .ts and .tsx modules
20 | shell-server@0.5.0 # Server-side component of the `meteor shell` command
21 |
22 | autopublish@1.0.7 # Publish all data to the clients (for prototyping)
23 | insecure@1.0.7 # Allow all DB writes from clients (for prototyping)
24 | reactive-dict@1.3.0
25 | hot-module-replacement@0.5.1
26 | blaze-hot
27 | dev-error-overlay@0.1.1
28 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@2.7.2
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/.meteor/versions:
--------------------------------------------------------------------------------
1 | allow-deny@1.1.1
2 | autopublish@1.0.7
3 | autoupdate@1.8.0
4 | babel-compiler@7.9.0
5 | babel-runtime@1.5.0
6 | base64@1.0.12
7 | binary-heap@1.0.11
8 | blaze@2.6.0
9 | blaze-hot@1.1.1
10 | blaze-html-templates@2.0.0
11 | blaze-tools@1.1.3
12 | boilerplate-generator@1.7.1
13 | caching-compiler@1.2.2
14 | caching-html-compiler@1.2.1
15 | callback-hook@1.4.0
16 | check@1.3.1
17 | ddp@1.4.0
18 | ddp-client@2.5.0
19 | ddp-common@1.4.0
20 | ddp-server@2.5.0
21 | dev-error-overlay@0.1.1
22 | diff-sequence@1.1.1
23 | dynamic-import@0.7.2
24 | ecmascript@0.16.2
25 | ecmascript-runtime@0.8.0
26 | ecmascript-runtime-client@0.12.1
27 | ecmascript-runtime-server@0.11.0
28 | ejson@1.1.2
29 | es5-shim@4.8.0
30 | fetch@0.1.1
31 | geojson-utils@1.0.10
32 | hot-code-push@1.0.4
33 | hot-module-replacement@0.5.1
34 | html-tools@1.1.3
35 | htmljs@1.1.1
36 | id-map@1.1.1
37 | insecure@1.0.7
38 | inter-process-messaging@0.1.1
39 | jquery@3.0.0
40 | launch-screen@1.3.0
41 | logging@1.3.1
42 | meteor@1.10.0
43 | meteor-base@1.5.1
44 | minifier-css@1.6.0
45 | minifier-js@2.7.4
46 | minimongo@1.8.0
47 | mobile-experience@1.1.0
48 | mobile-status-bar@1.1.0
49 | modern-browsers@0.1.8
50 | modules@0.18.0
51 | modules-runtime@0.13.0
52 | modules-runtime-hot@0.14.0
53 | mongo@1.15.0
54 | mongo-decimal@0.1.3
55 | mongo-dev-server@1.1.0
56 | mongo-id@1.0.8
57 | npm-mongo@4.3.1
58 | observe-sequence@1.0.20
59 | ordered-dict@1.1.0
60 | promise@0.12.0
61 | random@1.2.0
62 | react-fast-refresh@0.2.3
63 | reactive-dict@1.3.0
64 | reactive-var@1.0.11
65 | reload@1.3.1
66 | retry@1.1.0
67 | routepolicy@1.1.1
68 | shell-server@0.5.0
69 | socket-stream-client@0.5.0
70 | spacebars@1.3.0
71 | spacebars-compiler@1.3.1
72 | standard-minifier-css@1.8.1
73 | standard-minifier-js@2.8.0
74 | templating@1.4.2
75 | templating-compiler@1.4.1
76 | templating-runtime@1.6.0
77 | templating-tools@1.2.2
78 | tracker@1.2.0
79 | typescript@4.5.4
80 | underscore@1.0.10
81 | webapp@1.13.1
82 | webapp-hashing@1.1.0
83 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/client/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: sans-serif;
3 | background-color: #315481;
4 | background-image: linear-gradient(to bottom, #315481, #918e82 100%);
5 | background-attachment: fixed;
6 |
7 | position: absolute;
8 | top: 0;
9 | bottom: 0;
10 | left: 0;
11 | right: 0;
12 |
13 | padding: 0;
14 | margin: 0;
15 |
16 | font-size: 14px;
17 | }
18 |
19 | button {
20 | font-weight: bold;
21 | font-size: 1em;
22 | border: none;
23 | color: white;
24 | box-shadow: 0 3px 3px rgba(34, 25, 25, 0.4);
25 | padding: 5px;
26 | cursor: pointer;
27 | }
28 |
29 | button:focus {
30 | outline: 0;
31 | }
32 |
33 | .app {
34 | display: flex;
35 | flex-direction: column;
36 | height: 100vh;
37 | }
38 |
39 | .app-header {
40 | flex-grow: 1;
41 | white-space: nowrap;
42 | overflow: hidden;
43 | text-overflow: ellipsis;
44 | }
45 |
46 | .main {
47 | display: flex;
48 | flex-direction: column;
49 | flex-grow: 1;
50 | overflow: auto;
51 | background: white;
52 | }
53 |
54 | .main::-webkit-scrollbar {
55 | width: 0;
56 | height: 0;
57 | background: inherit;
58 | }
59 |
60 | header {
61 | background: #d2edf4;
62 | background-image: linear-gradient(to bottom, #d0edf5, #e1e5f0 100%);
63 | padding: 20px 15px 15px 15px;
64 | position: relative;
65 | box-shadow: 0 3px 3px rgba(34, 25, 25, 0.4);
66 | }
67 |
68 | .app-bar {
69 | display: flex;
70 | justify-content: space-between;
71 | }
72 |
73 | .app-bar h1 {
74 | font-size: 1.5em;
75 | margin: 0;
76 | display: inline-block;
77 | margin-right: 1em;
78 | }
79 |
80 | .task-form {
81 | display: flex;
82 | margin: 16px;
83 | }
84 |
85 | .task-form > input {
86 | flex-grow: 1;
87 | box-sizing: border-box;
88 | padding: 10px 6px;
89 | background: transparent;
90 | border: 1px solid #aaa;
91 | width: 100%;
92 | font-size: 1em;
93 | margin-right: 16px;
94 | }
95 |
96 | .task-form > input:focus {
97 | outline: 0;
98 | }
99 |
100 | .task-form > button {
101 | min-width: 100px;
102 | height: 95%;
103 | background-color: #315481;
104 | }
105 |
106 | .tasks {
107 | list-style-type: none;
108 | padding-inline-start: 0;
109 | padding-left: 16px;
110 | padding-right: 16px;
111 | margin-block-start: 0;
112 | margin-block-end: 0;
113 | }
114 |
115 | .tasks > li {
116 | display: flex;
117 | padding: 16px;
118 | border-bottom: #eee solid 1px;
119 | }
120 |
121 | .tasks > li > span {
122 | flex-grow: 1;
123 | }
124 |
125 | .tasks > li > button {
126 | justify-self: flex-end;
127 | background-color: #ff3046;
128 | }
129 |
130 | .filter {
131 | display: flex;
132 | justify-content: center;
133 | }
134 |
135 | .filter > button {
136 | background-color: #62807e;
137 | }
138 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/client/main.html:
--------------------------------------------------------------------------------
1 |
2 | step06
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/client/main.js:
--------------------------------------------------------------------------------
1 | import '../imports/ui/App.js';
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/imports/api/TasksCollection.js:
--------------------------------------------------------------------------------
1 | import { Mongo } from 'meteor/mongo';
2 |
3 | export const TasksCollection = new Mongo.Collection('tasks');
4 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/imports/ui/App.html:
--------------------------------------------------------------------------------
1 |
2 | {{> mainContainer}}
3 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
17 | {{> form }}
18 |
19 |
20 |
21 | {{#if hideCompleted}}
22 | Show All
23 | {{else}}
24 | Hide Completed
25 | {{/if}}
26 |
27 |
28 |
29 |
30 | {{#each tasks}}
31 | {{> task}}
32 | {{/each}}
33 |
34 |
35 |
36 |
37 |
38 |
39 |
43 |
44 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/imports/ui/App.js:
--------------------------------------------------------------------------------
1 | import { Template } from 'meteor/templating';
2 | import { TasksCollection } from '../api/TasksCollection';
3 | import { ReactiveDict } from 'meteor/reactive-dict';
4 | import './App.html';
5 | import './Task.js';
6 |
7 | const HIDE_COMPLETED_STRING = 'hideCompleted';
8 |
9 | Template.mainContainer.onCreated(function mainContainerOnCreated() {
10 | this.state = new ReactiveDict();
11 | });
12 |
13 | Template.mainContainer.events({
14 | 'click #hide-completed-button'(event, instance) {
15 | const currentHideCompleted = instance.state.get(HIDE_COMPLETED_STRING);
16 | instance.state.set(HIDE_COMPLETED_STRING, !currentHideCompleted);
17 | },
18 | });
19 |
20 | Template.mainContainer.helpers({
21 | tasks() {
22 | const instance = Template.instance();
23 | const hideCompleted = instance.state.get(HIDE_COMPLETED_STRING);
24 |
25 | const hideCompletedFilter = { isChecked: { $ne: true } };
26 |
27 | return TasksCollection.find(hideCompleted ? hideCompletedFilter : {}, {
28 | sort: { createdAt: -1 },
29 | }).fetch();
30 | },
31 | hideCompleted() {
32 | return Template.instance().state.get(HIDE_COMPLETED_STRING);
33 | },
34 | incompleteCount() {
35 | const incompleteTasksCount = TasksCollection.find({
36 | isChecked: { $ne: true },
37 | }).count();
38 | return incompleteTasksCount ? `(${incompleteTasksCount})` : '';
39 | },
40 | });
41 |
42 | Template.form.events({
43 | 'submit .task-form'(event) {
44 | // Prevent default browser form submit
45 | event.preventDefault();
46 |
47 | // Get value from form element
48 | const { target } = event;
49 | const text = target.text.value;
50 |
51 | // Insert a task into the collection
52 | TasksCollection.insert({
53 | text,
54 | createdAt: new Date(), // current time
55 | });
56 |
57 | // Clear form
58 | target.text.value = '';
59 | },
60 | });
61 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/imports/ui/Task.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{text}}
5 | ×
6 |
7 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/imports/ui/Task.js:
--------------------------------------------------------------------------------
1 | import { Template } from 'meteor/templating';
2 |
3 | import { TasksCollection } from '../api/TasksCollection';
4 |
5 | import './Task.html';
6 |
7 | Template.task.events({
8 | 'click .toggle-checked'() {
9 | // Set the checked property to the opposite of its current value
10 | TasksCollection.update(this._id, {
11 | $set: { isChecked: !this.isChecked },
12 | });
13 | },
14 | 'click .delete'() {
15 | TasksCollection.remove(this._id);
16 | },
17 | });
18 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "step01",
3 | "private": true,
4 | "scripts": {
5 | "start": "meteor run",
6 | "test": "meteor test --once --driver-package meteortesting:mocha",
7 | "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
8 | "visualize": "meteor --production --extra-packages bundle-visualizer"
9 | },
10 | "dependencies": {
11 | "@babel/runtime": "^7.15.4",
12 | "jquery": "^3.6",
13 | "meteor-node-stubs": "^1.2.3"
14 | },
15 | "meteor": {
16 | "mainModule": {
17 | "client": "client/main.js",
18 | "server": "server/main.js"
19 | },
20 | "testModule": "tests/main.js"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/server/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { TasksCollection } from '/imports/api/TasksCollection';
3 |
4 | const insertTask = taskText => TasksCollection.insert({ text: taskText });
5 |
6 | Meteor.startup(() => {
7 | if (TasksCollection.find().count() === 0) {
8 | [
9 | 'First Task',
10 | 'Second Task',
11 | 'Third Task',
12 | 'Fourth Task',
13 | 'Fifth Task',
14 | 'Sixth Task',
15 | 'Seventh Task',
16 | ].forEach(insertTask);
17 | }
18 | });
19 |
--------------------------------------------------------------------------------
/src/simple-todos/step06/tests/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import assert from 'assert';
3 |
4 | describe('step01', function() {
5 | it('package.json has correct name', async function() {
6 | const { name } = await import('../package.json');
7 | assert.strictEqual(name, 'step01');
8 | });
9 |
10 | if (Meteor.isClient) {
11 | it('client is not server', function() {
12 | assert.strictEqual(Meteor.isServer, false);
13 | });
14 | }
15 |
16 | if (Meteor.isServer) {
17 | it('server is not client', function() {
18 | assert.strictEqual(Meteor.isClient, false);
19 | });
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | 0.9.4-platform-file
8 | notices-for-facebook-graph-api-2
9 | 1.2.0-standard-minifiers-package
10 | 1.2.0-meteor-platform-split
11 | 1.2.0-cordova-changes
12 | 1.2.0-breaking-changes
13 | 1.3.0-split-minifiers-package
14 | 1.4.0-remove-old-dev-bundle-link
15 | 1.4.1-add-shell-server-package
16 | 1.4.3-split-account-service-packages
17 | 1.5-add-dynamic-import-package
18 | 1.7-split-underscore-from-meteor-base
19 | 1.8.3-split-jquery-from-blaze
20 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | nlvom1n4rsd.t6xtf6i5fdy
8 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | meteor-base@1.5.1 # Packages every Meteor app needs to have
8 | mobile-experience@1.1.0 # Packages for a great mobile UX
9 | mongo@1.15.0 # The database Meteor supports right now
10 | blaze-html-templates # Compile .html files into Meteor Blaze views
11 | jquery # Wrapper package for npm-installed jquery
12 | reactive-var@1.0.11 # Reactive variable for tracker
13 | tracker@1.2.0 # Meteor's client-side reactive programming library
14 |
15 | standard-minifier-css@1.8.1 # CSS minifier run for production mode
16 | standard-minifier-js@2.8.0 # JS minifier run for production mode
17 | es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers
18 | ecmascript@0.16.2 # Enable ECMAScript2015+ syntax in app code
19 | typescript@4.5.4 # Enable TypeScript syntax in .ts and .tsx modules
20 | shell-server@0.5.0 # Server-side component of the `meteor shell` command
21 |
22 | autopublish@1.0.7 # Publish all data to the clients (for prototyping)
23 | insecure@1.0.7 # Allow all DB writes from clients (for prototyping)
24 | reactive-dict@1.3.0
25 | accounts-password@2.3.1
26 | hot-module-replacement@0.5.1
27 | blaze-hot
28 | dev-error-overlay@0.1.1
29 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@2.7.2
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/.meteor/versions:
--------------------------------------------------------------------------------
1 | accounts-base@2.2.3
2 | accounts-password@2.3.1
3 | allow-deny@1.1.1
4 | autopublish@1.0.7
5 | autoupdate@1.8.0
6 | babel-compiler@7.9.0
7 | babel-runtime@1.5.0
8 | base64@1.0.12
9 | binary-heap@1.0.11
10 | blaze@2.6.0
11 | blaze-hot@1.1.1
12 | blaze-html-templates@2.0.0
13 | blaze-tools@1.1.3
14 | boilerplate-generator@1.7.1
15 | caching-compiler@1.2.2
16 | caching-html-compiler@1.2.1
17 | callback-hook@1.4.0
18 | check@1.3.1
19 | ddp@1.4.0
20 | ddp-client@2.5.0
21 | ddp-common@1.4.0
22 | ddp-rate-limiter@1.1.0
23 | ddp-server@2.5.0
24 | dev-error-overlay@0.1.1
25 | diff-sequence@1.1.1
26 | dynamic-import@0.7.2
27 | ecmascript@0.16.2
28 | ecmascript-runtime@0.8.0
29 | ecmascript-runtime-client@0.12.1
30 | ecmascript-runtime-server@0.11.0
31 | ejson@1.1.2
32 | email@2.2.1
33 | es5-shim@4.8.0
34 | fetch@0.1.1
35 | geojson-utils@1.0.10
36 | hot-code-push@1.0.4
37 | hot-module-replacement@0.5.1
38 | html-tools@1.1.3
39 | htmljs@1.1.1
40 | id-map@1.1.1
41 | insecure@1.0.7
42 | inter-process-messaging@0.1.1
43 | jquery@3.0.0
44 | launch-screen@1.3.0
45 | localstorage@1.2.0
46 | logging@1.3.1
47 | meteor@1.10.0
48 | meteor-base@1.5.1
49 | minifier-css@1.6.0
50 | minifier-js@2.7.4
51 | minimongo@1.8.0
52 | mobile-experience@1.1.0
53 | mobile-status-bar@1.1.0
54 | modern-browsers@0.1.8
55 | modules@0.18.0
56 | modules-runtime@0.13.0
57 | modules-runtime-hot@0.14.0
58 | mongo@1.15.0
59 | mongo-decimal@0.1.3
60 | mongo-dev-server@1.1.0
61 | mongo-id@1.0.8
62 | npm-mongo@4.3.1
63 | observe-sequence@1.0.20
64 | ordered-dict@1.1.0
65 | promise@0.12.0
66 | random@1.2.0
67 | rate-limit@1.0.9
68 | react-fast-refresh@0.2.3
69 | reactive-dict@1.3.0
70 | reactive-var@1.0.11
71 | reload@1.3.1
72 | retry@1.1.0
73 | routepolicy@1.1.1
74 | service-configuration@1.3.0
75 | sha@1.0.9
76 | shell-server@0.5.0
77 | socket-stream-client@0.5.0
78 | spacebars@1.3.0
79 | spacebars-compiler@1.3.1
80 | standard-minifier-css@1.8.1
81 | standard-minifier-js@2.8.0
82 | templating@1.4.2
83 | templating-compiler@1.4.1
84 | templating-runtime@1.6.0
85 | templating-tools@1.2.2
86 | tracker@1.2.0
87 | typescript@4.5.4
88 | underscore@1.0.10
89 | url@1.3.2
90 | webapp@1.13.1
91 | webapp-hashing@1.1.0
92 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/client/main.html:
--------------------------------------------------------------------------------
1 |
2 | step07
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/client/main.js:
--------------------------------------------------------------------------------
1 | import '../imports/ui/App.js';
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/imports/api/TasksCollection.js:
--------------------------------------------------------------------------------
1 | import { Mongo } from 'meteor/mongo';
2 |
3 | export const TasksCollection = new Mongo.Collection('tasks');
4 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/imports/ui/App.html:
--------------------------------------------------------------------------------
1 |
2 | {{> mainContainer}}
3 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
17 | {{#if isUserLogged}}
18 |
19 | {{getUser.username}} 🚪
20 |
21 | {{> form }}
22 |
23 |
24 |
25 | {{#if hideCompleted}}
26 | Show All
27 | {{else}}
28 | Hide Completed
29 | {{/if}}
30 |
31 |
32 |
33 |
34 | {{#each tasks}}
35 | {{> task}}
36 | {{/each}}
37 |
38 | {{else}}
39 | {{> login }}
40 | {{/if}}
41 |
42 |
43 |
44 |
45 |
46 |
50 |
51 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/imports/ui/App.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Template } from 'meteor/templating';
3 | import { TasksCollection } from '../api/TasksCollection';
4 | import { ReactiveDict } from 'meteor/reactive-dict';
5 | import './App.html';
6 | import './Task.js';
7 | import './Login.js';
8 |
9 | const HIDE_COMPLETED_STRING = 'hideCompleted';
10 |
11 | const getUser = () => Meteor.user();
12 | const isUserLogged = () => !!getUser();
13 |
14 | const getTasksFilter = () => {
15 | const user = getUser();
16 |
17 | const hideCompletedFilter = { isChecked: { $ne: true } };
18 |
19 | const userFilter = user ? { userId: user._id } : {};
20 |
21 | const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilter };
22 |
23 | return { userFilter, pendingOnlyFilter };
24 | };
25 |
26 | Template.mainContainer.onCreated(function mainContainerOnCreated() {
27 | this.state = new ReactiveDict();
28 | });
29 |
30 | Template.mainContainer.events({
31 | 'click #hide-completed-button'(event, instance) {
32 | const currentHideCompleted = instance.state.get(HIDE_COMPLETED_STRING);
33 | instance.state.set(HIDE_COMPLETED_STRING, !currentHideCompleted);
34 | },
35 | 'click .user'() {
36 | Meteor.logout();
37 | },
38 | });
39 |
40 | Template.mainContainer.helpers({
41 | tasks() {
42 | const instance = Template.instance();
43 | const hideCompleted = instance.state.get(HIDE_COMPLETED_STRING);
44 |
45 | const { pendingOnlyFilter, userFilter } = getTasksFilter();
46 |
47 | if (!isUserLogged()) {
48 | return [];
49 | }
50 |
51 | return TasksCollection.find(
52 | hideCompleted ? pendingOnlyFilter : userFilter,
53 | {
54 | sort: { createdAt: -1 },
55 | }
56 | ).fetch();
57 | },
58 | hideCompleted() {
59 | return Template.instance().state.get(HIDE_COMPLETED_STRING);
60 | },
61 | incompleteCount() {
62 | if (!isUserLogged()) {
63 | return '';
64 | }
65 |
66 | const { pendingOnlyFilter } = getTasksFilter();
67 |
68 | const incompleteTasksCount = TasksCollection.find(
69 | pendingOnlyFilter
70 | ).count();
71 | return incompleteTasksCount ? `(${incompleteTasksCount})` : '';
72 | },
73 | isUserLogged() {
74 | return isUserLogged();
75 | },
76 | getUser() {
77 | return getUser();
78 | },
79 | });
80 |
81 | Template.form.events({
82 | 'submit .task-form'(event) {
83 | // Prevent default browser form submit
84 | event.preventDefault();
85 |
86 | // Get value from form element
87 | const { target } = event;
88 | const text = target.text.value;
89 |
90 | // Insert a task into the collection
91 | TasksCollection.insert({
92 | text,
93 | userId: getUser()._id,
94 | createdAt: new Date(), // current time
95 | });
96 |
97 | // Clear form
98 | target.text.value = '';
99 | },
100 | });
101 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/imports/ui/Login.html:
--------------------------------------------------------------------------------
1 |
2 |
28 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/imports/ui/Login.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Template } from 'meteor/templating';
3 | import './Login.html';
4 |
5 | Template.login.events({
6 | 'submit .login-form'(event) {
7 | event.preventDefault();
8 |
9 | const { target } = event;
10 |
11 | const username = target.username.value;
12 | const password = target.password.value;
13 |
14 | Meteor.loginWithPassword(username, password);
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/imports/ui/Task.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{text}}
5 | ×
6 |
7 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/imports/ui/Task.js:
--------------------------------------------------------------------------------
1 | import { Template } from 'meteor/templating';
2 |
3 | import { TasksCollection } from '../api/TasksCollection';
4 |
5 | import './Task.html';
6 |
7 | Template.task.events({
8 | 'click .toggle-checked'() {
9 | // Set the checked property to the opposite of its current value
10 | TasksCollection.update(this._id, {
11 | $set: { isChecked: !this.isChecked },
12 | });
13 | },
14 | 'click .delete'() {
15 | TasksCollection.remove(this._id);
16 | },
17 | });
18 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "step01",
3 | "private": true,
4 | "scripts": {
5 | "start": "meteor run",
6 | "test": "meteor test --once --driver-package meteortesting:mocha",
7 | "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
8 | "visualize": "meteor --production --extra-packages bundle-visualizer"
9 | },
10 | "dependencies": {
11 | "@babel/runtime": "^7.15.4",
12 | "bcrypt": "^5.0.1",
13 | "jquery": "^3.6",
14 | "meteor-node-stubs": "^1.2.3"
15 | },
16 | "meteor": {
17 | "mainModule": {
18 | "client": "client/main.js",
19 | "server": "server/main.js"
20 | },
21 | "testModule": "tests/main.js"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/server/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Accounts } from 'meteor/accounts-base';
3 | import { TasksCollection } from '/imports/api/TasksCollection';
4 |
5 | const insertTask = (taskText, user) =>
6 | TasksCollection.insert({
7 | text: taskText,
8 | userId: user._id,
9 | createdAt: new Date(),
10 | });
11 |
12 | const SEED_USERNAME = 'meteorite';
13 | const SEED_PASSWORD = 'password';
14 |
15 | Meteor.startup(() => {
16 | if (!Accounts.findUserByUsername(SEED_USERNAME)) {
17 | Accounts.createUser({
18 | username: SEED_USERNAME,
19 | password: SEED_PASSWORD,
20 | });
21 | }
22 |
23 | const user = Accounts.findUserByUsername(SEED_USERNAME);
24 |
25 | if (TasksCollection.find().count() === 0) {
26 | [
27 | 'First Task',
28 | 'Second Task',
29 | 'Third Task',
30 | 'Fourth Task',
31 | 'Fifth Task',
32 | 'Sixth Task',
33 | 'Seventh Task',
34 | ].forEach(taskText => insertTask(taskText, user));
35 | }
36 | });
37 |
--------------------------------------------------------------------------------
/src/simple-todos/step07/tests/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import assert from 'assert';
3 |
4 | describe('step01', function() {
5 | it('package.json has correct name', async function() {
6 | const { name } = await import('../package.json');
7 | assert.strictEqual(name, 'step01');
8 | });
9 |
10 | if (Meteor.isClient) {
11 | it('client is not server', function() {
12 | assert.strictEqual(Meteor.isServer, false);
13 | });
14 | }
15 |
16 | if (Meteor.isServer) {
17 | it('server is not client', function() {
18 | assert.strictEqual(Meteor.isClient, false);
19 | });
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | 0.9.4-platform-file
8 | notices-for-facebook-graph-api-2
9 | 1.2.0-standard-minifiers-package
10 | 1.2.0-meteor-platform-split
11 | 1.2.0-cordova-changes
12 | 1.2.0-breaking-changes
13 | 1.3.0-split-minifiers-package
14 | 1.4.0-remove-old-dev-bundle-link
15 | 1.4.1-add-shell-server-package
16 | 1.4.3-split-account-service-packages
17 | 1.5-add-dynamic-import-package
18 | 1.7-split-underscore-from-meteor-base
19 | 1.8.3-split-jquery-from-blaze
20 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | nlvom1n4rsd.t6xtf6i5fdy
8 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | meteor-base@1.5.1 # Packages every Meteor app needs to have
8 | mobile-experience@1.1.0 # Packages for a great mobile UX
9 | mongo@1.15.0 # The database Meteor supports right now
10 | blaze-html-templates # Compile .html files into Meteor Blaze views
11 | jquery # Wrapper package for npm-installed jquery
12 | reactive-var@1.0.11 # Reactive variable for tracker
13 | tracker@1.2.0 # Meteor's client-side reactive programming library
14 |
15 | standard-minifier-css@1.8.1 # CSS minifier run for production mode
16 | standard-minifier-js@2.8.0 # JS minifier run for production mode
17 | es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers
18 | ecmascript@0.16.2 # Enable ECMAScript2015+ syntax in app code
19 | typescript@4.5.4 # Enable TypeScript syntax in .ts and .tsx modules
20 | shell-server@0.5.0 # Server-side component of the `meteor shell` command
21 |
22 | autopublish@1.0.7 # Publish all data to the clients (for prototyping)
23 | reactive-dict@1.3.0
24 | accounts-password@2.3.1
25 | hot-module-replacement@0.5.1
26 | blaze-hot
27 | dev-error-overlay@0.1.1
28 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@2.7.2
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/.meteor/versions:
--------------------------------------------------------------------------------
1 | accounts-base@2.2.3
2 | accounts-password@2.3.1
3 | allow-deny@1.1.1
4 | autopublish@1.0.7
5 | autoupdate@1.8.0
6 | babel-compiler@7.9.0
7 | babel-runtime@1.5.0
8 | base64@1.0.12
9 | binary-heap@1.0.11
10 | blaze@2.6.0
11 | blaze-hot@1.1.1
12 | blaze-html-templates@2.0.0
13 | blaze-tools@1.1.3
14 | boilerplate-generator@1.7.1
15 | caching-compiler@1.2.2
16 | caching-html-compiler@1.2.1
17 | callback-hook@1.4.0
18 | check@1.3.1
19 | ddp@1.4.0
20 | ddp-client@2.5.0
21 | ddp-common@1.4.0
22 | ddp-rate-limiter@1.1.0
23 | ddp-server@2.5.0
24 | dev-error-overlay@0.1.1
25 | diff-sequence@1.1.1
26 | dynamic-import@0.7.2
27 | ecmascript@0.16.2
28 | ecmascript-runtime@0.8.0
29 | ecmascript-runtime-client@0.12.1
30 | ecmascript-runtime-server@0.11.0
31 | ejson@1.1.2
32 | email@2.2.1
33 | es5-shim@4.8.0
34 | fetch@0.1.1
35 | geojson-utils@1.0.10
36 | hot-code-push@1.0.4
37 | hot-module-replacement@0.5.1
38 | html-tools@1.1.3
39 | htmljs@1.1.1
40 | id-map@1.1.1
41 | inter-process-messaging@0.1.1
42 | jquery@3.0.0
43 | launch-screen@1.3.0
44 | localstorage@1.2.0
45 | logging@1.3.1
46 | meteor@1.10.0
47 | meteor-base@1.5.1
48 | minifier-css@1.6.0
49 | minifier-js@2.7.4
50 | minimongo@1.8.0
51 | mobile-experience@1.1.0
52 | mobile-status-bar@1.1.0
53 | modern-browsers@0.1.8
54 | modules@0.18.0
55 | modules-runtime@0.13.0
56 | modules-runtime-hot@0.14.0
57 | mongo@1.15.0
58 | mongo-decimal@0.1.3
59 | mongo-dev-server@1.1.0
60 | mongo-id@1.0.8
61 | npm-mongo@4.3.1
62 | observe-sequence@1.0.20
63 | ordered-dict@1.1.0
64 | promise@0.12.0
65 | random@1.2.0
66 | rate-limit@1.0.9
67 | react-fast-refresh@0.2.3
68 | reactive-dict@1.3.0
69 | reactive-var@1.0.11
70 | reload@1.3.1
71 | retry@1.1.0
72 | routepolicy@1.1.1
73 | service-configuration@1.3.0
74 | sha@1.0.9
75 | shell-server@0.5.0
76 | socket-stream-client@0.5.0
77 | spacebars@1.3.0
78 | spacebars-compiler@1.3.1
79 | standard-minifier-css@1.8.1
80 | standard-minifier-js@2.8.0
81 | templating@1.4.2
82 | templating-compiler@1.4.1
83 | templating-runtime@1.6.0
84 | templating-tools@1.2.2
85 | tracker@1.2.0
86 | typescript@4.5.4
87 | underscore@1.0.10
88 | url@1.3.2
89 | webapp@1.13.1
90 | webapp-hashing@1.1.0
91 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/client/main.html:
--------------------------------------------------------------------------------
1 |
2 | step08
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/client/main.js:
--------------------------------------------------------------------------------
1 | import '../imports/ui/App.js';
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/imports/api/tasksMethods.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { check } from 'meteor/check';
3 | import { TasksCollection } from '../db/TasksCollection';
4 |
5 | Meteor.methods({
6 | 'tasks.insert'(text) {
7 | check(text, String);
8 |
9 | if (!this.userId) {
10 | throw new Meteor.Error('Not authorized.');
11 | }
12 |
13 | TasksCollection.insert({
14 | text,
15 | createdAt: new Date(),
16 | userId: this.userId,
17 | });
18 | },
19 |
20 | 'tasks.remove'(taskId) {
21 | check(taskId, String);
22 |
23 | if (!this.userId) {
24 | throw new Meteor.Error('Not authorized.');
25 | }
26 |
27 | TasksCollection.remove(taskId);
28 | },
29 |
30 | 'tasks.setIsChecked'(taskId, isChecked) {
31 | check(taskId, String);
32 | check(isChecked, Boolean);
33 |
34 | if (!this.userId) {
35 | throw new Meteor.Error('Not authorized.');
36 | }
37 |
38 | TasksCollection.update(taskId, {
39 | $set: {
40 | isChecked,
41 | },
42 | });
43 | },
44 | });
45 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/imports/db/TasksCollection.js:
--------------------------------------------------------------------------------
1 | import { Mongo } from 'meteor/mongo';
2 |
3 | export const TasksCollection = new Mongo.Collection('tasks');
4 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/imports/ui/App.html:
--------------------------------------------------------------------------------
1 |
2 | {{> mainContainer}}
3 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
17 | {{#if isUserLogged}}
18 |
19 | {{getUser.username}} 🚪
20 |
21 | {{> form }}
22 |
23 |
24 |
25 | {{#if hideCompleted}}
26 | Show All
27 | {{else}}
28 | Hide Completed
29 | {{/if}}
30 |
31 |
32 |
33 |
34 | {{#each tasks}}
35 | {{> task}}
36 | {{/each}}
37 |
38 | {{else}}
39 | {{> login }}
40 | {{/if}}
41 |
42 |
43 |
44 |
45 |
46 |
50 |
51 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/imports/ui/App.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Template } from 'meteor/templating';
3 | import { TasksCollection } from '../db/TasksCollection';
4 | import { ReactiveDict } from 'meteor/reactive-dict';
5 | import './App.html';
6 | import './Task.js';
7 | import './Login.js';
8 |
9 | const HIDE_COMPLETED_STRING = 'hideCompleted';
10 |
11 | const getUser = () => Meteor.user();
12 | const isUserLogged = () => !!getUser();
13 |
14 | const getTasksFilter = () => {
15 | const user = getUser();
16 |
17 | const hideCompletedFilter = { isChecked: { $ne: true } };
18 |
19 | const userFilter = user ? { userId: user._id } : {};
20 |
21 | const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilter };
22 |
23 | return { userFilter, pendingOnlyFilter };
24 | };
25 |
26 | Template.mainContainer.onCreated(function mainContainerOnCreated() {
27 | this.state = new ReactiveDict();
28 | });
29 |
30 | Template.mainContainer.events({
31 | 'click #hide-completed-button'(event, instance) {
32 | const currentHideCompleted = instance.state.get(HIDE_COMPLETED_STRING);
33 | instance.state.set(HIDE_COMPLETED_STRING, !currentHideCompleted);
34 | },
35 | 'click .user'() {
36 | Meteor.logout();
37 | },
38 | });
39 |
40 | Template.mainContainer.helpers({
41 | tasks() {
42 | const instance = Template.instance();
43 | const hideCompleted = instance.state.get(HIDE_COMPLETED_STRING);
44 |
45 | const { pendingOnlyFilter, userFilter } = getTasksFilter();
46 |
47 | if (!isUserLogged()) {
48 | return [];
49 | }
50 |
51 | return TasksCollection.find(
52 | hideCompleted ? pendingOnlyFilter : userFilter,
53 | {
54 | sort: { createdAt: -1 },
55 | }
56 | ).fetch();
57 | },
58 | hideCompleted() {
59 | return Template.instance().state.get(HIDE_COMPLETED_STRING);
60 | },
61 | incompleteCount() {
62 | if (!isUserLogged()) {
63 | return '';
64 | }
65 |
66 | const { pendingOnlyFilter } = getTasksFilter();
67 |
68 | const incompleteTasksCount = TasksCollection.find(
69 | pendingOnlyFilter
70 | ).count();
71 | return incompleteTasksCount ? `(${incompleteTasksCount})` : '';
72 | },
73 | isUserLogged() {
74 | return isUserLogged();
75 | },
76 | getUser() {
77 | return getUser();
78 | },
79 | });
80 |
81 | Template.form.events({
82 | 'submit .task-form'(event) {
83 | // Prevent default browser form submit
84 | event.preventDefault();
85 |
86 | // Get value from form element
87 | const { target } = event;
88 | const text = target.text.value;
89 |
90 | // Insert a task into the collection
91 | Meteor.call('tasks.insert', text);
92 |
93 | // Clear form
94 | target.text.value = '';
95 | },
96 | });
97 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/imports/ui/Login.html:
--------------------------------------------------------------------------------
1 |
2 |
28 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/imports/ui/Login.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Template } from 'meteor/templating';
3 | import './Login.html';
4 |
5 | Template.login.events({
6 | 'submit .login-form'(event) {
7 | event.preventDefault();
8 |
9 | const { target } = event;
10 |
11 | const username = target.username.value;
12 | const password = target.password.value;
13 |
14 | Meteor.loginWithPassword(username, password);
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/imports/ui/Task.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{text}}
5 | ×
6 |
7 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/imports/ui/Task.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Template } from 'meteor/templating';
3 |
4 | import './Task.html';
5 |
6 | Template.task.events({
7 | 'click .toggle-checked'() {
8 | // Set the checked property to the opposite of its current value
9 | Meteor.call('tasks.setIsChecked', this._id, !this.isChecked);
10 | },
11 | 'click .delete'() {
12 | Meteor.call('tasks.remove', this._id);
13 | },
14 | });
15 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "step01",
3 | "private": true,
4 | "scripts": {
5 | "start": "meteor run",
6 | "test": "meteor test --once --driver-package meteortesting:mocha",
7 | "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
8 | "visualize": "meteor --production --extra-packages bundle-visualizer"
9 | },
10 | "dependencies": {
11 | "@babel/runtime": "^7.15.4",
12 | "bcrypt": "^5.0.1",
13 | "jquery": "^3.6",
14 | "meteor-node-stubs": "^1.2.3"
15 | },
16 | "meteor": {
17 | "mainModule": {
18 | "client": "client/main.js",
19 | "server": "server/main.js"
20 | },
21 | "testModule": "tests/main.js"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/server/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Accounts } from 'meteor/accounts-base';
3 | import { TasksCollection } from '/imports/db/TasksCollection';
4 | import '/imports/api/tasksMethods';
5 |
6 | const insertTask = (taskText, user) =>
7 | TasksCollection.insert({
8 | text: taskText,
9 | userId: user._id,
10 | createdAt: new Date(),
11 | });
12 |
13 | const SEED_USERNAME = 'meteorite';
14 | const SEED_PASSWORD = 'password';
15 |
16 | Meteor.startup(() => {
17 | if (!Accounts.findUserByUsername(SEED_USERNAME)) {
18 | Accounts.createUser({
19 | username: SEED_USERNAME,
20 | password: SEED_PASSWORD,
21 | });
22 | }
23 |
24 | const user = Accounts.findUserByUsername(SEED_USERNAME);
25 |
26 | if (TasksCollection.find().count() === 0) {
27 | [
28 | 'First Task',
29 | 'Second Task',
30 | 'Third Task',
31 | 'Fourth Task',
32 | 'Fifth Task',
33 | 'Sixth Task',
34 | 'Seventh Task',
35 | ].forEach(taskText => insertTask(taskText, user));
36 | }
37 | });
38 |
--------------------------------------------------------------------------------
/src/simple-todos/step08/tests/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import assert from 'assert';
3 |
4 | describe('step01', function() {
5 | it('package.json has correct name', async function() {
6 | const { name } = await import('../package.json');
7 | assert.strictEqual(name, 'step01');
8 | });
9 |
10 | if (Meteor.isClient) {
11 | it('client is not server', function() {
12 | assert.strictEqual(Meteor.isServer, false);
13 | });
14 | }
15 |
16 | if (Meteor.isServer) {
17 | it('server is not client', function() {
18 | assert.strictEqual(Meteor.isClient, false);
19 | });
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | 0.9.4-platform-file
8 | notices-for-facebook-graph-api-2
9 | 1.2.0-standard-minifiers-package
10 | 1.2.0-meteor-platform-split
11 | 1.2.0-cordova-changes
12 | 1.2.0-breaking-changes
13 | 1.3.0-split-minifiers-package
14 | 1.4.0-remove-old-dev-bundle-link
15 | 1.4.1-add-shell-server-package
16 | 1.4.3-split-account-service-packages
17 | 1.5-add-dynamic-import-package
18 | 1.7-split-underscore-from-meteor-base
19 | 1.8.3-split-jquery-from-blaze
20 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | nlvom1n4rsd.t6xtf6i5fdy
8 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | meteor-base@1.5.1 # Packages every Meteor app needs to have
8 | mobile-experience@1.1.0 # Packages for a great mobile UX
9 | mongo@1.15.0 # The database Meteor supports right now
10 | blaze-html-templates # Compile .html files into Meteor Blaze views
11 | jquery # Wrapper package for npm-installed jquery
12 | reactive-var@1.0.11 # Reactive variable for tracker
13 | tracker@1.2.0 # Meteor's client-side reactive programming library
14 |
15 | standard-minifier-css@1.8.1 # CSS minifier run for production mode
16 | standard-minifier-js@2.8.0 # JS minifier run for production mode
17 | es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers
18 | ecmascript@0.16.2 # Enable ECMAScript2015+ syntax in app code
19 | typescript@4.5.4 # Enable TypeScript syntax in .ts and .tsx modules
20 | shell-server@0.5.0 # Server-side component of the `meteor shell` command
21 |
22 | reactive-dict@1.3.0
23 | accounts-password@2.3.1
24 | hot-module-replacement@0.5.1
25 | blaze-hot
26 | dev-error-overlay@0.1.1
27 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@2.7.2
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/.meteor/versions:
--------------------------------------------------------------------------------
1 | accounts-base@2.2.3
2 | accounts-password@2.3.1
3 | allow-deny@1.1.1
4 | autoupdate@1.8.0
5 | babel-compiler@7.9.0
6 | babel-runtime@1.5.0
7 | base64@1.0.12
8 | binary-heap@1.0.11
9 | blaze@2.6.0
10 | blaze-hot@1.1.1
11 | blaze-html-templates@2.0.0
12 | blaze-tools@1.1.3
13 | boilerplate-generator@1.7.1
14 | caching-compiler@1.2.2
15 | caching-html-compiler@1.2.1
16 | callback-hook@1.4.0
17 | check@1.3.1
18 | ddp@1.4.0
19 | ddp-client@2.5.0
20 | ddp-common@1.4.0
21 | ddp-rate-limiter@1.1.0
22 | ddp-server@2.5.0
23 | dev-error-overlay@0.1.1
24 | diff-sequence@1.1.1
25 | dynamic-import@0.7.2
26 | ecmascript@0.16.2
27 | ecmascript-runtime@0.8.0
28 | ecmascript-runtime-client@0.12.1
29 | ecmascript-runtime-server@0.11.0
30 | ejson@1.1.2
31 | email@2.2.1
32 | es5-shim@4.8.0
33 | fetch@0.1.1
34 | geojson-utils@1.0.10
35 | hot-code-push@1.0.4
36 | hot-module-replacement@0.5.1
37 | html-tools@1.1.3
38 | htmljs@1.1.1
39 | id-map@1.1.1
40 | inter-process-messaging@0.1.1
41 | jquery@3.0.0
42 | launch-screen@1.3.0
43 | localstorage@1.2.0
44 | logging@1.3.1
45 | meteor@1.10.0
46 | meteor-base@1.5.1
47 | minifier-css@1.6.0
48 | minifier-js@2.7.4
49 | minimongo@1.8.0
50 | mobile-experience@1.1.0
51 | mobile-status-bar@1.1.0
52 | modern-browsers@0.1.8
53 | modules@0.18.0
54 | modules-runtime@0.13.0
55 | modules-runtime-hot@0.14.0
56 | mongo@1.15.0
57 | mongo-decimal@0.1.3
58 | mongo-dev-server@1.1.0
59 | mongo-id@1.0.8
60 | npm-mongo@4.3.1
61 | observe-sequence@1.0.20
62 | ordered-dict@1.1.0
63 | promise@0.12.0
64 | random@1.2.0
65 | rate-limit@1.0.9
66 | react-fast-refresh@0.2.3
67 | reactive-dict@1.3.0
68 | reactive-var@1.0.11
69 | reload@1.3.1
70 | retry@1.1.0
71 | routepolicy@1.1.1
72 | service-configuration@1.3.0
73 | sha@1.0.9
74 | shell-server@0.5.0
75 | socket-stream-client@0.5.0
76 | spacebars@1.3.0
77 | spacebars-compiler@1.3.1
78 | standard-minifier-css@1.8.1
79 | standard-minifier-js@2.8.0
80 | templating@1.4.2
81 | templating-compiler@1.4.1
82 | templating-runtime@1.6.0
83 | templating-tools@1.2.2
84 | tracker@1.2.0
85 | typescript@4.5.4
86 | underscore@1.0.10
87 | url@1.3.2
88 | webapp@1.13.1
89 | webapp-hashing@1.1.0
90 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/client/main.html:
--------------------------------------------------------------------------------
1 |
2 | step09
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/client/main.js:
--------------------------------------------------------------------------------
1 | import '../imports/ui/App.js';
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/imports/api/tasksMethods.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { check } from 'meteor/check';
3 | import { TasksCollection } from '../db/TasksCollection';
4 |
5 | Meteor.methods({
6 | 'tasks.insert'(text) {
7 | check(text, String);
8 |
9 | if (!this.userId) {
10 | throw new Meteor.Error('Not authorized.');
11 | }
12 |
13 | TasksCollection.insert({
14 | text,
15 | createdAt: new Date(),
16 | userId: this.userId,
17 | });
18 | },
19 |
20 | 'tasks.remove'(taskId) {
21 | check(taskId, String);
22 |
23 | if (!this.userId) {
24 | throw new Meteor.Error('Not authorized.');
25 | }
26 |
27 | const task = TasksCollection.findOne({ _id: taskId, userId: this.userId });
28 |
29 | if (!task) {
30 | throw new Meteor.Error('Access denied.');
31 | }
32 |
33 | TasksCollection.remove(taskId);
34 | },
35 |
36 | 'tasks.setIsChecked'(taskId, isChecked) {
37 | check(taskId, String);
38 | check(isChecked, Boolean);
39 |
40 | if (!this.userId) {
41 | throw new Meteor.Error('Not authorized.');
42 | }
43 |
44 | const task = TasksCollection.findOne({ _id: taskId, userId: this.userId });
45 |
46 | if (!task) {
47 | throw new Meteor.Error('Access denied.');
48 | }
49 |
50 | TasksCollection.update(taskId, {
51 | $set: {
52 | isChecked,
53 | },
54 | });
55 | },
56 | });
57 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/imports/api/tasksPublications.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { TasksCollection } from '/imports/db/TasksCollection';
3 |
4 | Meteor.publish('tasks', function publishTasks() {
5 | return TasksCollection.find({ userId: this.userId });
6 | });
7 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/imports/db/TasksCollection.js:
--------------------------------------------------------------------------------
1 | import { Mongo } from 'meteor/mongo';
2 |
3 | export const TasksCollection = new Mongo.Collection('tasks');
4 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/imports/ui/App.html:
--------------------------------------------------------------------------------
1 |
2 | {{> mainContainer}}
3 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
17 | {{#if isUserLogged}}
18 |
19 | {{getUser.username}} 🚪
20 |
21 | {{> form }}
22 |
23 |
24 |
25 | {{#if hideCompleted}}
26 | Show All
27 | {{else}}
28 | Hide Completed
29 | {{/if}}
30 |
31 |
32 |
33 | {{#if isLoading}}
34 |
loading...
35 | {{/if}}
36 |
37 |
38 | {{#each tasks}}
39 | {{> task}}
40 | {{/each}}
41 |
42 | {{else}}
43 | {{> login }}
44 | {{/if}}
45 |
46 |
47 |
48 |
49 |
50 |
54 |
55 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/imports/ui/App.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Template } from 'meteor/templating';
3 | import { TasksCollection } from '../db/TasksCollection';
4 | import { Tracker } from 'meteor/tracker';
5 | import { ReactiveDict } from 'meteor/reactive-dict';
6 | import './App.html';
7 | import './Task.js';
8 | import './Login.js';
9 |
10 | const HIDE_COMPLETED_STRING = 'hideCompleted';
11 | const IS_LOADING_STRING = 'isLoading';
12 |
13 | const getUser = () => Meteor.user();
14 | const isUserLogged = () => !!getUser();
15 |
16 | const getTasksFilter = () => {
17 | const user = getUser();
18 |
19 | const hideCompletedFilter = { isChecked: { $ne: true } };
20 |
21 | const userFilter = user ? { userId: user._id } : {};
22 |
23 | const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilter };
24 |
25 | return { userFilter, pendingOnlyFilter };
26 | };
27 |
28 | Template.mainContainer.onCreated(function mainContainerOnCreated() {
29 | this.state = new ReactiveDict();
30 |
31 | const handler = Meteor.subscribe('tasks');
32 | Tracker.autorun(() => {
33 | this.state.set(IS_LOADING_STRING, !handler.ready());
34 | });
35 | });
36 |
37 | Template.mainContainer.events({
38 | 'click #hide-completed-button'(event, instance) {
39 | const currentHideCompleted = instance.state.get(HIDE_COMPLETED_STRING);
40 | instance.state.set(HIDE_COMPLETED_STRING, !currentHideCompleted);
41 | },
42 | 'click .user'() {
43 | Meteor.logout();
44 | },
45 | });
46 |
47 | Template.mainContainer.helpers({
48 | tasks() {
49 | const instance = Template.instance();
50 | const hideCompleted = instance.state.get(HIDE_COMPLETED_STRING);
51 |
52 | const { pendingOnlyFilter, userFilter } = getTasksFilter();
53 |
54 | if (!isUserLogged()) {
55 | return [];
56 | }
57 |
58 | return TasksCollection.find(
59 | hideCompleted ? pendingOnlyFilter : userFilter,
60 | {
61 | sort: { createdAt: -1 },
62 | }
63 | ).fetch();
64 | },
65 | hideCompleted() {
66 | return Template.instance().state.get(HIDE_COMPLETED_STRING);
67 | },
68 | incompleteCount() {
69 | if (!isUserLogged()) {
70 | return '';
71 | }
72 |
73 | const { pendingOnlyFilter } = getTasksFilter();
74 |
75 | const incompleteTasksCount = TasksCollection.find(
76 | pendingOnlyFilter
77 | ).count();
78 | return incompleteTasksCount ? `(${incompleteTasksCount})` : '';
79 | },
80 | isUserLogged() {
81 | return isUserLogged();
82 | },
83 | getUser() {
84 | return getUser();
85 | },
86 | isLoading() {
87 | const instance = Template.instance();
88 | return instance.state.get(IS_LOADING_STRING);
89 | },
90 | });
91 |
92 | Template.form.events({
93 | 'submit .task-form'(event) {
94 | // Prevent default browser form submit
95 | event.preventDefault();
96 |
97 | // Get value from form element
98 | const { target } = event;
99 | const text = target.text.value;
100 |
101 | // Insert a task into the collection
102 | Meteor.call('tasks.insert', text);
103 |
104 | // Clear form
105 | target.text.value = '';
106 | },
107 | });
108 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/imports/ui/Login.html:
--------------------------------------------------------------------------------
1 |
2 |
28 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/imports/ui/Login.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Template } from 'meteor/templating';
3 | import './Login.html';
4 |
5 | Template.login.events({
6 | 'submit .login-form'(event) {
7 | event.preventDefault();
8 |
9 | const { target } = event;
10 |
11 | const username = target.username.value;
12 | const password = target.password.value;
13 |
14 | Meteor.loginWithPassword(username, password);
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/imports/ui/Task.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{text}}
5 | ×
6 |
7 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/imports/ui/Task.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Template } from 'meteor/templating';
3 |
4 | import './Task.html';
5 |
6 | Template.task.events({
7 | 'click .toggle-checked'() {
8 | // Set the checked property to the opposite of its current value
9 | Meteor.call('tasks.setIsChecked', this._id, !this.isChecked);
10 | },
11 | 'click .delete'() {
12 | Meteor.call('tasks.remove', this._id);
13 | },
14 | });
15 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "step01",
3 | "private": true,
4 | "scripts": {
5 | "start": "meteor run",
6 | "test": "meteor test --once --driver-package meteortesting:mocha",
7 | "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
8 | "visualize": "meteor --production --extra-packages bundle-visualizer"
9 | },
10 | "dependencies": {
11 | "@babel/runtime": "^7.15.4",
12 | "bcrypt": "^5.0.1",
13 | "jquery": "^3.6",
14 | "meteor-node-stubs": "^1.2.3"
15 | },
16 | "meteor": {
17 | "mainModule": {
18 | "client": "client/main.js",
19 | "server": "server/main.js"
20 | },
21 | "testModule": "tests/main.js"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/server/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Accounts } from 'meteor/accounts-base';
3 | import { TasksCollection } from '/imports/db/TasksCollection';
4 | import '/imports/api/tasksMethods';
5 | import '/imports/api/tasksPublications';
6 |
7 | const insertTask = (taskText, user) =>
8 | TasksCollection.insert({
9 | text: taskText,
10 | userId: user._id,
11 | createdAt: new Date(),
12 | });
13 |
14 | const SEED_USERNAME = 'meteorite';
15 | const SEED_PASSWORD = 'password';
16 |
17 | Meteor.startup(() => {
18 | if (!Accounts.findUserByUsername(SEED_USERNAME)) {
19 | Accounts.createUser({
20 | username: SEED_USERNAME,
21 | password: SEED_PASSWORD,
22 | });
23 | }
24 |
25 | const user = Accounts.findUserByUsername(SEED_USERNAME);
26 |
27 | if (TasksCollection.find().count() === 0) {
28 | [
29 | 'First Task',
30 | 'Second Task',
31 | 'Third Task',
32 | 'Fourth Task',
33 | 'Fifth Task',
34 | 'Sixth Task',
35 | 'Seventh Task',
36 | ].forEach(taskText => insertTask(taskText, user));
37 | }
38 | });
39 |
--------------------------------------------------------------------------------
/src/simple-todos/step09/tests/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import assert from 'assert';
3 |
4 | describe('step01', function() {
5 | it('package.json has correct name', async function() {
6 | const { name } = await import('../package.json');
7 | assert.strictEqual(name, 'step01');
8 | });
9 |
10 | if (Meteor.isClient) {
11 | it('client is not server', function() {
12 | assert.strictEqual(Meteor.isServer, false);
13 | });
14 | }
15 |
16 | if (Meteor.isServer) {
17 | it('server is not client', function() {
18 | assert.strictEqual(Meteor.isClient, false);
19 | });
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | 0.9.4-platform-file
8 | notices-for-facebook-graph-api-2
9 | 1.2.0-standard-minifiers-package
10 | 1.2.0-meteor-platform-split
11 | 1.2.0-cordova-changes
12 | 1.2.0-breaking-changes
13 | 1.3.0-split-minifiers-package
14 | 1.4.0-remove-old-dev-bundle-link
15 | 1.4.1-add-shell-server-package
16 | 1.4.3-split-account-service-packages
17 | 1.5-add-dynamic-import-package
18 | 1.7-split-underscore-from-meteor-base
19 | 1.8.3-split-jquery-from-blaze
20 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | nlvom1n4rsd.t6xtf6i5fdy
8 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | meteor-base@1.5.1 # Packages every Meteor app needs to have
8 | mobile-experience@1.1.0 # Packages for a great mobile UX
9 | mongo@1.15.0 # The database Meteor supports right now
10 | blaze-html-templates # Compile .html files into Meteor Blaze views
11 | jquery # Wrapper package for npm-installed jquery
12 | reactive-var@1.0.11 # Reactive variable for tracker
13 | tracker@1.2.0 # Meteor's client-side reactive programming library
14 |
15 | standard-minifier-css@1.8.1 # CSS minifier run for production mode
16 | standard-minifier-js@2.8.0 # JS minifier run for production mode
17 | es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers
18 | ecmascript@0.16.2 # Enable ECMAScript2015+ syntax in app code
19 | typescript@4.5.4 # Enable TypeScript syntax in .ts and .tsx modules
20 | shell-server@0.5.0 # Server-side component of the `meteor shell` command
21 |
22 | reactive-dict@1.3.0
23 | accounts-password@2.3.1
24 | hot-module-replacement@0.5.1
25 | blaze-hot
26 | dev-error-overlay@0.1.1
27 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@2.7.2
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/.meteor/versions:
--------------------------------------------------------------------------------
1 | accounts-base@2.2.3
2 | accounts-password@2.3.1
3 | allow-deny@1.1.1
4 | autoupdate@1.8.0
5 | babel-compiler@7.9.0
6 | babel-runtime@1.5.0
7 | base64@1.0.12
8 | binary-heap@1.0.11
9 | blaze@2.6.0
10 | blaze-hot@1.1.1
11 | blaze-html-templates@2.0.0
12 | blaze-tools@1.1.3
13 | boilerplate-generator@1.7.1
14 | caching-compiler@1.2.2
15 | caching-html-compiler@1.2.1
16 | callback-hook@1.4.0
17 | check@1.3.1
18 | ddp@1.4.0
19 | ddp-client@2.5.0
20 | ddp-common@1.4.0
21 | ddp-rate-limiter@1.1.0
22 | ddp-server@2.5.0
23 | dev-error-overlay@0.1.1
24 | diff-sequence@1.1.1
25 | dynamic-import@0.7.2
26 | ecmascript@0.16.2
27 | ecmascript-runtime@0.8.0
28 | ecmascript-runtime-client@0.12.1
29 | ecmascript-runtime-server@0.11.0
30 | ejson@1.1.2
31 | email@2.2.1
32 | es5-shim@4.8.0
33 | fetch@0.1.1
34 | geojson-utils@1.0.10
35 | hot-code-push@1.0.4
36 | hot-module-replacement@0.5.1
37 | html-tools@1.1.3
38 | htmljs@1.1.1
39 | id-map@1.1.1
40 | inter-process-messaging@0.1.1
41 | jquery@3.0.0
42 | launch-screen@1.3.0
43 | localstorage@1.2.0
44 | logging@1.3.1
45 | meteor@1.10.0
46 | meteor-base@1.5.1
47 | minifier-css@1.6.0
48 | minifier-js@2.7.4
49 | minimongo@1.8.0
50 | mobile-experience@1.1.0
51 | mobile-status-bar@1.1.0
52 | modern-browsers@0.1.8
53 | modules@0.18.0
54 | modules-runtime@0.13.0
55 | modules-runtime-hot@0.14.0
56 | mongo@1.15.0
57 | mongo-decimal@0.1.3
58 | mongo-dev-server@1.1.0
59 | mongo-id@1.0.8
60 | npm-mongo@4.3.1
61 | observe-sequence@1.0.20
62 | ordered-dict@1.1.0
63 | promise@0.12.0
64 | random@1.2.0
65 | rate-limit@1.0.9
66 | react-fast-refresh@0.2.3
67 | reactive-dict@1.3.0
68 | reactive-var@1.0.11
69 | reload@1.3.1
70 | retry@1.1.0
71 | routepolicy@1.1.1
72 | service-configuration@1.3.0
73 | sha@1.0.9
74 | shell-server@0.5.0
75 | socket-stream-client@0.5.0
76 | spacebars@1.3.0
77 | spacebars-compiler@1.3.1
78 | standard-minifier-css@1.8.1
79 | standard-minifier-js@2.8.0
80 | templating@1.4.2
81 | templating-compiler@1.4.1
82 | templating-runtime@1.6.0
83 | templating-tools@1.2.2
84 | tracker@1.2.0
85 | typescript@4.5.4
86 | underscore@1.0.10
87 | url@1.3.2
88 | webapp@1.13.1
89 | webapp-hashing@1.1.0
90 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/client/main.html:
--------------------------------------------------------------------------------
1 |
2 | step10
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/client/main.js:
--------------------------------------------------------------------------------
1 | import '../imports/ui/App.js';
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/imports/api/tasksMethods.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { check } from 'meteor/check';
3 | import { TasksCollection } from '../db/TasksCollection';
4 |
5 | Meteor.methods({
6 | 'tasks.insert'(text) {
7 | check(text, String);
8 |
9 | if (!this.userId) {
10 | throw new Meteor.Error('Not authorized.');
11 | }
12 |
13 | TasksCollection.insert({
14 | text,
15 | createdAt: new Date(),
16 | userId: this.userId,
17 | });
18 | },
19 |
20 | 'tasks.remove'(taskId) {
21 | check(taskId, String);
22 |
23 | if (!this.userId) {
24 | throw new Meteor.Error('Not authorized.');
25 | }
26 |
27 | const task = TasksCollection.findOne({ _id: taskId, userId: this.userId });
28 |
29 | if (!task) {
30 | throw new Meteor.Error('Access denied.');
31 | }
32 |
33 | TasksCollection.remove(taskId);
34 | },
35 |
36 | 'tasks.setIsChecked'(taskId, isChecked) {
37 | check(taskId, String);
38 | check(isChecked, Boolean);
39 |
40 | if (!this.userId) {
41 | throw new Meteor.Error('Not authorized.');
42 | }
43 |
44 | const task = TasksCollection.findOne({ _id: taskId, userId: this.userId });
45 |
46 | if (!task) {
47 | throw new Meteor.Error('Access denied.');
48 | }
49 |
50 | TasksCollection.update(taskId, {
51 | $set: {
52 | isChecked,
53 | },
54 | });
55 | },
56 | });
57 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/imports/api/tasksPublications.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { TasksCollection } from '/imports/db/TasksCollection';
3 |
4 | Meteor.publish('tasks', function publishTasks() {
5 | return TasksCollection.find({ userId: this.userId });
6 | });
7 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/imports/db/TasksCollection.js:
--------------------------------------------------------------------------------
1 | import { Mongo } from 'meteor/mongo';
2 |
3 | export const TasksCollection = new Mongo.Collection('tasks');
4 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/imports/ui/App.html:
--------------------------------------------------------------------------------
1 |
2 | {{> mainContainer}}
3 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
17 | {{#if isUserLogged}}
18 |
19 | {{getUser.username}} 🚪
20 |
21 | {{> form }}
22 |
23 |
24 |
25 | {{#if hideCompleted}}
26 | Show All
27 | {{else}}
28 | Hide Completed
29 | {{/if}}
30 |
31 |
32 |
33 | {{#if isLoading}}
34 |
loading...
35 | {{/if}}
36 |
37 |
38 | {{#each tasks}}
39 | {{> task}}
40 | {{/each}}
41 |
42 | {{else}}
43 | {{> login }}
44 | {{/if}}
45 |
46 |
47 |
48 |
49 |
50 |
54 |
55 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/imports/ui/App.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Template } from 'meteor/templating';
3 | import { TasksCollection } from '../db/TasksCollection';
4 | import { Tracker } from 'meteor/tracker';
5 | import { ReactiveDict } from 'meteor/reactive-dict';
6 | import './App.html';
7 | import './Task.js';
8 | import './Login.js';
9 |
10 | const HIDE_COMPLETED_STRING = 'hideCompleted';
11 | const IS_LOADING_STRING = 'isLoading';
12 |
13 | const getUser = () => Meteor.user();
14 | const isUserLogged = () => !!getUser();
15 |
16 | const getTasksFilter = () => {
17 | const user = getUser();
18 |
19 | const hideCompletedFilter = { isChecked: { $ne: true } };
20 |
21 | const userFilter = user ? { userId: user._id } : {};
22 |
23 | const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilter };
24 |
25 | return { userFilter, pendingOnlyFilter };
26 | };
27 |
28 | Template.mainContainer.onCreated(function mainContainerOnCreated() {
29 | this.state = new ReactiveDict();
30 |
31 | const handler = Meteor.subscribe('tasks');
32 | Tracker.autorun(() => {
33 | this.state.set(IS_LOADING_STRING, !handler.ready());
34 | });
35 | });
36 |
37 | Template.mainContainer.events({
38 | 'click #hide-completed-button'(event, instance) {
39 | const currentHideCompleted = instance.state.get(HIDE_COMPLETED_STRING);
40 | instance.state.set(HIDE_COMPLETED_STRING, !currentHideCompleted);
41 | },
42 | 'click .user'() {
43 | Meteor.logout();
44 | },
45 | });
46 |
47 | Template.mainContainer.helpers({
48 | tasks() {
49 | const instance = Template.instance();
50 | const hideCompleted = instance.state.get(HIDE_COMPLETED_STRING);
51 |
52 | const { pendingOnlyFilter, userFilter } = getTasksFilter();
53 |
54 | if (!isUserLogged()) {
55 | return [];
56 | }
57 |
58 | return TasksCollection.find(
59 | hideCompleted ? pendingOnlyFilter : userFilter,
60 | {
61 | sort: { createdAt: -1 },
62 | }
63 | ).fetch();
64 | },
65 | hideCompleted() {
66 | return Template.instance().state.get(HIDE_COMPLETED_STRING);
67 | },
68 | incompleteCount() {
69 | if (!isUserLogged()) {
70 | return '';
71 | }
72 |
73 | const { pendingOnlyFilter } = getTasksFilter();
74 |
75 | const incompleteTasksCount = TasksCollection.find(
76 | pendingOnlyFilter
77 | ).count();
78 | return incompleteTasksCount ? `(${incompleteTasksCount})` : '';
79 | },
80 | isUserLogged() {
81 | return isUserLogged();
82 | },
83 | getUser() {
84 | return getUser();
85 | },
86 | isLoading() {
87 | const instance = Template.instance();
88 | return instance.state.get(IS_LOADING_STRING);
89 | },
90 | });
91 |
92 | Template.form.events({
93 | 'submit .task-form'(event) {
94 | // Prevent default browser form submit
95 | event.preventDefault();
96 |
97 | // Get value from form element
98 | const { target } = event;
99 | const text = target.text.value;
100 |
101 | // Insert a task into the collection
102 | Meteor.call('tasks.insert', text);
103 |
104 | // Clear form
105 | target.text.value = '';
106 | },
107 | });
108 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/imports/ui/Login.html:
--------------------------------------------------------------------------------
1 |
2 |
28 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/imports/ui/Login.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Template } from 'meteor/templating';
3 | import './Login.html';
4 |
5 | Template.login.events({
6 | 'submit .login-form'(event) {
7 | event.preventDefault();
8 |
9 | const { target } = event;
10 |
11 | const username = target.username.value;
12 | const password = target.password.value;
13 |
14 | Meteor.loginWithPassword(username, password);
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/imports/ui/Task.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{text}}
5 | ×
6 |
7 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/imports/ui/Task.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Template } from 'meteor/templating';
3 |
4 | import './Task.html';
5 |
6 | Template.task.events({
7 | 'click .toggle-checked'() {
8 | // Set the checked property to the opposite of its current value
9 | Meteor.call('tasks.setIsChecked', this._id, !this.isChecked);
10 | },
11 | 'click .delete'() {
12 | Meteor.call('tasks.remove', this._id);
13 | },
14 | });
15 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "step01",
3 | "private": true,
4 | "scripts": {
5 | "start": "meteor run",
6 | "test": "meteor test --once --driver-package meteortesting:mocha",
7 | "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
8 | "visualize": "meteor --production --extra-packages bundle-visualizer"
9 | },
10 | "dependencies": {
11 | "@babel/runtime": "^7.15.4",
12 | "bcrypt": "^5.0.1",
13 | "jquery": "^3.6",
14 | "meteor-node-stubs": "^1.2.3"
15 | },
16 | "meteor": {
17 | "mainModule": {
18 | "client": "client/main.js",
19 | "server": "server/main.js"
20 | },
21 | "testModule": "tests/main.js"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/server/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Accounts } from 'meteor/accounts-base';
3 | import { TasksCollection } from '/imports/db/TasksCollection';
4 | import '/imports/api/tasksMethods';
5 | import '/imports/api/tasksPublications';
6 |
7 | const insertTask = (taskText, user) =>
8 | TasksCollection.insert({
9 | text: taskText,
10 | userId: user._id,
11 | createdAt: new Date(),
12 | });
13 |
14 | const SEED_USERNAME = 'meteorite';
15 | const SEED_PASSWORD = 'password';
16 |
17 | Meteor.startup(() => {
18 | if (!Accounts.findUserByUsername(SEED_USERNAME)) {
19 | Accounts.createUser({
20 | username: SEED_USERNAME,
21 | password: SEED_PASSWORD,
22 | });
23 | }
24 |
25 | const user = Accounts.findUserByUsername(SEED_USERNAME);
26 |
27 | if (TasksCollection.find().count() === 0) {
28 | [
29 | 'First Task',
30 | 'Second Task',
31 | 'Third Task',
32 | 'Fourth Task',
33 | 'Fifth Task',
34 | 'Sixth Task',
35 | 'Seventh Task',
36 | ].forEach(taskText => insertTask(taskText, user));
37 | }
38 | });
39 |
--------------------------------------------------------------------------------
/src/simple-todos/step10/tests/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import assert from 'assert';
3 |
4 | describe('step01', function() {
5 | it('package.json has correct name', async function() {
6 | const { name } = await import('../package.json');
7 | assert.strictEqual(name, 'step01');
8 | });
9 |
10 | if (Meteor.isClient) {
11 | it('client is not server', function() {
12 | assert.strictEqual(Meteor.isServer, false);
13 | });
14 | }
15 |
16 | if (Meteor.isServer) {
17 | it('server is not client', function() {
18 | assert.strictEqual(Meteor.isClient, false);
19 | });
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | 0.9.4-platform-file
8 | notices-for-facebook-graph-api-2
9 | 1.2.0-standard-minifiers-package
10 | 1.2.0-meteor-platform-split
11 | 1.2.0-cordova-changes
12 | 1.2.0-breaking-changes
13 | 1.3.0-split-minifiers-package
14 | 1.4.0-remove-old-dev-bundle-link
15 | 1.4.1-add-shell-server-package
16 | 1.4.3-split-account-service-packages
17 | 1.5-add-dynamic-import-package
18 | 1.7-split-underscore-from-meteor-base
19 | 1.8.3-split-jquery-from-blaze
20 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | nlvom1n4rsd.t6xtf6i5fdy
8 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | meteor-base@1.5.1 # Packages every Meteor app needs to have
8 | mobile-experience@1.1.0 # Packages for a great mobile UX
9 | mongo@1.15.0 # The database Meteor supports right now
10 | blaze-html-templates # Compile .html files into Meteor Blaze views
11 | jquery # Wrapper package for npm-installed jquery
12 | reactive-var@1.0.11 # Reactive variable for tracker
13 | tracker@1.2.0 # Meteor's client-side reactive programming library
14 |
15 | standard-minifier-css@1.8.1 # CSS minifier run for production mode
16 | standard-minifier-js@2.8.0 # JS minifier run for production mode
17 | es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers
18 | ecmascript@0.16.2 # Enable ECMAScript2015+ syntax in app code
19 | typescript@4.5.4 # Enable TypeScript syntax in .ts and .tsx modules
20 | shell-server@0.5.0 # Server-side component of the `meteor shell` command
21 |
22 | reactive-dict@1.3.0
23 | accounts-password@2.3.1
24 | meteortesting:mocha
25 | quave:testing
26 | hot-module-replacement@0.5.1
27 | blaze-hot
28 | dev-error-overlay@0.1.1
29 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@2.7.2
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/.meteor/versions:
--------------------------------------------------------------------------------
1 | accounts-base@2.2.3
2 | accounts-password@2.3.1
3 | allow-deny@1.1.1
4 | autoupdate@1.8.0
5 | babel-compiler@7.9.0
6 | babel-runtime@1.5.0
7 | base64@1.0.12
8 | binary-heap@1.0.11
9 | blaze@2.6.0
10 | blaze-hot@1.1.1
11 | blaze-html-templates@2.0.0
12 | blaze-tools@1.1.3
13 | boilerplate-generator@1.7.1
14 | caching-compiler@1.2.2
15 | caching-html-compiler@1.2.1
16 | callback-hook@1.4.0
17 | check@1.3.1
18 | ddp@1.4.0
19 | ddp-client@2.5.0
20 | ddp-common@1.4.0
21 | ddp-rate-limiter@1.1.0
22 | ddp-server@2.5.0
23 | dev-error-overlay@0.1.1
24 | diff-sequence@1.1.1
25 | dynamic-import@0.7.2
26 | ecmascript@0.16.2
27 | ecmascript-runtime@0.8.0
28 | ecmascript-runtime-client@0.12.1
29 | ecmascript-runtime-server@0.11.0
30 | ejson@1.1.2
31 | email@2.2.1
32 | es5-shim@4.8.0
33 | fetch@0.1.1
34 | geojson-utils@1.0.10
35 | hot-code-push@1.0.4
36 | hot-module-replacement@0.5.1
37 | html-tools@1.1.3
38 | htmljs@1.1.1
39 | http@2.0.0
40 | id-map@1.1.1
41 | inter-process-messaging@0.1.1
42 | jquery@3.0.0
43 | launch-screen@1.3.0
44 | localstorage@1.2.0
45 | logging@1.3.1
46 | meteor@1.10.0
47 | meteor-base@1.5.1
48 | meteortesting:browser-tests@1.3.5
49 | meteortesting:mocha@2.0.3
50 | meteortesting:mocha-core@8.1.2
51 | minifier-css@1.6.0
52 | minifier-js@2.7.4
53 | minimongo@1.8.0
54 | mobile-experience@1.1.0
55 | mobile-status-bar@1.1.0
56 | modern-browsers@0.1.8
57 | modules@0.18.0
58 | modules-runtime@0.13.0
59 | modules-runtime-hot@0.14.0
60 | mongo@1.15.0
61 | mongo-decimal@0.1.3
62 | mongo-dev-server@1.1.0
63 | mongo-id@1.0.8
64 | npm-mongo@4.3.1
65 | observe-sequence@1.0.20
66 | ordered-dict@1.1.0
67 | promise@0.12.0
68 | quave:testing@1.0.1
69 | random@1.2.0
70 | rate-limit@1.0.9
71 | react-fast-refresh@0.2.3
72 | reactive-dict@1.3.0
73 | reactive-var@1.0.11
74 | reload@1.3.1
75 | retry@1.1.0
76 | routepolicy@1.1.1
77 | service-configuration@1.3.0
78 | sha@1.0.9
79 | shell-server@0.5.0
80 | socket-stream-client@0.5.0
81 | spacebars@1.3.0
82 | spacebars-compiler@1.3.1
83 | standard-minifier-css@1.8.1
84 | standard-minifier-js@2.8.0
85 | templating@1.4.2
86 | templating-compiler@1.4.1
87 | templating-runtime@1.6.0
88 | templating-tools@1.2.2
89 | tracker@1.2.0
90 | typescript@4.5.4
91 | underscore@1.0.10
92 | url@1.3.2
93 | webapp@1.13.1
94 | webapp-hashing@1.1.0
95 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/client/main.html:
--------------------------------------------------------------------------------
1 |
2 | step11
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/client/main.js:
--------------------------------------------------------------------------------
1 | import '../imports/ui/App.js';
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/imports/api/tasksMethods.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { check } from 'meteor/check';
3 | import { TasksCollection } from '../db/TasksCollection';
4 |
5 | Meteor.methods({
6 | 'tasks.insert'(text) {
7 | check(text, String);
8 |
9 | if (!this.userId) {
10 | throw new Meteor.Error('Not authorized.');
11 | }
12 |
13 | TasksCollection.insert({
14 | text,
15 | createdAt: new Date(),
16 | userId: this.userId,
17 | });
18 | },
19 |
20 | 'tasks.remove'(taskId) {
21 | check(taskId, String);
22 |
23 | if (!this.userId) {
24 | throw new Meteor.Error('Not authorized.');
25 | }
26 |
27 | const task = TasksCollection.findOne({ _id: taskId, userId: this.userId });
28 |
29 | if (!task) {
30 | throw new Meteor.Error('Access denied.');
31 | }
32 |
33 | TasksCollection.remove(taskId);
34 | },
35 |
36 | 'tasks.setIsChecked'(taskId, isChecked) {
37 | check(taskId, String);
38 | check(isChecked, Boolean);
39 |
40 | if (!this.userId) {
41 | throw new Meteor.Error('Not authorized.');
42 | }
43 |
44 | const task = TasksCollection.findOne({ _id: taskId, userId: this.userId });
45 |
46 | if (!task) {
47 | throw new Meteor.Error('Access denied.');
48 | }
49 |
50 | TasksCollection.update(taskId, {
51 | $set: {
52 | isChecked,
53 | },
54 | });
55 | },
56 | });
57 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/imports/api/tasksMethods.tests.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Random } from 'meteor/random';
3 | import { mockMethodCall } from 'meteor/quave:testing';
4 | import { assert } from 'chai';
5 | import { TasksCollection } from '/imports/db/TasksCollection';
6 | import '/imports/api/tasksMethods';
7 |
8 | if (Meteor.isServer) {
9 | describe('Tasks', () => {
10 | describe('methods', () => {
11 | const userId = Random.id();
12 | let taskId;
13 |
14 | beforeEach(() => {
15 | TasksCollection.remove({});
16 | taskId = TasksCollection.insert({
17 | text: 'Test Task',
18 | createdAt: new Date(),
19 | userId,
20 | });
21 | });
22 |
23 | it('can delete owned task', () => {
24 | mockMethodCall('tasks.remove', taskId, { context: { userId } });
25 |
26 | assert.equal(TasksCollection.find().count(), 0);
27 | });
28 |
29 | it("can't delete task without an user authenticated", () => {
30 | const fn = () => mockMethodCall('tasks.remove', taskId);
31 | assert.throw(fn, /Not authorized/);
32 | assert.equal(TasksCollection.find().count(), 1);
33 | });
34 |
35 | it("can't delete task from another owner", () => {
36 | const fn = () =>
37 | mockMethodCall('tasks.remove', taskId, {
38 | context: { userId: 'somebody-else-id' },
39 | });
40 | assert.throw(fn, /Access denied/);
41 | assert.equal(TasksCollection.find().count(), 1);
42 | });
43 |
44 | it('can change the status of a task', () => {
45 | const originalTask = TasksCollection.findOne(taskId);
46 | mockMethodCall('tasks.setIsChecked', taskId, !originalTask.isChecked, {
47 | context: { userId },
48 | });
49 |
50 | const updatedTask = TasksCollection.findOne(taskId);
51 | assert.notEqual(updatedTask.isChecked, originalTask.isChecked);
52 | });
53 |
54 | it('can insert new tasks', () => {
55 | const text = 'New Task';
56 | mockMethodCall('tasks.insert', text, {
57 | context: { userId },
58 | });
59 |
60 | const tasks = TasksCollection.find({}).fetch();
61 | assert.equal(tasks.length, 2);
62 | assert.isTrue(tasks.some(task => task.text === text));
63 | });
64 | });
65 | });
66 | }
67 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/imports/api/tasksPublications.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { TasksCollection } from '/imports/db/TasksCollection';
3 |
4 | Meteor.publish('tasks', function publishTasks() {
5 | return TasksCollection.find({ userId: this.userId });
6 | });
7 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/imports/db/TasksCollection.js:
--------------------------------------------------------------------------------
1 | import { Mongo } from 'meteor/mongo';
2 |
3 | export const TasksCollection = new Mongo.Collection('tasks');
4 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/imports/ui/App.html:
--------------------------------------------------------------------------------
1 |
2 | {{> mainContainer}}
3 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
17 | {{#if isUserLogged}}
18 |
19 | {{getUser.username}} 🚪
20 |
21 | {{> form }}
22 |
23 |
24 |
25 | {{#if hideCompleted}}
26 | Show All
27 | {{else}}
28 | Hide Completed
29 | {{/if}}
30 |
31 |
32 |
33 | {{#if isLoading}}
34 |
loading...
35 | {{/if}}
36 |
37 |
38 | {{#each tasks}}
39 | {{> task}}
40 | {{/each}}
41 |
42 | {{else}}
43 | {{> login }}
44 | {{/if}}
45 |
46 |
47 |
48 |
49 |
50 |
54 |
55 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/imports/ui/Login.html:
--------------------------------------------------------------------------------
1 |
2 |
28 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/imports/ui/Login.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Template } from 'meteor/templating';
3 | import './Login.html';
4 |
5 | Template.login.events({
6 | 'submit .login-form'(event) {
7 | event.preventDefault();
8 |
9 | const { target } = event;
10 |
11 | const username = target.username.value;
12 | const password = target.password.value;
13 |
14 | Meteor.loginWithPassword(username, password);
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/imports/ui/Task.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{text}}
5 | ×
6 |
7 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/imports/ui/Task.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Template } from 'meteor/templating';
3 |
4 | import './Task.html';
5 |
6 | Template.task.events({
7 | 'click .toggle-checked'() {
8 | // Set the checked property to the opposite of its current value
9 | Meteor.call('tasks.setIsChecked', this._id, !this.isChecked);
10 | },
11 | 'click .delete'() {
12 | Meteor.call('tasks.remove', this._id);
13 | },
14 | });
15 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "step01",
3 | "private": true,
4 | "scripts": {
5 | "start": "meteor run",
6 | "test": "meteor test --once --driver-package meteortesting:mocha",
7 | "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
8 | "visualize": "meteor --production --extra-packages bundle-visualizer"
9 | },
10 | "dependencies": {
11 | "@babel/runtime": "^7.15.4",
12 | "bcrypt": "^5.0.1",
13 | "jquery": "^3.6",
14 | "meteor-node-stubs": "^1.2.3"
15 | },
16 | "meteor": {
17 | "mainModule": {
18 | "client": "client/main.js",
19 | "server": "server/main.js"
20 | },
21 | "testModule": "tests/main.js"
22 | },
23 | "devDependencies": {
24 | "chai": "^4.3.4"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/server/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Accounts } from 'meteor/accounts-base';
3 | import { TasksCollection } from '/imports/db/TasksCollection';
4 | import '/imports/api/tasksMethods';
5 | import '/imports/api/tasksPublications';
6 |
7 | const insertTask = (taskText, user) =>
8 | TasksCollection.insert({
9 | text: taskText,
10 | userId: user._id,
11 | createdAt: new Date(),
12 | });
13 |
14 | const SEED_USERNAME = 'meteorite';
15 | const SEED_PASSWORD = 'password';
16 |
17 | Meteor.startup(() => {
18 | if (!Accounts.findUserByUsername(SEED_USERNAME)) {
19 | Accounts.createUser({
20 | username: SEED_USERNAME,
21 | password: SEED_PASSWORD,
22 | });
23 | }
24 |
25 | const user = Accounts.findUserByUsername(SEED_USERNAME);
26 |
27 | if (TasksCollection.find().count() === 0) {
28 | [
29 | 'First Task',
30 | 'Second Task',
31 | 'Third Task',
32 | 'Fourth Task',
33 | 'Fifth Task',
34 | 'Sixth Task',
35 | 'Seventh Task',
36 | ].forEach(taskText => insertTask(taskText, user));
37 | }
38 | });
39 |
--------------------------------------------------------------------------------
/src/simple-todos/step11/tests/main.js:
--------------------------------------------------------------------------------
1 | import '/imports/api/tasksMethods.tests.js';
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | 0.9.4-platform-file
8 | notices-for-facebook-graph-api-2
9 | 1.2.0-standard-minifiers-package
10 | 1.2.0-meteor-platform-split
11 | 1.2.0-cordova-changes
12 | 1.2.0-breaking-changes
13 | 1.3.0-split-minifiers-package
14 | 1.4.0-remove-old-dev-bundle-link
15 | 1.4.1-add-shell-server-package
16 | 1.4.3-split-account-service-packages
17 | 1.5-add-dynamic-import-package
18 | 1.7-split-underscore-from-meteor-base
19 | 1.8.3-split-jquery-from-blaze
20 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | nlvom1n4rsd.t6xtf6i5fdy
8 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | meteor-base@1.5.1 # Packages every Meteor app needs to have
8 | mobile-experience@1.1.0 # Packages for a great mobile UX
9 | mongo@1.15.0 # The database Meteor supports right now
10 | blaze-html-templates # Compile .html files into Meteor Blaze views
11 | jquery # Wrapper package for npm-installed jquery
12 | reactive-var@1.0.11 # Reactive variable for tracker
13 | tracker@1.2.0 # Meteor's client-side reactive programming library
14 |
15 | standard-minifier-css@1.8.1 # CSS minifier run for production mode
16 | standard-minifier-js@2.8.0 # JS minifier run for production mode
17 | es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers
18 | ecmascript@0.16.2 # Enable ECMAScript2015+ syntax in app code
19 | typescript@4.5.4 # Enable TypeScript syntax in .ts and .tsx modules
20 | shell-server@0.5.0 # Server-side component of the `meteor shell` command
21 |
22 | reactive-dict@1.3.0
23 | accounts-password@2.3.1
24 | meteortesting:mocha
25 | quave:testing
26 | hot-module-replacement@0.5.1
27 | blaze-hot
28 | dev-error-overlay@0.1.1
29 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@2.7.2
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/.meteor/versions:
--------------------------------------------------------------------------------
1 | accounts-base@2.2.3
2 | accounts-password@2.3.1
3 | allow-deny@1.1.1
4 | autoupdate@1.8.0
5 | babel-compiler@7.9.0
6 | babel-runtime@1.5.0
7 | base64@1.0.12
8 | binary-heap@1.0.11
9 | blaze@2.6.0
10 | blaze-hot@1.1.1
11 | blaze-html-templates@2.0.0
12 | blaze-tools@1.1.3
13 | boilerplate-generator@1.7.1
14 | caching-compiler@1.2.2
15 | caching-html-compiler@1.2.1
16 | callback-hook@1.4.0
17 | check@1.3.1
18 | ddp@1.4.0
19 | ddp-client@2.5.0
20 | ddp-common@1.4.0
21 | ddp-rate-limiter@1.1.0
22 | ddp-server@2.5.0
23 | dev-error-overlay@0.1.1
24 | diff-sequence@1.1.1
25 | dynamic-import@0.7.2
26 | ecmascript@0.16.2
27 | ecmascript-runtime@0.8.0
28 | ecmascript-runtime-client@0.12.1
29 | ecmascript-runtime-server@0.11.0
30 | ejson@1.1.2
31 | email@2.2.1
32 | es5-shim@4.8.0
33 | fetch@0.1.1
34 | geojson-utils@1.0.10
35 | hot-code-push@1.0.4
36 | hot-module-replacement@0.5.1
37 | html-tools@1.1.3
38 | htmljs@1.1.1
39 | http@2.0.0
40 | id-map@1.1.1
41 | inter-process-messaging@0.1.1
42 | jquery@3.0.0
43 | launch-screen@1.3.0
44 | localstorage@1.2.0
45 | logging@1.3.1
46 | meteor@1.10.0
47 | meteor-base@1.5.1
48 | meteortesting:browser-tests@1.3.5
49 | meteortesting:mocha@2.0.3
50 | meteortesting:mocha-core@8.1.2
51 | minifier-css@1.6.0
52 | minifier-js@2.7.4
53 | minimongo@1.8.0
54 | mobile-experience@1.1.0
55 | mobile-status-bar@1.1.0
56 | modern-browsers@0.1.8
57 | modules@0.18.0
58 | modules-runtime@0.13.0
59 | modules-runtime-hot@0.14.0
60 | mongo@1.15.0
61 | mongo-decimal@0.1.3
62 | mongo-dev-server@1.1.0
63 | mongo-id@1.0.8
64 | npm-mongo@4.3.1
65 | observe-sequence@1.0.20
66 | ordered-dict@1.1.0
67 | promise@0.12.0
68 | quave:testing@1.0.1
69 | random@1.2.0
70 | rate-limit@1.0.9
71 | react-fast-refresh@0.2.3
72 | reactive-dict@1.3.0
73 | reactive-var@1.0.11
74 | reload@1.3.1
75 | retry@1.1.0
76 | routepolicy@1.1.1
77 | service-configuration@1.3.0
78 | sha@1.0.9
79 | shell-server@0.5.0
80 | socket-stream-client@0.5.0
81 | spacebars@1.3.0
82 | spacebars-compiler@1.3.1
83 | standard-minifier-css@1.8.1
84 | standard-minifier-js@2.8.0
85 | templating@1.4.2
86 | templating-compiler@1.4.1
87 | templating-runtime@1.6.0
88 | templating-tools@1.2.2
89 | tracker@1.2.0
90 | typescript@4.5.4
91 | underscore@1.0.10
92 | url@1.3.2
93 | webapp@1.13.1
94 | webapp-hashing@1.1.0
95 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/client/main.html:
--------------------------------------------------------------------------------
1 |
2 | step12
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/client/main.js:
--------------------------------------------------------------------------------
1 | import '../imports/ui/App.js';
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/imports/api/tasksMethods.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { check } from 'meteor/check';
3 | import { TasksCollection } from '../db/TasksCollection';
4 |
5 | Meteor.methods({
6 | 'tasks.insert'(text) {
7 | check(text, String);
8 |
9 | if (!this.userId) {
10 | throw new Meteor.Error('Not authorized.');
11 | }
12 |
13 | TasksCollection.insert({
14 | text,
15 | createdAt: new Date(),
16 | userId: this.userId,
17 | });
18 | },
19 |
20 | 'tasks.remove'(taskId) {
21 | check(taskId, String);
22 |
23 | if (!this.userId) {
24 | throw new Meteor.Error('Not authorized.');
25 | }
26 |
27 | const task = TasksCollection.findOne({ _id: taskId, userId: this.userId });
28 |
29 | if (!task) {
30 | throw new Meteor.Error('Access denied.');
31 | }
32 |
33 | TasksCollection.remove(taskId);
34 | },
35 |
36 | 'tasks.setIsChecked'(taskId, isChecked) {
37 | check(taskId, String);
38 | check(isChecked, Boolean);
39 |
40 | if (!this.userId) {
41 | throw new Meteor.Error('Not authorized.');
42 | }
43 |
44 | const task = TasksCollection.findOne({ _id: taskId, userId: this.userId });
45 |
46 | if (!task) {
47 | throw new Meteor.Error('Access denied.');
48 | }
49 |
50 | TasksCollection.update(taskId, {
51 | $set: {
52 | isChecked,
53 | },
54 | });
55 | },
56 | });
57 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/imports/api/tasksMethods.tests.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Random } from 'meteor/random';
3 | import { mockMethodCall } from 'meteor/quave:testing';
4 | import { assert } from 'chai';
5 | import { TasksCollection } from '/imports/db/TasksCollection';
6 | import '/imports/api/tasksMethods';
7 |
8 | if (Meteor.isServer) {
9 | describe('Tasks', () => {
10 | describe('methods', () => {
11 | const userId = Random.id();
12 | let taskId;
13 |
14 | beforeEach(() => {
15 | TasksCollection.remove({});
16 | taskId = TasksCollection.insert({
17 | text: 'Test Task',
18 | createdAt: new Date(),
19 | userId,
20 | });
21 | });
22 |
23 | it('can delete owned task', () => {
24 | mockMethodCall('tasks.remove', taskId, { context: { userId } });
25 |
26 | assert.equal(TasksCollection.find().count(), 0);
27 | });
28 |
29 | it("can't delete task without an user authenticated", () => {
30 | const fn = () => mockMethodCall('tasks.remove', taskId);
31 | assert.throw(fn, /Not authorized/);
32 | assert.equal(TasksCollection.find().count(), 1);
33 | });
34 |
35 | it("can't delete task from another owner", () => {
36 | const fn = () =>
37 | mockMethodCall('tasks.remove', taskId, {
38 | context: { userId: 'somebody-else-id' },
39 | });
40 | assert.throw(fn, /Access denied/);
41 | assert.equal(TasksCollection.find().count(), 1);
42 | });
43 |
44 | it('can change the status of a task', () => {
45 | const originalTask = TasksCollection.findOne(taskId);
46 | mockMethodCall('tasks.setIsChecked', taskId, !originalTask.isChecked, {
47 | context: { userId },
48 | });
49 |
50 | const updatedTask = TasksCollection.findOne(taskId);
51 | assert.notEqual(updatedTask.isChecked, originalTask.isChecked);
52 | });
53 |
54 | it('can insert new tasks', () => {
55 | const text = 'New Task';
56 | mockMethodCall('tasks.insert', text, {
57 | context: { userId },
58 | });
59 |
60 | const tasks = TasksCollection.find({}).fetch();
61 | assert.equal(tasks.length, 2);
62 | assert.isTrue(tasks.some(task => task.text === text));
63 | });
64 | });
65 | });
66 | }
67 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/imports/api/tasksPublications.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { TasksCollection } from '/imports/db/TasksCollection';
3 |
4 | Meteor.publish('tasks', function publishTasks() {
5 | return TasksCollection.find({ userId: this.userId });
6 | });
7 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/imports/db/TasksCollection.js:
--------------------------------------------------------------------------------
1 | import { Mongo } from 'meteor/mongo';
2 |
3 | export const TasksCollection = new Mongo.Collection('tasks');
4 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/imports/ui/App.html:
--------------------------------------------------------------------------------
1 |
2 | {{> mainContainer}}
3 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
17 | {{#if isUserLogged}}
18 |
19 | {{getUser.username}} 🚪
20 |
21 | {{> form }}
22 |
23 |
24 |
25 | {{#if hideCompleted}}
26 | Show All
27 | {{else}}
28 | Hide Completed
29 | {{/if}}
30 |
31 |
32 |
33 | {{#if isLoading}}
34 |
loading...
35 | {{/if}}
36 |
37 |
38 | {{#each tasks}}
39 | {{> task}}
40 | {{/each}}
41 |
42 | {{else}}
43 | {{> login }}
44 | {{/if}}
45 |
46 |
47 |
48 |
49 |
50 |
54 |
55 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/imports/ui/Login.html:
--------------------------------------------------------------------------------
1 |
2 |
28 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/imports/ui/Login.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Template } from 'meteor/templating';
3 | import './Login.html';
4 |
5 | Template.login.events({
6 | 'submit .login-form'(event) {
7 | event.preventDefault();
8 |
9 | const { target } = event;
10 |
11 | const username = target.username.value;
12 | const password = target.password.value;
13 |
14 | Meteor.loginWithPassword(username, password);
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/imports/ui/Task.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{text}}
5 | ×
6 |
7 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/imports/ui/Task.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Template } from 'meteor/templating';
3 |
4 | import './Task.html';
5 |
6 | Template.task.events({
7 | 'click .toggle-checked'() {
8 | // Set the checked property to the opposite of its current value
9 | Meteor.call('tasks.setIsChecked', this._id, !this.isChecked);
10 | },
11 | 'click .delete'() {
12 | Meteor.call('tasks.remove', this._id);
13 | },
14 | });
15 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "step01",
3 | "private": true,
4 | "scripts": {
5 | "start": "meteor run",
6 | "test": "meteor test --once --driver-package meteortesting:mocha",
7 | "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
8 | "visualize": "meteor --production --extra-packages bundle-visualizer"
9 | },
10 | "dependencies": {
11 | "@babel/runtime": "^7.15.4",
12 | "bcrypt": "^5.0.1",
13 | "jquery": "^3.6",
14 | "meteor-node-stubs": "^1.2.3"
15 | },
16 | "meteor": {
17 | "mainModule": {
18 | "client": "client/main.js",
19 | "server": "server/main.js"
20 | },
21 | "testModule": "tests/main.js"
22 | },
23 | "devDependencies": {
24 | "chai": "^4.3.4"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/server/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Accounts } from 'meteor/accounts-base';
3 | import { TasksCollection } from '/imports/db/TasksCollection';
4 | import '/imports/api/tasksMethods';
5 | import '/imports/api/tasksPublications';
6 |
7 | const insertTask = (taskText, user) =>
8 | TasksCollection.insert({
9 | text: taskText,
10 | userId: user._id,
11 | createdAt: new Date(),
12 | });
13 |
14 | const SEED_USERNAME = 'meteorite';
15 | const SEED_PASSWORD = 'password';
16 |
17 | Meteor.startup(() => {
18 | if (!Accounts.findUserByUsername(SEED_USERNAME)) {
19 | Accounts.createUser({
20 | username: SEED_USERNAME,
21 | password: SEED_PASSWORD,
22 | });
23 | }
24 |
25 | const user = Accounts.findUserByUsername(SEED_USERNAME);
26 |
27 | if (TasksCollection.find().count() === 0) {
28 | [
29 | 'First Task',
30 | 'Second Task',
31 | 'Third Task',
32 | 'Fourth Task',
33 | 'Fifth Task',
34 | 'Sixth Task',
35 | 'Seventh Task',
36 | ].forEach(taskText => insertTask(taskText, user));
37 | }
38 | });
39 |
--------------------------------------------------------------------------------
/src/simple-todos/step12/tests/main.js:
--------------------------------------------------------------------------------
1 | import '/imports/api/tasksMethods.tests.js';
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | 0.9.4-platform-file
8 | notices-for-facebook-graph-api-2
9 | 1.2.0-standard-minifiers-package
10 | 1.2.0-meteor-platform-split
11 | 1.2.0-cordova-changes
12 | 1.2.0-breaking-changes
13 | 1.3.0-split-minifiers-package
14 | 1.4.0-remove-old-dev-bundle-link
15 | 1.4.1-add-shell-server-package
16 | 1.4.3-split-account-service-packages
17 | 1.5-add-dynamic-import-package
18 | 1.7-split-underscore-from-meteor-base
19 | 1.8.3-split-jquery-from-blaze
20 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | nlvom1n4rsd.t6xtf6i5fdy
8 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | meteor-base@1.5.1 # Packages every Meteor app needs to have
8 | mobile-experience@1.1.0 # Packages for a great mobile UX
9 | mongo@1.15.0 # The database Meteor supports right now
10 | blaze-html-templates # Compile .html files into Meteor Blaze views
11 | jquery # Wrapper package for npm-installed jquery
12 | reactive-var@1.0.11 # Reactive variable for tracker
13 | tracker@1.2.0 # Meteor's client-side reactive programming library
14 |
15 | standard-minifier-css@1.8.1 # CSS minifier run for production mode
16 | standard-minifier-js@2.8.0 # JS minifier run for production mode
17 | es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers
18 | ecmascript@0.16.2 # Enable ECMAScript2015+ syntax in app code
19 | typescript@4.5.4 # Enable TypeScript syntax in .ts and .tsx modules
20 | shell-server@0.5.0 # Server-side component of the `meteor shell` command
21 |
22 | reactive-dict@1.3.0
23 | accounts-password@2.3.1
24 | meteortesting:mocha
25 | quave:testing
26 | hot-module-replacement@0.5.1
27 | blaze-hot
28 | dev-error-overlay@0.1.1
29 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@2.7.2
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/.meteor/versions:
--------------------------------------------------------------------------------
1 | accounts-base@2.2.3
2 | accounts-password@2.3.1
3 | allow-deny@1.1.1
4 | autoupdate@1.8.0
5 | babel-compiler@7.9.0
6 | babel-runtime@1.5.0
7 | base64@1.0.12
8 | binary-heap@1.0.11
9 | blaze@2.6.0
10 | blaze-hot@1.1.1
11 | blaze-html-templates@2.0.0
12 | blaze-tools@1.1.3
13 | boilerplate-generator@1.7.1
14 | caching-compiler@1.2.2
15 | caching-html-compiler@1.2.1
16 | callback-hook@1.4.0
17 | check@1.3.1
18 | ddp@1.4.0
19 | ddp-client@2.5.0
20 | ddp-common@1.4.0
21 | ddp-rate-limiter@1.1.0
22 | ddp-server@2.5.0
23 | dev-error-overlay@0.1.1
24 | diff-sequence@1.1.1
25 | dynamic-import@0.7.2
26 | ecmascript@0.16.2
27 | ecmascript-runtime@0.8.0
28 | ecmascript-runtime-client@0.12.1
29 | ecmascript-runtime-server@0.11.0
30 | ejson@1.1.2
31 | email@2.2.1
32 | es5-shim@4.8.0
33 | fetch@0.1.1
34 | geojson-utils@1.0.10
35 | hot-code-push@1.0.4
36 | hot-module-replacement@0.5.1
37 | html-tools@1.1.3
38 | htmljs@1.1.1
39 | http@2.0.0
40 | id-map@1.1.1
41 | inter-process-messaging@0.1.1
42 | jquery@3.0.0
43 | launch-screen@1.3.0
44 | localstorage@1.2.0
45 | logging@1.3.1
46 | meteor@1.10.0
47 | meteor-base@1.5.1
48 | meteortesting:browser-tests@1.3.5
49 | meteortesting:mocha@2.0.3
50 | meteortesting:mocha-core@8.1.2
51 | minifier-css@1.6.0
52 | minifier-js@2.7.4
53 | minimongo@1.8.0
54 | mobile-experience@1.1.0
55 | mobile-status-bar@1.1.0
56 | modern-browsers@0.1.8
57 | modules@0.18.0
58 | modules-runtime@0.13.0
59 | modules-runtime-hot@0.14.0
60 | mongo@1.15.0
61 | mongo-decimal@0.1.3
62 | mongo-dev-server@1.1.0
63 | mongo-id@1.0.8
64 | npm-mongo@4.3.1
65 | observe-sequence@1.0.20
66 | ordered-dict@1.1.0
67 | promise@0.12.0
68 | quave:testing@1.0.1
69 | random@1.2.0
70 | rate-limit@1.0.9
71 | react-fast-refresh@0.2.3
72 | reactive-dict@1.3.0
73 | reactive-var@1.0.11
74 | reload@1.3.1
75 | retry@1.1.0
76 | routepolicy@1.1.1
77 | service-configuration@1.3.0
78 | sha@1.0.9
79 | shell-server@0.5.0
80 | socket-stream-client@0.5.0
81 | spacebars@1.3.0
82 | spacebars-compiler@1.3.1
83 | standard-minifier-css@1.8.1
84 | standard-minifier-js@2.8.0
85 | templating@1.4.2
86 | templating-compiler@1.4.1
87 | templating-runtime@1.6.0
88 | templating-tools@1.2.2
89 | tracker@1.2.0
90 | typescript@4.5.4
91 | underscore@1.0.10
92 | url@1.3.2
93 | webapp@1.13.1
94 | webapp-hashing@1.1.0
95 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/client/main.html:
--------------------------------------------------------------------------------
1 |
2 | step13
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/client/main.js:
--------------------------------------------------------------------------------
1 | import '../imports/ui/App.js';
2 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/imports/api/tasksMethods.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { check } from 'meteor/check';
3 | import { TasksCollection } from '../db/TasksCollection';
4 |
5 | Meteor.methods({
6 | 'tasks.insert'(text) {
7 | check(text, String);
8 |
9 | if (!this.userId) {
10 | throw new Meteor.Error('Not authorized.');
11 | }
12 |
13 | TasksCollection.insert({
14 | text,
15 | createdAt: new Date(),
16 | userId: this.userId,
17 | });
18 | },
19 |
20 | 'tasks.remove'(taskId) {
21 | check(taskId, String);
22 |
23 | if (!this.userId) {
24 | throw new Meteor.Error('Not authorized.');
25 | }
26 |
27 | const task = TasksCollection.findOne({ _id: taskId, userId: this.userId });
28 |
29 | if (!task) {
30 | throw new Meteor.Error('Access denied.');
31 | }
32 |
33 | TasksCollection.remove(taskId);
34 | },
35 |
36 | 'tasks.setIsChecked'(taskId, isChecked) {
37 | check(taskId, String);
38 | check(isChecked, Boolean);
39 |
40 | if (!this.userId) {
41 | throw new Meteor.Error('Not authorized.');
42 | }
43 |
44 | const task = TasksCollection.findOne({ _id: taskId, userId: this.userId });
45 |
46 | if (!task) {
47 | throw new Meteor.Error('Access denied.');
48 | }
49 |
50 | TasksCollection.update(taskId, {
51 | $set: {
52 | isChecked,
53 | },
54 | });
55 | },
56 | });
57 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/imports/api/tasksMethods.tests.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Random } from 'meteor/random';
3 | import { mockMethodCall } from 'meteor/quave:testing';
4 | import { assert } from 'chai';
5 | import { TasksCollection } from '/imports/db/TasksCollection';
6 | import '/imports/api/tasksMethods';
7 |
8 | if (Meteor.isServer) {
9 | describe('Tasks', () => {
10 | describe('methods', () => {
11 | const userId = Random.id();
12 | let taskId;
13 |
14 | beforeEach(() => {
15 | TasksCollection.remove({});
16 | taskId = TasksCollection.insert({
17 | text: 'Test Task',
18 | createdAt: new Date(),
19 | userId,
20 | });
21 | });
22 |
23 | it('can delete owned task', () => {
24 | mockMethodCall('tasks.remove', taskId, { context: { userId } });
25 |
26 | assert.equal(TasksCollection.find().count(), 0);
27 | });
28 |
29 | it("can't delete task without an user authenticated", () => {
30 | const fn = () => mockMethodCall('tasks.remove', taskId);
31 | assert.throw(fn, /Not authorized/);
32 | assert.equal(TasksCollection.find().count(), 1);
33 | });
34 |
35 | it("can't delete task from another owner", () => {
36 | const fn = () =>
37 | mockMethodCall('tasks.remove', taskId, {
38 | context: { userId: 'somebody-else-id' },
39 | });
40 | assert.throw(fn, /Access denied/);
41 | assert.equal(TasksCollection.find().count(), 1);
42 | });
43 |
44 | it('can change the status of a task', () => {
45 | const originalTask = TasksCollection.findOne(taskId);
46 | mockMethodCall('tasks.setIsChecked', taskId, !originalTask.isChecked, {
47 | context: { userId },
48 | });
49 |
50 | const updatedTask = TasksCollection.findOne(taskId);
51 | assert.notEqual(updatedTask.isChecked, originalTask.isChecked);
52 | });
53 |
54 | it('can insert new tasks', () => {
55 | const text = 'New Task';
56 | mockMethodCall('tasks.insert', text, {
57 | context: { userId },
58 | });
59 |
60 | const tasks = TasksCollection.find({}).fetch();
61 | assert.equal(tasks.length, 2);
62 | assert.isTrue(tasks.some(task => task.text === text));
63 | });
64 | });
65 | });
66 | }
67 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/imports/api/tasksPublications.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { TasksCollection } from '/imports/db/TasksCollection';
3 |
4 | Meteor.publish('tasks', function publishTasks() {
5 | return TasksCollection.find({ userId: this.userId });
6 | });
7 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/imports/db/TasksCollection.js:
--------------------------------------------------------------------------------
1 | import { Mongo } from 'meteor/mongo';
2 |
3 | export const TasksCollection = new Mongo.Collection('tasks');
4 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/imports/ui/App.html:
--------------------------------------------------------------------------------
1 |
2 | {{> mainContainer}}
3 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
17 | {{#if isUserLogged}}
18 |
19 | {{getUser.username}} 🚪
20 |
21 | {{> form }}
22 |
23 |
24 |
25 | {{#if hideCompleted}}
26 | Show All
27 | {{else}}
28 | Hide Completed
29 | {{/if}}
30 |
31 |
32 |
33 | {{#if isLoading}}
34 |
loading...
35 | {{/if}}
36 |
37 |
38 | {{#each tasks}}
39 | {{> task}}
40 | {{/each}}
41 |
42 | {{else}}
43 | {{> login }}
44 | {{/if}}
45 |
46 |
47 |
48 |
49 |
50 |
54 |
55 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/imports/ui/Login.html:
--------------------------------------------------------------------------------
1 |
2 |
28 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/imports/ui/Login.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Template } from 'meteor/templating';
3 | import './Login.html';
4 |
5 | Template.login.events({
6 | 'submit .login-form'(event) {
7 | event.preventDefault();
8 |
9 | const { target } = event;
10 |
11 | const username = target.username.value;
12 | const password = target.password.value;
13 |
14 | Meteor.loginWithPassword(username, password);
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/imports/ui/Task.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{text}}
5 | ×
6 |
7 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/imports/ui/Task.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Template } from 'meteor/templating';
3 |
4 | import './Task.html';
5 |
6 | Template.task.events({
7 | 'click .toggle-checked'() {
8 | // Set the checked property to the opposite of its current value
9 | Meteor.call('tasks.setIsChecked', this._id, !this.isChecked);
10 | },
11 | 'click .delete'() {
12 | Meteor.call('tasks.remove', this._id);
13 | },
14 | });
15 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "step01",
3 | "private": true,
4 | "scripts": {
5 | "start": "meteor run",
6 | "test": "meteor test --once --driver-package meteortesting:mocha",
7 | "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
8 | "visualize": "meteor --production --extra-packages bundle-visualizer"
9 | },
10 | "dependencies": {
11 | "@babel/runtime": "^7.15.4",
12 | "bcrypt": "^5.0.1",
13 | "jquery": "^3.6",
14 | "meteor-node-stubs": "^1.2.3"
15 | },
16 | "meteor": {
17 | "mainModule": {
18 | "client": "client/main.js",
19 | "server": "server/main.js"
20 | },
21 | "testModule": "tests/main.js"
22 | },
23 | "devDependencies": {
24 | "chai": "^4.3.4"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/server/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { Accounts } from 'meteor/accounts-base';
3 | import { TasksCollection } from '/imports/db/TasksCollection';
4 | import '/imports/api/tasksMethods';
5 | import '/imports/api/tasksPublications';
6 |
7 | const insertTask = (taskText, user) =>
8 | TasksCollection.insert({
9 | text: taskText,
10 | userId: user._id,
11 | createdAt: new Date(),
12 | });
13 |
14 | const SEED_USERNAME = 'meteorite';
15 | const SEED_PASSWORD = 'password';
16 |
17 | Meteor.startup(() => {
18 | if (!Accounts.findUserByUsername(SEED_USERNAME)) {
19 | Accounts.createUser({
20 | username: SEED_USERNAME,
21 | password: SEED_PASSWORD,
22 | });
23 | }
24 |
25 | const user = Accounts.findUserByUsername(SEED_USERNAME);
26 |
27 | if (TasksCollection.find().count() === 0) {
28 | [
29 | 'First Task',
30 | 'Second Task',
31 | 'Third Task',
32 | 'Fourth Task',
33 | 'Fifth Task',
34 | 'Sixth Task',
35 | 'Seventh Task',
36 | ].forEach(taskText => insertTask(taskText, user));
37 | }
38 | });
39 |
--------------------------------------------------------------------------------
/src/simple-todos/step13/tests/main.js:
--------------------------------------------------------------------------------
1 | import '/imports/api/tasksMethods.tests.js';
2 |
--------------------------------------------------------------------------------
/tutorial/changelog.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Changelog
3 | ---
4 |
5 | v1.1 - 06/06/2022
6 |
7 | - Tutorial Review.
8 |
9 | v1.0 - 03/24/2021
10 |
11 | - First version.
12 |
--------------------------------------------------------------------------------
/tutorial/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Home
3 | ---
4 |
5 | The Meteor Blaze Tutorial is where you can start learning the basics of Meteor with Blaze.
6 |
7 | Before you begin - If you want to know more about Meteor check our [website](https://www.meteor.com).
8 |
9 | A few tips before you start:
10 | - If you want to check the final code for each step, you can always go to the [`src`](https://github.com/meteor/blaze-tutorial/tree/master/src) folder.
11 | - Each folder inside [`src`](https://github.com/meteor/blaze-tutorial/tree/master/src) folder is a tutorial. Inside each, you have one folder for each step's final state. Each step folder is a Meteor app - you can run them at any time.
12 | - Install dependencies: `meteor npm install`
13 | - Run the project: `meteor`
14 | - If you see `..` in the code samples, it means that we are not showing all the code on this file or function.
15 |
16 |
17 | The `Simple Todos` tutorial is the best place for you to start with Meteor and Blaze. Check it out [here](/simple-todos/).
18 |
19 | If you have questions on how to get started, please ask the community on our [Forums](https://forums.meteor.com) or on Community Slack ([join here](https://join.slack.com/t/meteor-community/shared_invite/enQtODA0NTU2Nzk5MTA3LWY5NGMxMWRjZDgzYWMyMTEyYTQ3MTcwZmU2YjM5MTY3MjJkZjQ0NWRjOGZlYmIxZjFlYTA5Mjg4OTk3ODRiOTc)). We'd love to have you there!
20 |
21 | If you find any issues please click in the `Edit on Github` button at the bottom of every page and make a [Pull Request](https://github.com/meteor/blaze-tutorial/pulls) with your suggested changes.
22 |
--------------------------------------------------------------------------------
/tutorial/simple-todos/13-next-steps.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "13: Next Steps"
3 | ---
4 |
5 | Congratulations on your newly built Meteor app, which is running on Galaxy! Awesome job!
6 |
7 | Your app currently supports adding private tasks for the authenticated user.
8 |
9 | Ideas for new features:
10 | - Style completed tasks to be more evident the state;
11 | - In the login form, add the option to create a new user;
12 | - Share a task with someone else.
13 |
14 | Things to do on Galaxy:
15 | - Check your logs on Galaxy, watch [here](https://www.youtube.com/watch?v=WPYyHeWM21Q) or read [here](https://cloud-guide.meteor.com/logs.html);
16 | - Set up your free SSL certificate so you can use `https`, read [here](https://cloud-guide.meteor.com/encryption.html).
17 | - Set up your notifications, read [here](https://cloud-guide.meteor.com/notifications.html).
18 | - Auto-scale your app based on demand, watch [here](https://www.youtube.com/watch?v=rwLoviLzG6s) or read [here](https://cloud-guide.meteor.com/triggers.html);
19 | - Change your plan to Professional and watch your metrics on APM, read [here](https://cloud-guide.meteor.com/apm-getting-started.html).
20 | - Check all the Galaxy guide for [more](https://cloud-guide.meteor.com/).
21 |
22 | Here are some options for where you can go next:
23 |
24 | 1. Read the [Meteor Guide](https://guide.meteor.com/) to learn about best practices and useful community packages.
25 | 2. Check out the [complete documentation](https://docs.meteor.com/).
26 | 3. Enroll in our free [online univeristy](https://university.meteor.com/) and become a certified Meteor developer!
27 |
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step01-dev-tools-mobile-toggle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step01-dev-tools-mobile-toggle.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step01-mobile-with-meta-tags.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step01-mobile-with-meta-tags.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step01-mobile-without-meta-tags.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step01-mobile-without-meta-tags.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step02-connect-mongo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step02-connect-mongo.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step02-see-your-collection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step02-see-your-collection.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step02-see-your-db.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step02-see-your-db.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step02-tasks-list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step02-tasks-list.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step03-form-new-task.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step03-form-new-task.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step03-new-task-on-list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step03-new-task-on-list.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step04-checkbox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step04-checkbox.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step04-delete-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step04-delete-button.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step05-styles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step05-styles.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step06-all.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step06-all.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step06-ddp-messages.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step06-ddp-messages.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step06-extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step06-extension.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step06-filtered.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step06-filtered.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step07-login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step07-login.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step07-logout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step07-logout.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step10-android-emulator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step10-android-emulator.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step10-ios-simulator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step10-ios-simulator.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step11-test-report.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step11-test-report.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/assets/step12-sign-up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meteor/blaze-tutorial/ca0aa3c5cd09691ffbbaaaa0e83f0187f6864149/tutorial/simple-todos/assets/step12-sign-up.png
--------------------------------------------------------------------------------
/tutorial/simple-todos/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Introduction
3 | description: Learn how to create a Simple Todos with Meteor and Blaze
4 | ---
5 |
6 | In this tutorial we will build a simple to-do tasks app using [Blaze](https://www.blazejs.org/guide/introduction.html) with the Meteor platform.
7 |
8 | Blaze is a powerful library for creating user interfaces by writing reactive HTML templates. Usually, templates are written in Spacebars, a variant of Handlebars designed to take advantage of Tracker, Meteor’s reactivity system. These templates are compiled into JavaScript UI components that are rendered by the Blaze library.
9 |
10 | To develop your app, you will need a code editor. If you don't have any editor of your choice, a great option is to install [Visual Studio Code](https://code.visualstudio.com/). After installing it, you can and the [Meteor Toolbox extension](https://marketplace.visualstudio.com/items?itemName=meteor-toolbox.meteor-toolbox) to enable intellisense for Meteor core and packages. This extension also adds launch configurations for the browser (run/debug).
11 |
12 | Meteor works out-of-the-box with several other frameworks like [React](https://reactjs.org), [Svelte](https://svelte.dev/) and [Vue](https://guide.meteor.com/vue.html). We recommend you check out all of our [tutorials](https://www.meteor.com/tutorials).
13 |
14 | Let's get started with building your Blaze To-Do app with Meteor!
15 |
--------------------------------------------------------------------------------