├── .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 | 19 | 20 | 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 | 19 | 20 | 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 | 21 | 22 | 25 | 26 | 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 | 21 | 22 | 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 | -------------------------------------------------------------------------------- /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 | 27 | 28 | 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 | -------------------------------------------------------------------------------- /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 | 37 | 38 | 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 | -------------------------------------------------------------------------------- /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 | 44 | 45 | 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 44 | 45 | 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 48 | 49 | 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 48 | 49 | 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 48 | 49 | 55 | -------------------------------------------------------------------------------- /src/simple-todos/step11/imports/ui/Login.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 48 | 49 | 55 | -------------------------------------------------------------------------------- /src/simple-todos/step12/imports/ui/Login.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 48 | 49 | 55 | -------------------------------------------------------------------------------- /src/simple-todos/step13/imports/ui/Login.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------