Permalink
Please sign in to comment.
Showing
with
1,313 additions
and 0 deletions.
- +3 −0 .babelrc
- +6 −0 .gitignore
- +6 −0 .gitmodules
- +14 −0 README.md
- +11 −0 app.js
- +3 −0 clearPages.sh
- +3 −0 config.toml
- +49 −0 convert_files.js
- +33 −0 create_structure.js
- +123 −0 css/github.css
- +52 −0 deploy.sh
- +77 −0 html.jsx
- +34 −0 package.json
- +117 −0 templates/_template.jsx
- +121 −0 templates/docs/10-steps-to-plan-better-so-you-can-write-less-code/index.md
- +23 −0 templates/docs/5-steps-to-organizing-a-successful-campsite-event/index.md
- +109 −0 templates/docs/_template.jsx
- +14 −0 templates/docs/academic-honesty-policy/index.md
- +17 −0 templates/docs/adding-environment-variables/index.md
- +17 −0 templates/docs/guide-to-basejumps/accessing-the-database-from-your-frontend/index.md
- +13 −0 templates/docs/guide-to-basejumps/backend-file-structure/index.md
- +13 −0 templates/docs/guide-to-basejumps/bonus-socketio/index.md
- +13 −0 templates/docs/guide-to-basejumps/creating-a-new-api-endpoint/index.md
- +16 −0 templates/docs/guide-to-basejumps/creating-a-new-directive/index.md
- +14 −0 templates/docs/guide-to-basejumps/creating-a-new-route/index.md
- +34 −0 templates/docs/guide-to-basejumps/dynamic-URLs-using-routeParams/index.md
- +17 −0 templates/docs/guide-to-basejumps/epilogue/index.md
- +18 −0 templates/docs/guide-to-basejumps/fixing-exports.update/index.md
- +15 −0 templates/docs/guide-to-basejumps/frontend-file-structure/index.md
- +19 −0 templates/docs/guide-to-basejumps/get-info-about-the-current-user/index.md
- +8 −0 templates/docs/guide-to-basejumps/grunt/index.md
- +13 −0 templates/docs/guide-to-basejumps/index.md
- +21 −0 templates/docs/guide-to-basejumps/isLoggedInAsync/index.md
- +35 −0 templates/docs/guide-to-basejumps/more-useful-apis/index.md
- +31 −0 templates/docs/guide-to-basejumps/quick-tip-keep-data-in-sync/index.md
- +19 −0 templates/docs/guide-to-basejumps/restrict-a-page-to-authenticated-users/index.md
- +10 −0 templates/docs/guide-to-basejumps/seed-data/index.md
- +35 −0 templates/docs/guide-to-basejumps/table-of-contents/index.md
- +22 −0 templates/docs/how-to-use-the-free-code-camp-wiki/index.md
- +48 −0 templates/docs/index.md
- +20 −0 templates/index.md
- +25 −0 utils/typography.js
- +1 −0 wiki-gh-pages
- +1 −0 wiki-master
- +20 −0 wrappers/md.jsx
3
.babelrc
@@ -0,0 +1,3 @@ | ||
+{ | ||
+ "stage": 0 | ||
+} |
6
.gitignore
@@ -0,0 +1,6 @@ | ||
+node_modules/ | ||
+public/ | ||
+wiki-gh-pages/* | ||
+wiki-master/* | ||
+pages/* | ||
+docs/* |
6
.gitmodules
@@ -0,0 +1,6 @@ | ||
+[submodule "wiki-master"] | ||
+ path = wiki-master | ||
+ url = git@github.com:FreeCodeCamp/wiki.git | ||
+[submodule "wiki-gh-pages"] | ||
+ path = wiki-gh-pages | ||
+ url = git@github.com:FreeCodeCamp/wiki.git |
@@ -0,0 +1,14 @@ | ||
+# Scripts for deploying the wiki to gh-pages | ||
+ | ||
+## Setup | ||
+1. `npm install` | ||
+2. `cd scripts` | ||
+3. `npm install` | ||
+4. `chmod 744 deploy.sh` | ||
+ | ||
+Git Remotes: | ||
+`live` = `git@github.com:FreeCodeCamp/FreeCodeCamp/wiki.git` | ||
+`live-gatsby` = `git@github.com:FreeCodeCamp/wiki.git` | ||
+ | ||
+## To Run | ||
+`./deploy.sh` |
11
app.js
@@ -0,0 +1,11 @@ | ||
+exports.loadContext = function(callback) { | ||
+ var context; | ||
+ context = require.context('./pages', true); | ||
+ if (module.hot) { | ||
+ module.hot.accept(context.id, function() { | ||
+ context = require.context('./pages', true); | ||
+ return callback(context); | ||
+ }); | ||
+ } | ||
+ return callback(context); | ||
+}; |
3
clearPages.sh
@@ -0,0 +1,3 @@ | ||
+#!/bin/bash | ||
+rm -rf ./pages/* | ||
+cp -r templates/* pages/ |
3
config.toml
@@ -0,0 +1,3 @@ | ||
+siteTitle="FreeCodeCamp Wiki" | ||
+headerColor = "#884499" | ||
+linkPrefix = "/wiki" |
49
convert_files.js
@@ -0,0 +1,49 @@ | ||
+/* | ||
+Automated cleanup / Setup -- node script | ||
+-- All in "Pages" | ||
+- Add Headers to each file | ||
+ - Title, Order (whatever that is) | ||
+- ? Automated cleanup of Markdown | ||
+IE: ###NoSpace === ### With Space | ||
+Regex : /^(\s+#{1,4})(\S)/ => /$1 $2/ | ||
+- List of regex to automate | ||
+JSON Array/Object | ||
+ - Link modification/cleanup | ||
+*/ | ||
+ | ||
+var fs = require('fs'); | ||
+var incomingLink = /github\.com\/freecodecamp\/freecodecamp\/wiki/gi; | ||
+var outgoingLink = 'freecodecamp.com/wiki/docs'; | ||
+ | ||
+// Get File list | ||
+fs.readdir('./pages/docs/', function(err, folders) { | ||
+ if(err) throw err; | ||
+ var fileList = folders.filter(function(folder) { | ||
+ // Remove stupid hidden folders | ||
+ return !/^\.|\.md$|^_/.test(folder); | ||
+ }).map(function(folder) { | ||
+ // Make directories/filenames | ||
+ var filename = folder+'/index.md'; | ||
+ var title = folder.replace(/-/g, ' ').replace('.md', ''); | ||
+ return { filename: filename, title: title}; | ||
+ }); | ||
+ | ||
+ fileList.forEach(function(fileobj) { | ||
+ // Create directory | ||
+ | ||
+ var newFileName = './pages/docs/'+fileobj.filename; | ||
+ | ||
+ var data = fs.readFileSync(newFileName, 'utf-8'); //read existing contents into data | ||
+ var fd = fs.openSync(newFileName, 'w+'); | ||
+ | ||
+ data = data.replace(incomingLink, outgoingLink); | ||
+ var newData = new Buffer(data); | ||
+ | ||
+ var header = '---\ntitle: ' + fileobj.title + '\norder: 5\n---\n'; | ||
+ var buffer = new Buffer(header); | ||
+ | ||
+ fs.writeSync(fd, buffer, 0, buffer.length); //write new data | ||
+ fs.writeSync(fd, newData, 0, newData.length); //append old data | ||
+ fs.close(fd); | ||
+ }); | ||
+}); |
33
create_structure.js
@@ -0,0 +1,33 @@ | ||
+/* | ||
+Automate converting the raw "wiki" into the proper hierarchy -- node script | ||
+- Readin in the file list | ||
+- Create top-level folders based on file name (Assume flat structure) | ||
+- Copy the files into their folders as index.md | ||
+-- All in "Pages" | ||
+*/ | ||
+ | ||
+var mkdirp = require('mkdirp'); | ||
+var fs = require('fs'); | ||
+ | ||
+// Get File list | ||
+fs.readdir('./wiki-master', function(err, files) { | ||
+ if(err) throw err; | ||
+ var fileList = files.filter(function(file) { | ||
+ return (/\.md$/.test(file) && !/^_/.test(file)); | ||
+ }).map(function(file) { | ||
+ // Make directories/filenames | ||
+ var filename = file; | ||
+ var dir = file.replace('.md', ''); | ||
+ return { filename: filename, dir: dir}; | ||
+ }); | ||
+ | ||
+ fileList.forEach(function(fileobj) { | ||
+ // Create directory | ||
+ mkdirp('./pages/docs/' + fileobj.dir, function(err) { | ||
+ if(err) throw err; | ||
+ // Copy File | ||
+ var newFileName = './pages/docs/'+fileobj.dir+"/index.md"; | ||
+ fs.createReadStream('./wiki-master/' + fileobj.filename).pipe(fs.createWriteStream(newFileName)); | ||
+ }); | ||
+ }); | ||
+}); |
123
css/github.css
@@ -0,0 +1,123 @@ | ||
+/* | ||
+ | ||
+github.com style (c) Vasily Polovnyov <vast@whiteants.net> | ||
+ | ||
+*/ | ||
+ | ||
+.hljs { | ||
+ display: block; | ||
+ overflow-x: auto; | ||
+ padding: 0.5em; | ||
+ color: #333; | ||
+ background: #f8f8f8; | ||
+ -webkit-text-size-adjust: none; | ||
+} | ||
+ | ||
+.hljs-comment, | ||
+.diff .hljs-header { | ||
+ color: #998; | ||
+ font-style: italic; | ||
+} | ||
+ | ||
+.hljs-keyword, | ||
+.css .rule .hljs-keyword, | ||
+.hljs-winutils, | ||
+.nginx .hljs-title, | ||
+.hljs-subst, | ||
+.hljs-request, | ||
+.hljs-status { | ||
+ color: #333; | ||
+ font-weight: bold; | ||
+} | ||
+ | ||
+.hljs-number, | ||
+.hljs-hexcolor, | ||
+.ruby .hljs-constant { | ||
+ color: #008080; | ||
+} | ||
+ | ||
+.hljs-string, | ||
+.hljs-tag .hljs-value, | ||
+.hljs-doctag, | ||
+.tex .hljs-formula { | ||
+ color: #d14; | ||
+} | ||
+ | ||
+.hljs-title, | ||
+.hljs-id, | ||
+.scss .hljs-preprocessor { | ||
+ color: #900; | ||
+ font-weight: bold; | ||
+} | ||
+ | ||
+.hljs-list .hljs-keyword, | ||
+.hljs-subst { | ||
+ font-weight: normal; | ||
+} | ||
+ | ||
+.hljs-class .hljs-title, | ||
+.hljs-type, | ||
+.vhdl .hljs-literal, | ||
+.tex .hljs-command { | ||
+ color: #458; | ||
+ font-weight: bold; | ||
+} | ||
+ | ||
+.hljs-tag, | ||
+.hljs-tag .hljs-title, | ||
+.hljs-rule .hljs-property, | ||
+.django .hljs-tag .hljs-keyword { | ||
+ color: #000080; | ||
+ font-weight: normal; | ||
+} | ||
+ | ||
+.hljs-attribute, | ||
+.hljs-variable, | ||
+.lisp .hljs-body, | ||
+.hljs-name { | ||
+ color: #008080; | ||
+} | ||
+ | ||
+.hljs-regexp { | ||
+ color: #009926; | ||
+} | ||
+ | ||
+.hljs-symbol, | ||
+.ruby .hljs-symbol .hljs-string, | ||
+.lisp .hljs-keyword, | ||
+.clojure .hljs-keyword, | ||
+.scheme .hljs-keyword, | ||
+.tex .hljs-special, | ||
+.hljs-prompt { | ||
+ color: #990073; | ||
+} | ||
+ | ||
+.hljs-built_in { | ||
+ color: #0086b3; | ||
+} | ||
+ | ||
+.hljs-preprocessor, | ||
+.hljs-pragma, | ||
+.hljs-pi, | ||
+.hljs-doctype, | ||
+.hljs-shebang, | ||
+.hljs-cdata { | ||
+ color: #999; | ||
+ font-weight: bold; | ||
+} | ||
+ | ||
+.hljs-deletion { | ||
+ background: #fdd; | ||
+} | ||
+ | ||
+.hljs-addition { | ||
+ background: #dfd; | ||
+} | ||
+ | ||
+.diff .hljs-change { | ||
+ background: #0086b3; | ||
+} | ||
+ | ||
+.hljs-chunk { | ||
+ color: #aaa; | ||
+} |
52
deploy.sh
@@ -0,0 +1,52 @@ | ||
+#!/bin/bash | ||
+ | ||
+# Automate Deployment -- bash script | ||
+# - run clearPages.sh | ||
+# - run | ||
+# - git checkout master | ||
+# - Pull down the Wiki | ||
+# - Run Conversion (See above) | ||
+# - Run Cleanup (See above) | ||
+# - Run Gatsby Build Operation | ||
+# - git checkout gh-pages | ||
+# - Copy files to `gh-pages` | ||
+# - Commit files to that branch | ||
+# - Git push | ||
+ | ||
+# Refresh pages directory | ||
+./clearPages.sh | ||
+ | ||
+# Update wiki repo copy | ||
+cd wiki-master | ||
+git pull origin master | ||
+cd .. | ||
+ | ||
+# Copy and Transform .md files from wiki repo | ||
+node create_structure.js | ||
+node convert_files.js | ||
+ | ||
+# Build Output | ||
+gatsby build --prefix-links | ||
+ | ||
+# Copy generated output to gh-pages on live wiki | ||
+cp -r public/docs/* wiki-gh-pages/docs/ | ||
+cp public/bundle.js wiki-gh-pages/ | ||
+cp public/index.html wiki-gh-pages/ | ||
+cp public/bundle.js.map wiki-gh-pages/ | ||
+ | ||
+# Update gh-pages branch with new files | ||
+cd wiki-gh-pages/ | ||
+git pull origin gh-pages | ||
+git add docs | ||
+git add bundle.js.map | ||
+git add bundle.js | ||
+git add index.html | ||
+git commit -m "Page built on `date +"%d-%m-%Y %T"`" | ||
+ | ||
+# Push gh-pages live | ||
+git push origin gh-pages | ||
+ | ||
+# Push regular wiki live | ||
+cd ../wiki-master | ||
+#git push live master | ||
+cd .. |
77
html.jsx
@@ -0,0 +1,77 @@ | ||
+import React from 'react'; | ||
+import DocumentTitle from 'react-document-title'; | ||
+ | ||
+import { link } from 'gatsby-helpers'; | ||
+import typography from './utils/typography'; | ||
+const { TypographyStyle } = typography; | ||
+ | ||
+module.exports = React.createClass({ | ||
+ getDefaultProps: function() { | ||
+ return { | ||
+ body: "" | ||
+ }; | ||
+ }, | ||
+ | ||
+ render: function() { | ||
+ var title | ||
+ title = DocumentTitle.rewind(); | ||
+ if (this.props.title) { | ||
+ title = this.props.title; | ||
+ } | ||
+ | ||
+ return ( | ||
+ <html lang="en"> | ||
+ <head> | ||
+ <meta charSet="utf-8"/> | ||
+ <meta httpEquiv="X-UA-Compatible" content="IE=edge"/> | ||
+ <meta name='viewport' content='user-scalable=no width=device-width, initial-scale=1.0 maximum-scale=1.0'/> | ||
+ <title>{title}</title> | ||
+ <link rel="shortcut icon" href={this.props.favicon}/> | ||
+ <TypographyStyle/> | ||
+ <style dangerouslySetInnerHTML={{__html: | ||
+ ` | ||
+ a { | ||
+ color: #884499; | ||
+ } | ||
+ pre { | ||
+ background: whitesmoke; | ||
+ padding: 1.5rem; | ||
+ } | ||
+ .demo1-ball { | ||
+ border-radius: 99px; | ||
+ background-color: white; | ||
+ width: 50px; | ||
+ height: 50px; | ||
+ border: 3px solid white; | ||
+ position: absolute; | ||
+ background-size: 50px; | ||
+ } | ||
+ .ball-0 { | ||
+ background-image: url(${link("/docs/some-react-code/0.jpg")}); | ||
+ } | ||
+ .ball-1 { | ||
+ background-image: url(${link("/docs/some-react-code/1.jpg")}); | ||
+ } | ||
+ .ball-2 { | ||
+ background-image: url(${link("/docs/some-react-code/2.jpg")}); | ||
+ } | ||
+ .ball-3 { | ||
+ background-image: url(${link("/docs/some-react-code/3.jpg")}); | ||
+ } | ||
+ .ball-4 { | ||
+ background-image: url(${link("/docs/some-react-code/4.jpg")}); | ||
+ } | ||
+ .ball-5 { | ||
+ background-image: url(${link("/docs/some-react-code/5.jpg")}); | ||
+ } | ||
+ ` | ||
+ }} /> | ||
+ </head> | ||
+ <body className="landing-page"> | ||
+ <div id="react-mount" dangerouslySetInnerHTML={{__html: this.props.body}} /> | ||
+ <script src={link("/bundle.js")}/> | ||
+ </body> | ||
+ </html> | ||
+ ); | ||
+ } | ||
+}); |
34
package.json
@@ -0,0 +1,34 @@ | ||
+{ | ||
+ "name": "wiki-generator", | ||
+ "version": "1.0.0", | ||
+ "description": "Wiki Pages Generator for Free Code Camp", | ||
+ "main": "index.js", | ||
+ "scripts": { | ||
+ "test": "echo \"Error: no test specified\" && exit 1" | ||
+ }, | ||
+ "repository": { | ||
+ "type": "git", | ||
+ "url": "git+ssh://git@github.com/FreeCodeCamp/wiki-generator.git" | ||
+ }, | ||
+ "author": "Free Code Camp", | ||
+ "bugs": { | ||
+ "url": "https://github.com/FreeCodeCamp/wiki-generator/issues" | ||
+ }, | ||
+ "homepage": "https://github.com/FreeCodeCamp/wiki-generator#readme", | ||
+ "license": "(BSD-3-Clause AND CC-BY-SA-4.0)", | ||
+ "dependencies": { | ||
+ "chroma-js": "0.7.2", | ||
+ "color-pairs-picker": "^1.3.5", | ||
+ "lodash": "^3.10.1", | ||
+ "react": "^0.14.3", | ||
+ "react-document-title": "^2.0.1", | ||
+ "react-dom": "^0.14.3", | ||
+ "react-motion": "^0.1.0", | ||
+ "react-responsive-grid": "^0.2.1", | ||
+ "react-router": "^0.13.5", | ||
+ "typography": "^0.6.2", | ||
+ "underscore.string": "^3.2.2", | ||
+ "mkdirp": "^0.5.1", | ||
+ "promise": "^7.0.4" | ||
+ } | ||
+} |
117
templates/_template.jsx
@@ -0,0 +1,117 @@ | ||
+import React from 'react'; | ||
+import { RouteHandler, Link, State } from 'react-router'; | ||
+import { Container, Grid, Breakpoint, Span } from 'react-responsive-grid'; | ||
+import colorPairsPicker from 'color-pairs-picker'; | ||
+import chroma from 'chroma-js'; | ||
+import includes from 'underscore.string/include'; | ||
+import { link } from 'gatsby-helpers'; | ||
+ | ||
+import typography from 'utils/typography'; | ||
+ | ||
+// Style code | ||
+import 'css/github.css'; | ||
+ | ||
+const { rhythm, fontSizeToPx } = typography; | ||
+ | ||
+module.exports = React.createClass({ | ||
+ mixins: [State], | ||
+ render: function() { | ||
+ var activeHeaderColors, darker, docsActive, examplesActive, headerColors, ref1, ref2, routes | ||
+ headerColors = colorPairsPicker(this.props.config.headerColor, { | ||
+ contrast: 5.5 | ||
+ }); | ||
+ darker = chroma(this.props.config.headerColor).darken(9).hex(); | ||
+ activeHeaderColors = colorPairsPicker(darker, { | ||
+ contrast: 7 | ||
+ }); | ||
+ | ||
+ routes = this.getRoutes().map(function(route) { | ||
+ return route.path; | ||
+ }); | ||
+ docsActive = (routes.indexOf(link("/docs/")) >= 0); | ||
+ | ||
+ return ( | ||
+ <div> | ||
+ <div | ||
+ style={{ | ||
+ background: headerColors.bg, | ||
+ color: headerColors.fg, | ||
+ marginBottom: rhythm(1.5) | ||
+ }} | ||
+ > | ||
+ <Container | ||
+ style={{ | ||
+ maxWidth: 960, | ||
+ padding: `${rhythm(1/2)}`, | ||
+ paddingBottom: `${rhythm(1/2)}` | ||
+ }} | ||
+ > | ||
+ <Grid | ||
+ columns={12} | ||
+ style={{ | ||
+ padding: `${rhythm(1/2)} 0` | ||
+ }} | ||
+ > | ||
+ <Span | ||
+ columns={4} | ||
+ style={{ | ||
+ height: 24 // Ugly hack. How better to constrain height of div? | ||
+ }} | ||
+ > | ||
+ <Link | ||
+ to={link('/')} | ||
+ style={{ | ||
+ textDecoration: 'none', | ||
+ color: headerColors.fg, | ||
+ fontSize: fontSizeToPx("25.5px").fontSize | ||
+ }} | ||
+ > | ||
+ {this.props.config.siteTitle} | ||
+ </Link> | ||
+ </Span> | ||
+ <Span columns={8} last={true}> | ||
+ <a | ||
+ style={{ | ||
+ float: 'right', | ||
+ color: headerColors.fg, | ||
+ textDecoration: 'none', | ||
+ marginLeft: rhythm(1/2) | ||
+ }} | ||
+ href="https://github.com/gatsbyjs/gatsby" | ||
+ > | ||
+ Github | ||
+ </a> | ||
+ <Link | ||
+ to={link('/docs/')} | ||
+ style={{ | ||
+ background: docsActive ? activeHeaderColors.bg : headerColors.bg, | ||
+ color: docsActive ? activeHeaderColors.fg : headerColors.fg, | ||
+ float: 'right', | ||
+ textDecoration: 'none', | ||
+ paddingLeft: rhythm(1/2), | ||
+ paddingRight: rhythm(1/2), | ||
+ paddingBottom: rhythm(1), | ||
+ marginBottom: rhythm(-1), | ||
+ paddingTop: rhythm(1), | ||
+ marginTop: rhythm(-1) | ||
+ }} | ||
+ > | ||
+ Documentation | ||
+ </Link> | ||
+ </Span> | ||
+ </Grid> | ||
+ </Container> | ||
+ </div> | ||
+ <Container | ||
+ style={{ | ||
+ maxWidth: 960, | ||
+ padding: `${rhythm(1)} ${rhythm(1/2)}`, | ||
+ paddingTop: 0 | ||
+ }} | ||
+ > | ||
+ <RouteHandler {...this.props}/> | ||
+ </Container> | ||
+ </div> | ||
+ ); | ||
+ } | ||
+}); |
@@ -0,0 +1,121 @@ | ||
+--- | ||
+title: 10 Steps To Plan Better So You Can Write Less Code | ||
+order: 5 | ||
+--- | ||
+ | ||
+## Learn how to plan your future project! | ||
+ | ||
+*Blog post written by BiancaMihai - [GitHub](https://github.com/biancamihai) / [Twitter](https://twitter.com/intent/user?screen_name=bubuslubu)* | ||
+ | ||
+An ounce of preparation is worth a pound of cure. That's true in medicine, and that's definitely true in software development. | ||
+ | ||
+Here's a structured 10-step workflow that will guide you through the app planning process, with the goal of saving you from writing a lot of unnecessary code. | ||
+ | ||
+Together, we'll plan out a simple "To-do" single-page web app. We'll also plan for an API backend for a future mobile app. | ||
+ | ||
+### 1) Create our Trello board | ||
+ | ||
+[Trello](https://trello.com/) is a fun, free way to break your planning and development process into small tasks that can be tracked. | ||
+ | ||
+![Image of Trello board](https://lh3.googleusercontent.com/EI4AQ4NINm3B2DHR_YIS29JyKVa5dTPiT3RtITylmndFlpshTHepsKuO8_1KQNfdPDSBjslDReHCuPFeH1GNrDtgOwTyq6ZtGf3DFBmq1AsAhPHKt_0pLXQLf0o4ZbDuKVj4-Bo) | ||
+ | ||
+ | ||
+[Here's what our Trello board will eventually look like](https://trello.com/b/O9MZcYyY/todo-app). I prefer to split my tasks into 3 columns (depending on the complexity of the project): | ||
+ | ||
+* To Do - what is left to do | ||
+* In progress - tasks that people are currently working on | ||
+* Done - tasks that are done and ready for testing | ||
+ | ||
+### 2) Write user stories | ||
+ | ||
+Here are some example user stories. These will guide how we think about our app's features and functionality. Note that they all follow a similar structure: as a <person> I can <do something>. | ||
+ | ||
+* as a logged-in user I can see the list of my to-do's. | ||
+* as a logged-in user I can add a new to-do. | ||
+* as a logged-in user I can delete a to-do (only my to-do's - not other users'). | ||
+* as a logged-in user I can complete a to-do (only my to-do's - not other users'). | ||
+* as an anonymous user, I can register for a new account, recover my password, or log in to the app with an existing account. | ||
+ | ||
+### 3) Create our use case model | ||
+ | ||
+Our use case model will help us visualize our user stories so we can better understand how to implement them. | ||
+ | ||
+![Anonymous user case diagram](https://lh5.googleusercontent.com/2v6iIMbCrLSKVfqttEToum7OA3YGQCBKWUHcSCB1KEbEcijXxQtKJKY6fhLXeecJiO27P4icOuPlkVc9_uNXolzlzNXOo_TPh09GZsAqRH-JISqPrpx0PZdtbHOr0RIuQUbTbaw) | ||
+![Authenticated user case diagram](https://lh6.googleusercontent.com/3V6dVvAcyjqFkaOukimucYOX0CfwBBYNN9SvjmnVy40Pdhs4Wtrr34i3E-9pbV7tFsp4jHm77IFQvFupjq6OWyxqEgCzcQ995Ayh52Msczu6TfwKeNhL9PYHyxSgmPYA1TR6l6Q) | ||
+ | ||
+### 4) Create our activity diagram | ||
+ | ||
+Our activity diagram will show the different paths our users can take through our app. | ||
+ | ||
+![Activity diagram picture](https://lh6.googleusercontent.com/jAQL4myqWOPA3gk2iTpGyAQBrO6p1GlPe8BQQ1Se6a-Di40X3Zw1p0wfJewZUL-YyDmedYzX5Lxvo2GW2Qnr6I-6kuKe1sDb9_5F_n46cKoawWReWW_ZoZCIJO6Semc4fvsiuHc) | ||
+ | ||
+A user accesses our to-do application. | ||
+* If the user is not logged in she will see our login page. | ||
+* If she already has an account, she can log in. | ||
+* If she has an account, but she forgot her password, she can recover her password. | ||
+* If she doesn't have an account, she can create one. | ||
+* Both "create an account" and "recover my password" will require email validation. A user can log in to our application only after she has confirmed her email address. | ||
+* If she is logged in, she will see her to-do list (this can be empty if she hasn't added any to-dos yet). | ||
+* A logged in user: | ||
+ * is able to see her tasks list | ||
+ * is able to mark a task from her list as completed | ||
+ * is able to search within her task list | ||
+ * is able to delete a task from her list | ||
+ * can logout. | ||
+* The user can exit the application at any time. | ||
+ | ||
+### 5) Create our mockups | ||
+ | ||
+Our mockups show what our app should look like. It's much faster to iterate on a mockup than it is to do so on working code. | ||
+ | ||
+![Mockup picture](https://lh3.googleusercontent.com/GBFhmBkfr-xM5YSXlR0Fm9y8b24ivdRlUtRWQOHJ8skNxEgjTkAef0e5nZ-CcHKNUq2p4V4hgDuAm9LSEuvbovlVborH1ZioAUXVlEblWZ4hN_d2tGEpxhfTkKH9os2JS1pab4w) | ||
+ | ||
+### 6) Choose the right technologies for our project | ||
+ | ||
+Because this is a single page app, we'll rely heavily - or in this case exclusively - on JavaScript. Let's use one of the most popular JavaScript stacks: the MEAN stack. One big benefit of the MEAN stack is that all of its components are free and open-source. There are also tons of resources available for learning the MEAN stack, and for debugging it when you inevitably encounter errors. | ||
+ | ||
+You can have a [MEAN stack development environment](http://www.freecodecamp.com/challenges/waypoint-get-set-for-basejumps) up and running in the cloud in less than an hour, for free. | ||
+ | ||
+Here are the components we'll use: | ||
+1. [MongoDB](http://mongodb.org/) for our database | ||
+2. [Node.js](http://nodejs.org/) and [Express.js](http://expressjs.com/) for implementing our API | ||
+3. [AngularJS](http://angularjs.org/), along with HTML and CSS (and Bootstrap) for our client-side application | ||
+4. [Mongoose](http://mongoosejs.com/) to connect our application to MongoDB | ||
+ | ||
+### 7) Design our database schema | ||
+ | ||
+It's worth the effort to design a database schema, even for our simple application. | ||
+ | ||
+We'll have two collections: our "Users" collection will house our user data, and our "ToDo" collection will house our tasks that need to be done. One user can have zero, one, or many tasks in her to-do list, so we will have a one-to-many (1:m) relationship between our two collections. | ||
+ | ||
+![Database schema diagram](https://lh6.googleusercontent.com/5uSb_xnSSc5CWXJD0yyUGVJsL92RRZl3Bex_3wjuzl5Xr69Ks0j3od-yFju24SAd5wWMBNy9uqBrvOzdrUWluOkbcr4H5zFg-ZemJX3ZRWS12D42OowuvWnxA7wWIGrhhzaQ0aw) | ||
+ | ||
+### 8) Define our use cases | ||
+ | ||
+1. What happens to the to-dos related to a user that deletes her account? When the user deletes her account the to-dos related to that user should also be deleted. | ||
+2. No to-do can be added without being attached to a confirmed user. | ||
+3. A to-do can only be deleted by its owner. | ||
+4. No user can be added with an empty username or password. | ||
+5. No to-do can be added with an empty task. | ||
+ | ||
+Things to keep in mind: | ||
+ | ||
+1. Use the Mongoose middleware to remove dependent documents like to-dos when a user deletes her account. | ||
+2. Use Mongoose validation rules on models to prevent empty fields from being added to our database. | ||
+ | ||
+### 9) Design and test our API | ||
+ | ||
+I used a free product called Apiary [to document our API](http://docs.fcctodoapp.apiary.io/). | ||
+ | ||
+Here's the syntax I used to [create this simple BluePrint](https://jsapi.apiary.io/apis/fcctodoapp.apib). | ||
+ | ||
+I recommend you create an account and start playing with it. If you link your [GitHub](http://github.com/) account with Apiary, you can ensure your documentation always stays up to date. You'll also be able to test your data visually without the need for actually hitting your API endpoints. If you prefer to test your API from the command line, [here's an example of how to do this](http://docs.agendor.apiary.io/). | ||
+ | ||
+ | ||
+Later, once you've implemented your API with Node.js and Express.js, you'll just need to set your URL in Apiary. Then you can start testing your calls. Our current host url (http://fcctodoapp.apiblueprint.org/) will be replaced by your API's URL. | ||
+ | ||
+![App demo picture](https://lh6.googleusercontent.com/hU3ilG_y9FqtL_zajQ_KOjWy8Qx590Go8nkNvA1j0oR50YJTpjJhL1lAPgjyeLTAS06tq6V62EcJrLQyT_TR2BK49DYiX6kksU6s9cqJDvvaS6jvepIM6uiO4JMbXuu-oXhdsas) | ||
+ | ||
+### 10) Start writing code! | ||
+ | ||
+This is the fun part, and it will take up most of your project's time. If you need help with this, join us and learn to code. |
@@ -0,0 +1,23 @@ | ||
+--- | ||
+title: 5 Steps to organizing a successful Campsite event | ||
+order: 5 | ||
+--- | ||
+ | ||
+# In-person group programming sessions and events are fun! | ||
+ | ||
+## This Wiki will help you with organizing a successful Campsite event. | ||
+ | ||
+### With a little planning and communication having a successful Campsite event can be easy! Here are some steps to help you in doing this. | ||
+### | ||
+ | ||
+* Determine the topic for the event (code and coffee, hack session, invite campers to another organization's event). | ||
+ | ||
+* Find a suitable location. Campsite events should always take place in a public space (library, cafe, hackerspace). | ||
+ | ||
+* Create an event on your Campsite's Facebook page for the event, and link to it on your Campsite Facebook Group page. | ||
+ | ||
+* Follow-up with reminder posts for the event 1 week prior to the event and then again the day before the event. | ||
+ | ||
+* On the day of the event arrive early, get setup, greet members, and kick the event off. Don't forget to thank everyone afterwards and extend invites to future meetups. | ||
+ | ||
+**Try to take some pictures and post them on your Campsite's Facebook group page.** |
109
templates/docs/_template.jsx
@@ -0,0 +1,109 @@ | ||
+import React from 'react'; | ||
+import { RouteHandler, Link, State, Navigation } from 'react-router'; | ||
+import { Container, Grid, Breakpoint, Span } from 'react-responsive-grid'; | ||
+import Typography from 'typography'; | ||
+import sortBy from 'lodash/collection/sortBy'; | ||
+import { link, templateChildrenPages } from 'gatsby-helpers'; | ||
+ | ||
+import typography from 'utils/typography'; | ||
+const { rhythm, fontSizeToPx } = typography; | ||
+ | ||
+module.exports = React.createClass({ | ||
+ mixins: [State, Navigation], | ||
+ | ||
+ handleTopicChange: function(e) { | ||
+ return this.transitionTo(e.target.value); | ||
+ }, | ||
+ | ||
+ render: function() { | ||
+ var childPages, docOptions, docPages; | ||
+ childPages = templateChildrenPages(__filename, this.props.state).map(function(child) { | ||
+ return { | ||
+ title: child.data.title, | ||
+ order: child.data.order, | ||
+ path: child.path | ||
+ }; | ||
+ }); | ||
+ childPages = sortBy(childPages, function(child) { | ||
+ return child.order; | ||
+ }); | ||
+ docOptions = childPages.map(function(child) { | ||
+ return React.createElement("option", { | ||
+ "key": child.path, | ||
+ "value": child.path | ||
+ }, child.title); | ||
+ }); | ||
+ docPages = childPages.map((function(_this) { | ||
+ return function(child) { | ||
+ var isActive; | ||
+ isActive = _this.isActive(link(child.path)); | ||
+ return ( | ||
+ <li | ||
+ key={child.path} | ||
+ style={{ | ||
+ marginBottom: rhythm(1/2) | ||
+ }} | ||
+ > | ||
+ <Link | ||
+ to={link(child.path)} | ||
+ style={{ | ||
+ textDecoration: 'none' | ||
+ }} | ||
+ > | ||
+ {isActive ? <strong>{child.title}</strong> : child.title } | ||
+ </Link> | ||
+ </li> | ||
+ ) | ||
+ }; | ||
+ })(this)); | ||
+ | ||
+ return ( | ||
+ <div> | ||
+ <Breakpoint minWidth={700}> | ||
+ <div> | ||
+ <div | ||
+ style={{ | ||
+ overflowY: 'auto', | ||
+ paddingRight: `calc(${rhythm(1/2)} - 1px)`, | ||
+ position: 'absolute', | ||
+ width: `calc(${rhythm(8)} - 1px)`, | ||
+ borderRight: '1px solid lightgrey' | ||
+ }} | ||
+ > | ||
+ <ul | ||
+ style={{ | ||
+ listStyle: 'none', | ||
+ marginLeft: 0, | ||
+ marginTop: rhythm(1/2) | ||
+ }} | ||
+ > | ||
+ {docPages} | ||
+ </ul> | ||
+ </div> | ||
+ <div | ||
+ style={{ | ||
+ padding: `0 ${rhythm(1)}`, | ||
+ paddingLeft: `calc(${rhythm(8)} + ${rhythm(1)})` | ||
+ }} | ||
+ > | ||
+ <RouteHandler typography={typography} {...this.props}/> | ||
+ </div> | ||
+ </div> | ||
+ </Breakpoint> | ||
+ <Breakpoint maxWidth={700}> | ||
+ <strong>Topics:</strong> | ||
+ {' '} | ||
+ <select | ||
+ defaultValue={this.props.state.path} | ||
+ onChange={this.handleTopicChange} | ||
+ > | ||
+ {docOptions} | ||
+ </select> | ||
+ <br /> | ||
+ <br /> | ||
+ <RouteHandler typography={typography} {...this.props}/> | ||
+ </Breakpoint> | ||
+ </div> | ||
+ ); | ||
+ } | ||
+}); |
@@ -0,0 +1,14 @@ | ||
+--- | ||
+title: Academic Honesty Policy | ||
+order: 5 | ||
+--- | ||
+ | ||
+Before we issue our verified certificate to a camper, he or she must accept our Academic Honesty Pledge, which reads: | ||
+ | ||
+**I understand that plagiarism means copying someone else's work and presenting the work as if it were my own, without clearly attributing the original author.** | ||
+ | ||
+**I understand that plagiarism is an act of intellectual dishonesty, and that people usually get kicked out of university or fired from their jobs if they get caught plagiarizing.** | ||
+ | ||
+**Aside from using open source libraries such as jQuery and Bootstrap, and short snippets of code which are clearly attributed to their original author, 100% of the code in my Bonfires, Basejumps and Ziplines was written by me or along with another camper with whom I was pair programming in real time.** | ||
+ | ||
+**I pledge that I did not plagiarize any of my Free Code Camp work, and that I am OK with any random auditing Free Code Camp may do to confirm this.** |
@@ -0,0 +1,17 @@ | ||
+--- | ||
+title: Adding Environment Variables | ||
+order: 5 | ||
+--- | ||
+# In Windows | ||
+ | ||
+### Via GUI | ||
+ | ||
+1. Download [Varpanel](http://implbits.com/products/varpanel/). | ||
+2. Open Varpanel. | ||
+3. In PATH variable, add the relevant path (for example). | ||
+ | ||
+![](http://i.imgur.com/RqgGcf5.gif) | ||
+ | ||
+## Via Command Line | ||
+ | ||
+Refer to [this answer](http://superuser.com/a/284351/275797) on Super User. |
@@ -0,0 +1,17 @@ | ||
+--- | ||
+title: Accessing the database from your frontend | ||
+order: 5 | ||
+--- | ||
+You must have noticed in **main.controller.js** how *things* were retrieved from the database and displayed: | ||
+ | ||
+~~~javascript | ||
+ $http.get('/api/things').success(function(awesomeThings){ | ||
+ $scope.awesomeThings = awesomeThings; | ||
+}); | ||
+ | ||
+~~~ | ||
+ | ||
+What this does is call the api with a “get” request, which is then routed by **/server/api/thing/index.js** to the *exports.index* function in **thing.controller.js**. You’ll also notice in **main.controller.js** that there are included examples of *$http.post* and *$http.delete* functions too! How nice! | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Fixing-exports.update) | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Seed-data) |
@@ -0,0 +1,13 @@ | ||
+--- | ||
+title: Backend file structure | ||
+order: 5 | ||
+--- | ||
+Your app’s backend api that interacts with your database is located in **/server/api** | ||
+Let’s take a look at **/server/api/thing**: | ||
+ | ||
+1. **index.js**: this file routes the $http API requests made from your app’s front-end to the appropriate function in **thing.controller.js ** | ||
+2. **thing.controller.js**: Here is where we actually deal with the database! Take a minute to look through here and figure out what’s going on. These functions will: return all items in a collection, return a single item from a collection when passed its id, post an item to a collection, update an item in the collection (this doesn’t really work as intended out of the box, we're going to fix that in a minute), and of course, delete an item from the collection. | ||
+3. **thing.model.js**: Here, the actual structure of a *thing* object is defined. You can add or remove any fields you want from the *thing* model, and as long as they’re syntactically correct they won’t break anything, even if there are *things* with different schemas in your database already. But! You don’t just have to edit the *thing* model to make a new type of collection, because generator-angular-fullstack can do it for you! | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Grunt) | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Creating-a-new-API-endpoint) |
@@ -0,0 +1,13 @@ | ||
+--- | ||
+title: Bonus SocketIO | ||
+order: 5 | ||
+--- | ||
+If you've gotten to the Stock Charting basejump you may have noticed that the bonus criteria is to have your stock list live update across clients. This can be accomplished with SocketIO, but that’s not all SocketIO can do. Remember earlier, I mentioned that when using *$http.post* you had to update your local array with the database's version of the item you were posting? SocketIO keeps a user’s browser environment synced with your database in realtime. This has two practical upshots: | ||
+ | ||
+1. You no longer have to manually update your local data with database data; it is all managed automatically | ||
+2. You can push database changes live to users on different machines all at the same time | ||
+ | ||
+Even better, if you just include SocketIO when prompted during the yeoman angular-fullstack setup, there is absolutely no work involved to include it. It works out of the box, has a working demo on the **main/** route, and you can learn how to use it yourself by simply looking at how they include it in **main.controller.js** (so I won’t go any further into detail). | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/isLoggedInAsync()) | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Epilogue) |
@@ -0,0 +1,13 @@ | ||
+--- | ||
+title: Creating a new API endpoint | ||
+order: 5 | ||
+--- | ||
+Your app’s backend api that interacts with your database is located in **/server/api** | ||
+Let’s take a look at **/server/api/thing**: | ||
+ | ||
+1. **index.js**: this file routes the $http API requests made from your app’s front-end to the appropriate function in **thing.controller.js ** | ||
+2. **thing.controller.js**: Here is where we actually deal with the database! Take a minute to look through here and figure out what’s going on. These functions will: return all items in a collection, return a single item from a collection when passed its id, post an item to a collection, update an item in the collection (this doesn’t really work as intended out of the box, we're going to fix that in a minute), and of course, delete an item from the collection. | ||
+3. **thing.model.js**: Here, the actual structure of a *thing* object is defined. You can add or remove any fields you want from the *thing* model, and as long as they’re syntactically correct they won’t break anything, even if there are *things* with different schemas in your database already. But! You don’t just have to edit the *thing* model to make a new type of collection, because generator-angular-fullstack can do it for you! | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Grunt) | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Creating-a-new-API-endpoint) |
@@ -0,0 +1,16 @@ | ||
+--- | ||
+title: Creating a new directive | ||
+order: 5 | ||
+--- | ||
+Do you remember custom directives from the shaping up with angular course? You can also make a custom directive! | ||
+ | ||
+ >> yo angular-fullstack:directive newdirective | ||
+ | ||
+And if you need an html template for your custom directive (maybe you’re just making a directive to clean up your HTML code), tell it to make an html file when it prompts you to and you'll be able to include the contents of that template anywhere in your app with: | ||
+ | ||
+~~~html | ||
+<newdirective></newdirective> | ||
+~~~ | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Creating-a-new-route) | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Grunt) |
@@ -0,0 +1,14 @@ | ||
+--- | ||
+title: Creating a new route | ||
+order: 5 | ||
+--- | ||
+ >> yo angular-fullstack:route newpage | ||
+ Typing the above into your command-line will generate a **newpage/** route for your app! It automatically generates all the necessary files within your **/client/app/newpage** folder, like your **/client/app/main** folder, with a **newpage.controller.js**, **newpage.controller.spec.js**, **newpage.js**, and **newpage.html**. These all pretty much behave like the ones in the **main/** route. If you’re accessing the database in your newpage controller, you’ll want to add *$http* to the list of dependencies in **newpage.controller.js** the same way it’s included in **main.controller.js**: | ||
+ | ||
+~~~javascript | ||
+angular.module('myApp') | ||
+ .controller('MainCtrl', function ($scope, $http) { ... | ||
+~~~ | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Frontend-file-structure) | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Creating-a-new-directive) |
@@ -0,0 +1,34 @@ | ||
+--- | ||
+title: Dynamic URLs using $routeParams | ||
+order: 5 | ||
+--- | ||
+What if you have a lot of users posting *things* to your website? Maybe your users want to have a profile, or a wall, of the *things* they’ve posted, and they want to be able to share it with their friends with a url? You can do that, no biggie! | ||
+ | ||
+Let’s say you used | ||
+ | ||
+ >> yo angular-fullstack:route wall | ||
+ | ||
+to generate a <a href="#">http://myapp.wherever.com/wall/</a> route for your users. You want a link to <a href="#">http://myapp.wherever.com/wall/someUsername</a> to show a specific user’s *things*. | ||
+Browse to **/client/app/wall/wall.js** and notice that it detects what URL the user is requesting before acting on it: | ||
+ | ||
+~~~javascript | ||
+$routeProvider.when('/wall', … | ||
+~~~ | ||
+You can customize that path to catch when a user is trying to see a profile associated with a specific username like so: | ||
+ | ||
+~~~javascript | ||
+$routeProvider.when('/wall/:username', … | ||
+~~~ | ||
+The colon before "username" indicates that this is a variable, which is then passed to the *$routeParams* module. In **wall.controller.js**, include *$routeParams*: | ||
+ | ||
+~~~javascript | ||
+.controller('WallCtrl', function ($scope, $routeParams) { … | ||
+~~~ | ||
+Then later on in **wall.controller.js**, you can see what username was requested in the URL by referring to the variable generated by *$routeProvider* using something like | ||
+ | ||
+~~~javascript | ||
+var wallOwner = $routeParams.username; | ||
+~~~ | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Quick-tip-keep-data-in-sync) | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/More-useful-APIs) |
@@ -0,0 +1,17 @@ | ||
+--- | ||
+title: Epilogue | ||
+order: 5 | ||
+--- | ||
+If you have any issues not covered in this guide: | ||
+ | ||
+1. google google google google duckduckgo | ||
+2. bug @freecodecamp and me (@clnhll) on twitter | ||
+3. did you miss a semicolon? a comma? | ||
+4. make a big loud stink in the freecodecamp help gitter. | ||
+ | ||
+If you notice any inaccuracies or bad coding practices in this guide, please let me know ASAP! | ||
+ | ||
+I believe in you! | ||
+-[clnhll](https://github.com/clnhll) | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Bonus-SocketIO) |
@@ -0,0 +1,18 @@ | ||
+--- | ||
+title: Fixing exports.update | ||
+order: 5 | ||
+--- | ||
+As it turns out, in **thing.controller.js** as well as in any other endpoints you may generate, the *exports.update* function that is called when you make an *$http.put* call from your frontend to modify an existing database object is broken. This is a <a href="https://github.com/DaftMonk/generator-angular-fullstack/issues/310">known issue</a>, and can be fixed by changing the following line: | ||
+ | ||
+~~~javascript | ||
+// Updates an existing thing in the DB. | ||
+exports.update = function(req, res) { | ||
+... | ||
+ var updated = _.extend(thing, req.body); | ||
+ // change _.merge to _.extend | ||
+... | ||
+ }; | ||
+~~~ | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Creating-a-new-API-endpoint) | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Accessing-the-database-from-your-frontend) |
@@ -0,0 +1,15 @@ | ||
+--- | ||
+title: Frontend file structure | ||
+order: 5 | ||
+--- | ||
+First things first: All your user-facing files and angular files are in **/client/app/** | ||
+ | ||
+1. **app.js**: defines your app and includes some basic app-wide functions, you probably don’t really need to mess with it unless you’re trying to add more dependencies to your app. We’re not gonna worry about that right now. | ||
+2. **app.css**: an app-wide stylesheet, you can put styles here if you want but I’d recommend you put them in **main/main.css**, as these styles are also app-wide. | ||
+3. **main/**: this folder contains what the user sees first when they load up your site. **main.html** is the page template, **main.js** routes the user to **main.html** when the user goes to the top level directory of your website—that is, <a href="#">http://yourapp.wherever.itis/</a> with no <a href="#">/other/url/hierarchy</a>. You’ll also learn soon that you can define your app’s <a href="#">/url/heirarchy/fairly/arbitrarily</a>. You won’t really need to edit **main.js** or **main.controller.spec.js**, so let's not worry about those right now. If you look through the **main.html** file you’ll see it uses *ng-repeat* to show *things* in *awesomeThings*. Where does it get *awesomeThings*? | ||
+4. **main/main.controller.js**: all of the javascript functions you want to use to interact directly with the user go here! You’ll put functions here to interact with your API, refresh views for your user, etc. Here, *awesomeThings* are pulled from your database and added to the local scope so your HTML view can display them! How cool! We’ll get to adding custom objects to your database in a minute. | ||
+ | ||
+Great! Now you know how to interact with the user! But what if you want your app to have another page that does something else? Maybe **main.html** shows the home page, but you want a page that shows a form to add a poll? maybe <a href="#">http://yourapp.wherever.itis/newpage</a>? This is where the yeoman generator comes in handy. | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Guide-to-Basejumps-Table-of-Contents/) | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Creating-a-new-route) |
@@ -0,0 +1,19 @@ | ||
+--- | ||
+title: Get info about the current user | ||
+order: 5 | ||
+--- | ||
+You may have noticed if you opened up **/client/app/admin/admin.controller.js** that it calls the *Auth* module like so: | ||
+ | ||
+~~~javascript | ||
+.controller('AdminCtrl', function ($scope, $http, Auth … | ||
+~~~ | ||
+You can include Auth in your other controllers the same way. It’s pretty useful to have *Auth* available in your controller to detect if a user is logged in, or to get information about the current user. In the body of your controller you can add | ||
+ | ||
+~~~javascript | ||
+$scope.getCurrentUser = Auth.getCurrentUser; | ||
+$scope.isLoggedIn = Auth.isLoggedIn; | ||
+~~~ | ||
+And then you can use *isLoggedIn()* or *getCurrentUser()* in the HTML view for your controller! | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/More-useful-APIs) | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Restrict-a-page-to-authenticated-users) |
@@ -0,0 +1,8 @@ | ||
+--- | ||
+title: Grunt | ||
+order: 5 | ||
+--- | ||
+Whenever you create a new route or directive, you have to use `control+c` in your *grunt* terminal window to quit the grunt process and re-run `grunt serve` for your new route/directive to be included in your project's **index.html**. Sometimes *grunt* can be a little finnicky and refuses to run if it thinks something is wrong with your project. Obviously you should try to fix the problem, but grunt's errors aren't very helpful so don't worry too much—grunt usually will still run totally fine with the command `grunt serve --force`. | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Creating-a-new-directive) | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Backend-file-structure) |
@@ -0,0 +1,13 @@ | ||
+--- | ||
+title: Intro to Yeoman Angular Fullstack Basejumps | ||
+order: 5 | ||
+--- | ||
+> Hey FreeCodeCampers! This guide is here to help you navigate creating your first basejump. When I encountered the first basejump, I had no idea what was going on and spent weeks learning all of these things myself. Everything here is stuff I wish I had known coming into the basejumps. Oh and by the way, if you have a question that isn't answered by this guide, that's an issue, and you should report it as an issue to this repository! —[@clnhll](http://twitter.com/clnhll) | ||
+ | ||
+Yeoman is a tool that allows you to generate barebones apps based on different software stacks using “generator” packages made by developers who want to make your life easier. These packages streamline your time developing and deploying websites using your platform of choice. We’re using a full-stack MEAN (MongoDB, ExpressJS, AngularJS, NodeJS) generator called generator-angular-fullstack by DaftMonk (https://github.com/DaftMonk/generator-angular-fullstack). | ||
+ | ||
+Once you’ve completed the Waypoint: Get Set for Basejumps, use this guide to navigate the base structure of your new app and learn how to interact with the database as well as the user. | ||
+ | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Guide-to-Basejumps-Table-of-Contents) | ||
+ | ||
+Sourced from (https://github.com/clnhll/guidetobasejumps) with permission. |
@@ -0,0 +1,21 @@ | ||
+--- | ||
+title: isLoggedInAsync() | ||
+order: 5 | ||
+--- | ||
+Let's say you have a public page, but if the user is logged in you want to show special information to them. You'll need to detect if a user is logged in before you make an *$http* call, right? It’s not guaranteed that this will work, because *isLoggedIn()* is actually an async call. If you want to force something to wait until after *isLoggedIn()* is successful before it gets called, you should include *Auth.isLoggedInAsync*: | ||
+ | ||
+~~~javascript | ||
+$scope.isLoggedInAsync = Auth.isLoggedInAsync; | ||
+~~~ | ||
+ | ||
+*isLoggedInAsync* takes a callback function as an input, and passes the callback function a *true* boolean if the user is logged in, and a *false* if the user is not. You can call it like so: | ||
+ | ||
+~~~javascript | ||
+$scope.isLoggedInAsync(callback(bool) { | ||
+ if (bool) { /** do thing if they’re logged in **/ } | ||
+ else { /** do different thing if they’re not logged in **/ } | ||
+}); | ||
+~~~ | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Restrict-a-page-to-authenticated-users) | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Bonus-SocketIO) |
@@ -0,0 +1,35 @@ | ||
+--- | ||
+title: More useful APIs | ||
+order: 5 | ||
+--- | ||
+There are two more things you have to do before this to be useful to you, however. Say you want to show all the *things* associated with the username requested with that page: you must first | ||
+ | ||
+1. Have a “username” or “owner” field in your *thing* schema at **/server/api/thing/thing.model.js** | ||
+2. Write a custom route in **/server/api/thing/index.js** to catch a request for a specific username. The request from your frontend might look something like: | ||
+ | ||
+~~~javascript | ||
+ $http.get('/api/things/' + username).success( … | ||
+ | ||
+~~~ | ||
+so you’ll add a line into your **index.js** like: | ||
+ | ||
+```javascript | ||
+ | ||
+router.get('/:user', controller.indexUser); | ||
+``` | ||
+ and then in **thing.controller.js** you’ll write an *exports.indexUser* function like so: | ||
+ | ||
+~~~javascript | ||
+exports.indexUser = function(req, res) { | ||
+ Thing.find({owner:req.params.user}, function (err, things) { | ||
+ if(err) return res.send(500, err); | ||
+ res.json(200, things); | ||
+ }); | ||
+}; | ||
+~~~ | ||
+ | ||
+ | ||
+Warning!!! this method only works right if usernames are absolutely unique between users. The default authentication system that comes with the angular-fullstack generator does not have unique usernames, so you’re probably better off using the *user._id* field to determine unique users in your database for now, unless you want to implement unique user names yourself by altering your **/api/user/user.model.js**, **/api/user/user.controller.js**, and your **/app/client/account/signup/signup.controller.js**. Thankfully, you should know how to go about doing all that after reading this guide! | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Dynamic-URLs-using-%24routeParams) | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Get-info-about-the-current-user) |
@@ -0,0 +1,31 @@ | ||
+--- | ||
+title: Quick tip keep data in sync | ||
+order: 5 | ||
+--- | ||
+Say you want something to show up on the user view when you add it to the database. A new *thing* object will instantly show up in an *ng-repeat* loop in your HTML view if you simply add it to your local array with | ||
+ | ||
+~~~javascript | ||
+ | ||
+$scope.awesomeThings.push(newThing); | ||
+~~~ | ||
+ | ||
+But you’ll still need to add it to your database collection. Add it to your collection with | ||
+ | ||
+~~~javascript | ||
+ | ||
+$http.post('/api/things', newThing); | ||
+ | ||
+~~~ | ||
+But wait! You’ll soon realize that while all the other things in your *$scope.awesomeThings* array have unique ids assigned by MongoDB (under the *thing.\_id* property), your *newThing* object will not, which will make it hard for you at some point to make database actions on it (deleting it from your database requires you to use its *._id* property). So what you’ll want to do after you add it to your *$scope.awesomeThings* array (because we want it to show up on the user’s page immediately). Altogether, your code to add a newThing to your local array and database will look like: | ||
+ | ||
+~~~javascript | ||
+$scope.awesomeThings.push(newThing); | ||
+$http.post('/api/things', newThing).success(function(thatThingWeJustAdded) { | ||
+ $scope.awesomeThings.pop(); // let's lose that id-lacking newThing | ||
+ $scope.awesomeThings.push(thatThingWeJustAdded); // and add the id-having newThing! | ||
+}; | ||
+~~~ | ||
+This updates the local array for seemingly instant results for your user and then syncs it to your database and updates the local array in the background with the database’s version of your *newThing* object, unique *._id* and all. Notice the callback we pass to the *success* function receives the new *thing* back from the database as an argument! This way you can easily add it back to your local scope without too much overhead. | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Seed-data) | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Dynamic-URLs-using-$routeParams) |
@@ -0,0 +1,19 @@ | ||
+--- | ||
+title: Restrict a page to authenticated users | ||
+order: 5 | ||
+--- | ||
+Let's say you have a route that you want to restrict to logged-in users; maybe you have a <a href="#">/profile</a> page that lets your users fill in some information about themselves, but it wouldn't work if they weren't logged in. Open **/client/app/profile/profile.js**, and add `authenticate: true` to the options passed to *$routeProvider.when* like so: | ||
+ | ||
+~~~javascript | ||
+ $routeProvider | ||
+ .when('/profile', { | ||
+ templateUrl: 'app/profile/profile.html', | ||
+ controller: 'ProfileCtrl', | ||
+ authenticate: true // restrict to authenticated users | ||
+ }); | ||
+~~~ | ||
+ | ||
+This way, if the user isn't authenticated when they try to access the <A href="#">/profile</a> page, they'll be redirected to your login screen to authenticate before continuing to their profile page. | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Get-info-about-the-current-user) | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/isLoggedInAsync()) |
@@ -0,0 +1,10 @@ | ||
+--- | ||
+title: Seed data | ||
+order: 5 | ||
+--- | ||
+The *things* that show up on your app's main view are part of some seed data that is added to your database (including your test and admin users) every time you restart your app (by running `grunt serve` in the command line). This data is defined in **/server/config/seed.js**. | ||
+ | ||
+You can add, remove, or change data in this file, and it will be written to your database, overwriting any duplicates the next time you run `grunt serve`. If an object defined in **seed.js** is overwritten, the database will assign a new *.\_id* property to it (we'll cover *.\_id* properties in the next section), which may give you some issues later on in testing. To avoid this, you can turn off seeding by setting `seedDB: false` in **/server/config/environment/development.js**. | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Accessing-the-database-from-your-frontend) | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Quick-tip:-keep-data-in-sync) |
@@ -0,0 +1,35 @@ | ||
+--- | ||
+title: Guide to Basejumps Table of Contents | ||
+order: 5 | ||
+--- | ||
+### Table of contents | ||
+* Part 1: Frontend | ||
+ - [Frontend file structure](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Frontend-file-structure) | ||
+ - [Creating a new route](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Creating-a-new-route) | ||
+ - [Creating a new directive](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Creating-a-new-directive) | ||
+ - [Grunt](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Grunt) | ||
+* Part 2: Backend | ||
+ - [Backend file structure](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Backend-file-structure) | ||
+ - [Creating a new API endpoint](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Creating-a-new-API-endpoint) | ||
+ - [Fixing exports.update](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Fixing-exports.update) | ||
+* Part 3: Interfacing Between Frontend & Backend | ||
+ - [Accessing the database from your frontend](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Accessing-the-database-from-your-frontend) | ||
+ - [Seed Data](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Seed-data) | ||
+ - [Quick tip: keep data in sync](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Quick-tip-keep-data-in-sync) | ||
+* Part 4: Dynamic URLs using $routeParams, more useful APIs | ||
+ - [Dynamic URLS using $routeParams](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Dynamic-URLs-using-$routeParams) | ||
+ - [More Useful APIs](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/More-useful-APIs) | ||
+* Part 5: Auth, isLoggedInAsync() | ||
+ - [Get info about the current user](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Get-info-about-the-current-user) | ||
+ - [Restrict a page to authenticated users](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Restrict-a-page-to-authenticated-users) | ||
+ - [isLoggedInAsync()](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/isLoggedInAsync()) | ||
+* [Bonus: SocketIO](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Bonus-SocketIO) | ||
+* [Epilogue](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Epilogue) | ||
+ | ||
+### Legend | ||
+**/bolded/names/with.extensions** are directories and files in the project file structure | ||
+<a href="#">highlighted.items/are/hypothetical</a> URLs that allow access to different pages in your app | ||
+*italicizedItems* are function and object names within your code | ||
+ | ||
+[PREVIOUS](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Intro-to-Yeoman-Angular-Fullstack-Basejumps) | ||
+[NEXT](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Frontend-file-structure) |
@@ -0,0 +1,22 @@ | ||
+--- | ||
+title: How to use the Free Code Camp Wiki | ||
+order: 1 | ||
+--- | ||
+ | ||
+The Free Code Camp wiki exists to provide clear answers to common questions about Free Code Camp, learning to code, and getting a coding job. Please feel free to add relevant content to the wiki. Just be sure to search for a topic and see if it already exists before starting a new page. | ||
+ | ||
+Individual Wiki's can be accessed from the main page, or from other linked Wiki pages. | ||
+ | ||
+You can also access them from Gitter using Camperbot | ||
+ | ||
+- #### **`help $topic`** | ||
+ find related materials to that topic, usually a page from the [wiki](https://github.com/FreeCodeCamp/freecodecamp/wiki) | ||
+ examples: `help css` `help bootstrap` | ||
+ | ||
+- #### `topics` | ||
+ show the list of topics. | ||
+ | ||
+- #### `find $topic` | ||
+ this will search for entries that include `$topic` in the title. We'll add fulltext search in | ||
+ future. | ||
+ examples: `find wiki` |
@@ -0,0 +1,48 @@ | ||
+--- | ||
+title: Start Here | ||
+order: 0 | ||
+--- | ||
+ | ||
+## If you're new to Free Code Camp, or just new to the wiki, start here: | ||
+ | ||
+### Curriculum | ||
+ | ||
+* [What you will learn, and in what sequence you will learn it](http://beta.freecodecamp.com/wiki/docs/What-you-will-learn,-and-in-what-sequence-you-will-learn-it) | ||
+ | ||
+* [How long does Free Code Camp take?](http://beta.freecodecamp.com/wiki/docs/How-Long-Free-Code-Camp-Takes) | ||
+ | ||
+* [What are these brownie points?](http://beta.freecodecamp.com/wiki/docs/Brownie-Points) | ||
+ | ||
+* [The Front End Development Certificate](http://beta.freecodecamp.com/wiki/docs/Free-Code-Camp-Front-End-Development-Certificate) | ||
+ | ||
+* [The Full Stack Development Certificate](http://beta.freecodecamp.com/wiki/docs/Free-Code-Camp-Full-Stack-Development-Certificate) | ||
+ | ||
+* [Guide to Basejumps](http://beta.freecodecamp.com/wiki/docs/Guide-to-Basejumps-Table-of-Contents) | ||
+ | ||
+* [Basejump Resources](http://beta.freecodecamp.com/wiki/docs/Basejump-Resources) | ||
+ | ||
+* [Why JavaScript?](http://beta.freecodecamp.com/wiki/docs/Why-does-Free-Code-Camp-use-JavaScript-instead-of-Ruby-or-Python) | ||
+ | ||
+### Community | ||
+ | ||
+* [Code of Conduct](http://beta.freecodecamp.com/wiki/docs/Code-of-Conduct) | ||
+ | ||
+* [Camper News](http://beta.freecodecamp.com/wiki/docs/Camper-News) | ||
+ | ||
+* [Campsites](http://beta.freecodecamp.com/wiki/docs/Campsites) | ||
+ | ||
+* [Official Chat Rooms](http://beta.freecodecamp.com/wiki/docs/Official-Free-Code-Camp-Chat-Rooms) | ||
+ | ||
+* [How to use CamperBot](http://beta.freecodecamp.com/wiki/docs/camperbot) | ||
+ | ||
+* [Join the LinkedIn Community and Find Alumni](http://beta.freecodecamp.com/wiki/docs/How-to-add-Free-Code-Camp-to-my-LinkedIn-profile) | ||
+ | ||
+* [Stream your Coding Session on our Twitch.tv page](http://beta.freecodecamp.com/wiki/docs/How-you-can-stream-your-live-coding-sessions-on-the-Free-Code-Camp-Twitch.tv-channel) | ||
+ | ||
+### Nonprofit | ||
+ | ||
+* [How Nonprofit Projects Work](http://beta.freecodecamp.com/wiki/docs/How-FreeCodeCamp-Nonprofit-Projects-work) | ||
+ | ||
+* [Natural Language Requirements](http://beta.freecodecamp.com/wiki/docs/Free-Code-Camp-completion-language-requirements) | ||
+ | ||
+* [Resources that Free Code Camp recommends to Nonprofits Who Don't Qualify](http://beta.freecodecamp.com/wiki/docs/Other-resources-that-Free-Code-Camp-recommends-to-nonprofits) |
@@ -0,0 +1,20 @@ | ||
+--- | ||
+title: "Welcome to the Free Code Camp Wiki!" | ||
+--- | ||
+ | ||
+Our open source community's Wiki focuses on answering your questions about learning to code and getting a coding job. We also cover in detail our: | ||
+- Curriculum | ||
+- Local Campsite Communities | ||
+- Nonprofit Projects | ||
+ | ||
+![An illustration of CamperBot](http://i.imgur.com/gyJwzkx.png) | ||
+ | ||
+The best way to access this wiki is via [CamperBot](http://beta.freecodecamp.com/wiki/docs/camperbot), located in our Gitter channels. CamperBot is a community designed tool useful for accessing our wiki content without ever leaving Gitter. | ||
+ | ||
+To contribute a wiki article for any of the bonfires, please use this [template](http://beta.freecodecamp.com/wiki/docs/Bonfire-Wiki-Template). This is essential for [@CamperBot](https://github.com/camperbot) to retrieve the article. Bonfire articles that do not use this template will be removed. | ||
+ | ||
+You will then need to clone the [wiki](http://beta.freecodecamp.com/wiki/docs) and create a branch where you will make your changes and submmit a pull request to be merged before the changes goes live on the wiki. This is to filter any spam content or damage to **our** wiki. | ||
+ | ||
+If you have questions about contributing to the Free Code Camp Wiki message [@Rafase282 in Gitter](https://gitter.im/Rafase282). | ||
+ | ||
+We look forward to collaborating with you on expanding and improving this wiki! |
25
utils/typography.js
@@ -0,0 +1,25 @@ | ||
+import Typography from 'typography'; | ||
+ | ||
+const options = { | ||
+ baseFontSize: '16px', | ||
+ baseLineHeight: '24px', | ||
+ bodyFontFamily: '"Helvetica Neue", "Segoe UI", Helvetica, Arial, sans-serif', | ||
+ headerFontFamily: '"Helvetica Neue", "Segoe UI", Helvetica, Arial, sans-serif', | ||
+ bodyWeight: 300, | ||
+ headerWeight: 600, | ||
+ boldWeight: 600, | ||
+ modularScales: [ | ||
+ { | ||
+ "scale": "minor third" | ||
+ } | ||
+ ] | ||
+} | ||
+ | ||
+const typography = new Typography(options) | ||
+ | ||
+// Hot reload typography in development. | ||
+if (process.env.NODE_ENV !== "production") { | ||
+ typography.injectStyles() | ||
+} | ||
+ | ||
+export default typography |
1
wiki-gh-pages
@@ -0,0 +1 @@ | ||
+Subproject commit 1745e53615ed1ff86037aeca94d37e74701cf4d0 |
1
wiki-master
@@ -0,0 +1 @@ | ||
+Subproject commit 9896da063a780127437235826f10fdff241c3beb |
20
wrappers/md.jsx
@@ -0,0 +1,20 @@ | ||
+import React from 'react'; | ||
+import DocumentTitle from 'react-document-title'; | ||
+import typography from 'utils/typography'; | ||
+const { rhythm } = typography; | ||
+ | ||
+module.exports = React.createClass({ | ||
+ render: function() { | ||
+ var post, rhythm; | ||
+ post = this.props.page.data; | ||
+ | ||
+ return ( | ||
+ <DocumentTitle title={`${post.title} | ${this.props.config.siteTitle}`}> | ||
+ <div className="markdown"> | ||
+ <h1>{post.title}</h1> | ||
+ <div dangerouslySetInnerHTML={{__html: post.body}}/> | ||
+ </div> | ||
+ </DocumentTitle> | ||
+ ); | ||
+ } | ||
+}); |
0 comments on commit
0672f65