├── .gitignore
├── README.md
├── calc
├── .babelrc
├── .eslintrc
├── bundle.js
├── calcapp.js
├── entry.js
├── index.html
├── package.json
├── style.css
└── webpack.config.js
├── ee_forum
├── .babelrc
├── .eslintignore
├── .eslintrc.json
├── data
│ ├── Posts.json
│ └── Users.json
├── devServer.js
├── index.html
├── package.json
├── public
│ └── .keep
├── server
│ ├── api.js
│ ├── app.js
│ └── run.js
├── src
│ ├── components
│ │ ├── Header.js
│ │ ├── LoginPage.js
│ │ ├── NewPostPage.js
│ │ ├── NotFoundPage.js
│ │ ├── PostListPage.js
│ │ ├── UserInfoPage.js
│ │ └── UserStat.js
│ ├── index.js
│ ├── routes.js
│ └── styles
│ │ ├── Header.css
│ │ ├── LoginPage.css
│ │ ├── NewPostPage.css
│ │ ├── PostListPage.css
│ │ ├── UserInfoPage.css
│ │ └── UserStat.css
├── webpack.config.dev.js
└── webpack.config.prod.js
├── hw1
├── index.html
├── styles.css
└── todo.js
├── hw11
└── script.sql
├── hw2
├── counter.js
├── curry_sum.js
├── getType.js
└── index.html
├── hw3
├── .babelrc
├── .eslintrc
├── bundle.js
├── entry.js
├── index.html
├── package.json
├── style.css
├── todoapp.js
└── webpack.config.js
├── hw4
├── .babelrc
├── .eslintrc
├── dist
│ └── bundle.js
├── index.html
├── package.json
├── src
│ ├── component
│ │ ├── ChatApp.js
│ │ ├── MessageItem.js
│ │ └── ThreadItem.js
│ ├── entry.js
│ └── style.css
└── webpack.config.js
├── hw5
├── package.json
├── public
│ └── example.jpg
├── server.js
└── views
│ ├── error.nunjucks
│ ├── index.html
│ └── index.nunjucks
├── hw6
├── .babelrc
├── .eslintrc
├── dist
│ └── bundle.js
├── image
│ ├── chen.jpg
│ ├── chiang1.jpg
│ ├── chiang2.jpg
│ ├── fun.jpg
│ ├── lee.jpg
│ ├── ma.png
│ └── tsai.png
├── index.html
├── package.json
├── src
│ ├── component
│ │ ├── ChatApp.js
│ │ ├── MessageItem.js
│ │ └── ThreadItem.js
│ ├── entry.js
│ └── style.css
└── webpack.config.js
├── hw7
├── .babelrc
├── .eslintrc
├── dist
│ └── bundle.js
├── index.html
├── package.json
├── server.js
├── src
│ ├── component
│ │ ├── ChatApp.js
│ │ ├── MessageItem.js
│ │ ├── ThreadItem.js
│ │ └── UserData.js
│ ├── entry.js
│ ├── pages
│ │ ├── NotFound.js
│ │ ├── Root.js
│ │ └── User.js
│ └── style.css
├── webpack.config.dev.js
└── webpack.config.js
├── hw8
├── .babelrc
├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── README.md
├── devServer.js
├── index.html
├── package.json
├── public
│ ├── .keep
│ ├── bundle.js
│ ├── bundle.js.map
│ ├── style.css
│ └── style.css.map
├── server
│ ├── api.js
│ ├── app.js
│ └── run.js
├── src
│ ├── components
│ │ ├── NotFoundPage.js
│ │ ├── SingleUserPage.css
│ │ ├── SingleUserPage.js
│ │ ├── UsersPage.css
│ │ └── UsersPage.js
│ ├── index.js
│ └── routes.js
├── webpack.config.dev.js
└── webpack.config.prod.js
├── index.html
├── index
├── images
│ ├── body-bg.png
│ ├── highlight-bg.jpg
│ ├── hr.png
│ ├── octocat-icon.png
│ ├── tar-gz-icon.png
│ └── zip-icon.png
├── javascripts
│ └── main.js
└── stylesheets
│ ├── github-dark.css
│ ├── print.css
│ ├── selfdefine.css
│ └── stylesheet.css
└── params.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
18 | .grunt
19 |
20 | # node-waf configuration
21 | .lock-wscript
22 |
23 | # Compiled binary addons (http://nodejs.org/api/addons.html)
24 | build/Release
25 |
26 | # Dependency directories
27 | node_modules
28 | jspm_packages
29 |
30 | # Optional npm cache directory
31 | .npm
32 |
33 | # Optional REPL history
34 | .node_repl_history
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #Web Programming Project
2 |
3 | A central repo for all assignments.
--------------------------------------------------------------------------------
/calc/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react", "es2015", "stage-0"]
3 | }
--------------------------------------------------------------------------------
/calc/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | }
--------------------------------------------------------------------------------
/calc/calcapp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class CalcApp extends React.Component {
4 | constructor(props) {
5 | super(props);
6 | this.state = {
7 | num: "0",
8 | tempnum: 0,
9 | mode: 0,
10 | valid: true,
11 | };
12 | this.resetState = this.resetState.bind(this);
13 | this.genAppend = this.genAppend.bind(this);
14 | this.genMode = this.genMode.bind(this);
15 | this.calculate = this.calculate.bind(this);
16 | this.invert = this.invert.bind(this);
17 | this.percent = this.percent.bind(this);
18 | }
19 |
20 | updateState() {
21 | this.setState({
22 | num: this.state.num,
23 | tempnum: this.state.tempnum,
24 | mode: this.state.mode,
25 | valid: this.state.valid,
26 | })
27 | }
28 |
29 | resetState() {
30 | this.state.num = "0";
31 | this.state.mode = 0;
32 | this.state.tempnum = 0;
33 | this.state.valid = true;
34 | this.updateState();
35 | }
36 |
37 | showNotImplemented() {
38 | console.warn('This function is not implemented yet.');
39 | }
40 |
41 | genAppend(num) {
42 | function append() {
43 | if(this.state.num === "0" || this.state.num === "-0") this.state.num = this.state.num.slice(0,-1);
44 | if(!this.state.valid) {
45 | this.state.num = "";
46 | this.state.valid = true;
47 | }
48 | this.state.num += num;
49 | this.updateState();
50 | }
51 | append = append.bind(this);
52 | return append;
53 | }
54 |
55 | genMode(key) {
56 | function mode() {
57 | this.calculate();
58 | if(!key) {
59 | let str = this.state.num;
60 | this.resetState();
61 | this.state.num = str;
62 | }
63 | else this.state.mode = key;
64 | this.updateState();
65 | }
66 | mode = mode.bind(this);
67 | return mode;
68 | }
69 |
70 | calculate() {
71 | if(!this.state.valid) return;
72 | if(this.state.mode === 0) {
73 | this.state.tempnum = +this.state.num;
74 | }
75 | else if(this.state.mode === 1) {
76 | this.state.tempnum += +this.state.num;
77 | }
78 | else if(this.state.mode === 2) {
79 | this.state.tempnum -= +this.state.num;
80 | }
81 | else if(this.state.mode === 3) {
82 | this.state.tempnum *= +this.state.num;
83 | }
84 | else if(this.state.mode === 4) {
85 | this.state.tempnum /= +this.state.num;
86 | }
87 | else if(this.state.mode === 5) return;
88 |
89 | this.state.num = this.state.tempnum.toString();
90 |
91 | this.state.valid = false;
92 | }
93 |
94 | invert() {
95 | if(!this.state.valid) this.state.num = "0";
96 | if(this.state.num[0] !== '-') this.state.num = "-" + this.state.num;
97 | else this.state.num = this.state.num.substr(1);
98 | this.updateState();
99 | }
100 |
101 | percent() {
102 | if(!this.state.valid) this.state.num = "0";
103 | this.state.num = +this.state.num / 100;
104 | this.updateState();
105 | }
106 |
107 | render() {
108 | return (
109 |
110 |
111 |
112 |
{this.state.num}
113 |
114 |
115 | AC
116 | +/-
117 | %
118 | ÷
119 |
120 |
121 | 7
122 | 8
123 | 9
124 | ×
125 |
126 |
127 | 4
128 | 5
129 | 6
130 | -
131 |
132 |
133 | 1
134 | 2
135 | 3
136 | +
137 |
138 |
139 | 0
140 | .
141 | =
142 |
143 |
144 |
145 | );
146 | }
147 | }
148 |
149 |
150 | class CalcButton extends React.Component {
151 | render() {
152 | const { className, children, onClick } = this.props;
153 | return (
154 |
158 | {children}
159 |
160 | );
161 | }
162 | }
163 |
164 | CalcButton.propTypes = {
165 | className: React.PropTypes.string,
166 | children: React.PropTypes.string.isRequired,
167 | onClick: React.PropTypes.func
168 | };
169 |
170 | CalcButton.defaultProps = {
171 | onClick: () => {}
172 | };
173 |
174 |
175 | export default CalcApp;
--------------------------------------------------------------------------------
/calc/entry.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {render} from 'react-dom';
3 | import CalcApp from './calcapp'
4 | import './style.css'
5 |
6 | render(, document.getElementById('root'));
--------------------------------------------------------------------------------
/calc/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CalcApp
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/calc/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "calculator",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "topjohnwu",
10 | "license": "ISC",
11 | "devDependencies": {
12 | "babel-loader": "^6.2.4",
13 | "babel-preset-es2015": "^6.6.0",
14 | "babel-preset-react": "^6.5.0",
15 | "babel-preset-stage-0": "^6.5.0",
16 | "css-loader": "^0.23.1",
17 | "style-loader": "^0.13.1",
18 | "react": "^15.0.1",
19 | "react-dom": "^15.0.1"
20 | },
21 | "dependencies": {
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/calc/style.css:
--------------------------------------------------------------------------------
1 | li {
2 | list-style: none;
3 | }
4 |
5 | a {
6 | text-decoration: none;
7 | }
8 |
9 | a:hover {
10 | text-decoration: none;
11 | cursor: pointer;
12 | }
13 |
14 | /* layout */
15 | .calc-container {
16 | width: 249px;
17 | height: 444px;
18 | margin: auto;
19 | background-color: black;
20 | }
21 |
22 | .calc-output {
23 | height: 139px;
24 | position: relative;
25 | }
26 |
27 | .calc-display {
28 | position: absolute;
29 | bottom: 5px;
30 | right: 15px;
31 | font-size: 50px;
32 | font-family: 'Lato', sans-serif;
33 | color: white;
34 | }
35 |
36 | .calc-row {
37 | height: 61px;
38 | }
39 |
40 | .calc-btn {
41 | cursor: pointer;
42 | display: inline-block;
43 | text-align: center;
44 | vertical-align: top;
45 | width: 60px;
46 | height: 60px;
47 | line-height: 60px;
48 | border: 1px solid #a08c88;
49 | background-color: #c8c9cb;
50 | }
51 |
52 | .calc-btn {
53 | cursor: pointer;
54 | display: inline-block;
55 | text-align: center;
56 | vertical-align: top;
57 | width: 60px;
58 | height: 60px;
59 | line-height: 60px;
60 | border: 1px solid #a08c88;
61 | background-color: #c8c9cb;
62 | }
63 |
64 | .calc-number {
65 | background-color: #d2d3d5;
66 | }
67 |
68 | .calc-number-0 {
69 | width: 122px;
70 | background-color: #d2d3d5;
71 | }
72 |
73 | .calc-operator {
74 | color: white;
75 | background-color: #f58c00;
76 | }
77 |
78 |
79 |
80 | /* clearfix
81 | * http://stackoverflow.com/questions/211383/which-method-of-clearfix-is-best
82 | */
83 | .clearfix:before,
84 | .clearfix:after {
85 | content:"";
86 | display:table;
87 | }
88 | .clearfix:after {
89 | clear:both;
90 | }
91 | .clearfix {
92 | zoom:1; /* For IE 6/7 (trigger hasLayout) */
93 | }
--------------------------------------------------------------------------------
/calc/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | devtool: 'cheap-module-eval-source-map',
3 | entry: './entry', // 進入點
4 | output: {
5 | filename: 'bundle.js', // 輸出的檔案名稱
6 | },
7 | module: {
8 | loaders: [{
9 | test: /\.js$/, // 針對 js 檔
10 | loaders: ['babel'],
11 | exclude: /node_modules/ // 不要處理 3rd party 的 code
12 | }, {
13 | test: /\.css$/, // 針對 css 檔
14 | loaders: ['style', 'css'],
15 | exclude: /node_modules/ // 不要處理 3rd party 的 code
16 | }]
17 | }
18 | };
--------------------------------------------------------------------------------
/ee_forum/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react", "es2015", "stage-0"],
3 | "env": {
4 | "development": {
5 | "presets": ["react-hmre"]
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ee_forum/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | public/bundle.js
3 |
--------------------------------------------------------------------------------
/ee_forum/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extend": "airbnb",
4 | "rules": {
5 | "react/prefer-stateless-function": 0
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/ee_forum/data/Posts.json:
--------------------------------------------------------------------------------
1 | [{"id":0,"op":1,"time":1463640041767,"title":"LOL","content":":)","up":0,"down":0},{"id":1,"op":2,"time":1463642240731,"title":"Good :)","content":"Ahhhhh....\nNice ^ ^","up":0,"down":0}]
--------------------------------------------------------------------------------
/ee_forum/data/Users.json:
--------------------------------------------------------------------------------
1 | [
2 | { "id": 0 },
3 | { "id": 1, "name": "John", "password": "john", "pic": "http://thisismykea2.s3.amazonaws.com/sites/default/files/designs/6995/mr-happy-1310118986.png"},
4 | { "id": 2, "name": "Amy", "password": "amy", "pic": "http://i.imgur.com/tSfIYtw.png" }
5 | ]
--------------------------------------------------------------------------------
/ee_forum/devServer.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console: 0 */
2 | const path = require('path');
3 | const express = require('express');
4 | const webpack = require('webpack');
5 | const proxy = require('proxy-middleware');
6 | const config = require('./webpack.config.dev');
7 | require('./server/run');
8 |
9 | const API_PORT = 8080;
10 | const DEV_PORT = 3000;
11 |
12 | const app = express();
13 | const compiler = webpack(config);
14 |
15 | app.use(require('webpack-dev-middleware')(compiler, {
16 | noInfo: true,
17 | publicPath: config.output.publicPath,
18 | }));
19 |
20 | app.use(require('webpack-hot-middleware')(compiler));
21 |
22 | app.use('/public', express.static('public'));
23 | app.use('/api', proxy(`http://localhost:${API_PORT}/api`));
24 |
25 | app.get('*', (req, res) => {
26 | res.sendFile(path.join(__dirname, 'index.html'));
27 | });
28 |
29 | app.listen(DEV_PORT, (err) => {
30 | if (err) {
31 | console.log(err);
32 | return;
33 | }
34 |
35 | console.log('Listening at http://localhost:3000');
36 | });
37 |
--------------------------------------------------------------------------------
/ee_forum/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | EE Forum
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/ee_forum/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ee_forum",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "lint": "eslint .",
8 | "start": "node devServer",
9 | "build": "NODE_ENV=production webpack --config webpack.config.prod.js",
10 | "start:prod": "NODE_ENV=production node server/run.js",
11 | "test": "echo \"Error: no test specified\" && exit 1"
12 | },
13 | "keywords": [],
14 | "author": "",
15 | "license": "ISC",
16 | "dependencies": {
17 | "babel-polyfill": "^6.8.0",
18 | "body-parser": "^1.15.1",
19 | "classnames": "^2.2.5",
20 | "express": "^4.13.4",
21 | "fs": "0.0.2",
22 | "isomorphic-fetch": "^2.2.1",
23 | "morgan": "^1.7.0",
24 | "react": "^15.0.2",
25 | "react-dom": "^15.0.2",
26 | "react-router": "^2.4.0"
27 | },
28 | "devDependencies": {
29 | "babel-eslint": "^6.0.4",
30 | "babel-loader": "^6.2.4",
31 | "babel-preset-es2015": "^6.6.0",
32 | "babel-preset-react": "^6.5.0",
33 | "babel-preset-react-hmre": "^1.1.1",
34 | "babel-preset-stage-0": "^6.5.0",
35 | "css-loader": "^0.23.1",
36 | "eslint": "^2.9.0",
37 | "eslint-config-airbnb": "^8.0.0",
38 | "eslint-plugin-import": "^1.6.1",
39 | "eslint-plugin-jsx-a11y": "^1.0.4",
40 | "eslint-plugin-react": "^5.0.1",
41 | "extract-text-webpack-plugin": "^1.0.1",
42 | "proxy-middleware": "^0.15.0",
43 | "style-loader": "^0.13.1",
44 | "webpack": "^1.13.0",
45 | "webpack-dev-middleware": "^1.6.1",
46 | "webpack-hot-middleware": "^2.10.0"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/ee_forum/public/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/ee_forum/public/.keep
--------------------------------------------------------------------------------
/ee_forum/server/api.js:
--------------------------------------------------------------------------------
1 | const Router = require('express').Router;
2 | const router = new Router();
3 | const bodyParser = require('body-parser');
4 | const fs = require('fs');
5 | const Users = require('../data/Users.json');
6 | const Posts = require('../data/Posts.json');
7 |
8 | router.use(bodyParser.urlencoded({ extended: false }));
9 | router.use(bodyParser.json());
10 |
11 |
12 | router.post('/login/', function(req, res) {
13 | let user = 0;
14 | for(let i = 0; i < Users.length; ++i) {
15 | if(Users[i].name === req.body.username) {
16 | if(Users[i].password === req.body.password) {
17 | user = i;
18 | break;
19 | }
20 | }
21 | }
22 | if(user)
23 | res.json(Users[user]);
24 | else
25 | res.json(null);
26 | });
27 |
28 | router.get('/users/', function(req, res) {
29 | res.json(Users);
30 | });
31 |
32 | router.get('/users/:id', function(req, res, next) {
33 | if(req.params.id < 0 || req.params.id >= Users.length) {
34 | var err = new Error();
35 | err.status = 404;
36 | err.message = 'This id doesn\'t exist'
37 | next(err);
38 | }
39 | else res.json(Users[req.params.id]);
40 | });
41 |
42 | router.get('/posts/', function(req, res) {
43 | res.json(Posts);
44 | });
45 |
46 | router.post('/posts/', function(req, res) {
47 | req.body.id = Posts.length;
48 | Posts.push(req.body);
49 | fs.writeFile('./data/Posts.json', JSON.stringify(Posts), (err) => {
50 | if (err) throw err;
51 | console.log('Posts saved to Post.json!');
52 | });
53 | res.json(true);
54 | });
55 |
56 | router.use(function(err, req, res, next) {
57 | console.log("error occurs: " + err.message);
58 | res.status(err.status || 500);
59 | res.send(err);
60 | });
61 |
62 | module.exports = router;
63 |
--------------------------------------------------------------------------------
/ee_forum/server/app.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const path = require('path');
3 | const logger = require('morgan');
4 | const api = require('./api');
5 |
6 | const app = express();
7 |
8 | app.use(logger('dev'));
9 | app.use('/public', express.static(path.join(__dirname, '..', 'public')));
10 |
11 |
12 | app.use('/api', api);
13 | app.use('*', (req, res) => {
14 | res.sendFile(path.join(__dirname, '..', 'index.html'));
15 | });
16 |
17 |
18 | // error handlers
19 |
20 | // development error handler
21 | // will print stacktrace
22 | if (app.get('env') === 'development') {
23 | app.use((err, req, res, next) => { // eslint-disable-line no-unused-vars
24 | res.status(err.status || 500);
25 | res.render('error', {
26 | message: err.message,
27 | error: err,
28 | });
29 | });
30 | }
31 |
32 | // production error handler
33 | // no stacktraces leaked to user
34 | app.use((err, req, res, next) => { // eslint-disable-line no-unused-vars
35 | res.status(err.status || 500);
36 | res.render('error', {
37 | message: err.message,
38 | error: {},
39 | });
40 | });
41 |
42 |
43 | module.exports = app;
44 |
--------------------------------------------------------------------------------
/ee_forum/server/run.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console: 0 */
2 | const APIServer = require('./app');
3 |
4 | const API_PORT = 8080;
5 |
6 | APIServer.listen(API_PORT, () => {
7 | console.log(
8 | `API Server is now running on http://localhost:${API_PORT}`
9 | );
10 | });
11 |
--------------------------------------------------------------------------------
/ee_forum/src/components/Header.js:
--------------------------------------------------------------------------------
1 | import React, { Component, PropTypes } from 'react';
2 | import 'babel-polyfill';
3 |
4 | import NotFoundPage from './NotFoundPage';
5 | import LoginPage from './LoginPage';
6 | import PostListPage from './PostListPage';
7 | import UserInfoPage from './UserInfoPage';
8 | import UserStat from './UserStat';
9 |
10 | import '../styles/Header.css'
11 |
12 | export default class Header extends Component {
13 | constructor(context) {
14 | super(context);
15 | this.state = {
16 | user: null,
17 | users: null,
18 | }
19 | this.users = null;
20 | }
21 | static contextTypes = {
22 | router: React.PropTypes.object.isRequired
23 | };
24 | componentWillMount() {
25 | if(!this.state.user)
26 | if(this.props.location.pathname !== "/login")
27 | this.context.router.push('/login');
28 | }
29 | componentDidMount() {
30 | fetch('/api/users')
31 | .then(res => { return res.json(); } )
32 | .then(json => { this.setState( {users: json} ); });
33 | }
34 | setUser(json) {
35 | this.setState( {user: json} );
36 | }
37 | Child() {
38 | const children = React.Children.map(this.props.children,
39 | (child) => React.cloneElement(child, {
40 | user: this.state.user,
41 | users: this.state.users,
42 | setUser: this.setUser.bind(this),
43 | }));
44 | return children;
45 | }
46 | render() {
47 | if(!this.state.users) return null;
48 | return(
49 |
50 |
51 |
{this.context.router.push('/')} }>NTUEESA
52 |
53 |
{this.Child()}
54 |
55 | )
56 | }
57 | }
--------------------------------------------------------------------------------
/ee_forum/src/components/LoginPage.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import 'babel-polyfill';
3 | import fetch from 'isomorphic-fetch';
4 | import classNames from 'classnames'
5 |
6 | import '../styles/LoginPage.css'
7 |
8 | export default class LoginPage extends Component {
9 | constructor(props, context) {
10 | super(props, context);
11 | this.state = {
12 | valid: true,
13 | }
14 | }
15 | static contextTypes = {
16 | router: React.PropTypes.object.isRequired
17 | };
18 | login(event) {
19 | fetch('/api/login', {
20 | method: 'post',
21 | headers: {
22 | 'Accept': 'application/json',
23 | 'Content-Type': 'application/json',
24 | },
25 | body: JSON.stringify({
26 | username: document.getElementById('username').value,
27 | password: document.getElementById('password').value,
28 | }),
29 | })
30 | .then(res => { return res.json(); } )
31 | .then(json => {
32 | if(json) {
33 | this.props.setUser(json);
34 | this.context.router.push('/');
35 | }
36 | else
37 | this.setState( {valid: false} );
38 | })
39 | }
40 |
41 | render() {
42 | return(
43 |
55 | )
56 | }
57 | }
--------------------------------------------------------------------------------
/ee_forum/src/components/NewPostPage.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import 'babel-polyfill';
3 | import fetch from 'isomorphic-fetch';
4 |
5 | import '../styles/NewPostPage.css'
6 |
7 | export default class NewPostPage extends Component {
8 | constructor(props, context) {
9 | super(props, context);
10 | }
11 | static contextTypes = {
12 | router: React.PropTypes.object.isRequired
13 | };
14 | addPost() {
15 | fetch('/api/posts', {
16 | method: 'post',
17 | headers: {
18 | 'Accept': 'application/json',
19 | 'Content-Type': 'application/json',
20 | },
21 | body: JSON.stringify(
22 | { id: null, op: this.props.user.id, time: (new Date()).getTime(),
23 | title: document.getElementById('post-title').value,
24 | content: document.getElementById('post-content').value,
25 | up: 0, down: 0,}),
26 | })
27 | .then(() => this.context.router.push('/') );
28 |
29 | }
30 | render() {
31 | return (
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | )
40 | }
41 | }
--------------------------------------------------------------------------------
/ee_forum/src/components/NotFoundPage.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class NotFoundPage extends Component {
4 | render() {
5 | return (
6 | NotFoundPage
7 | );
8 | }
9 | }
10 |
11 | export default NotFoundPage;
12 |
--------------------------------------------------------------------------------
/ee_forum/src/components/PostListPage.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import 'babel-polyfill';
3 | import fetch from 'isomorphic-fetch';
4 | import classNames from 'classnames'
5 |
6 | import '../styles/PostListPage.css'
7 |
8 | export default class PostListPage extends Component {
9 | constructor(props, context) {
10 | super(props, context);
11 | this.state = {
12 | posts: null,
13 | };
14 | }
15 | static contextTypes = {
16 | router: React.PropTypes.object.isRequired
17 | };
18 |
19 | setPosts(json) {
20 | this.setState( {posts: json} );
21 | }
22 |
23 | printTime(millisec) {
24 | let a = "";
25 | let d = new Date(millisec);
26 | let c = new Date();
27 | if(d.toDateString() !== c.toDateString()) a += (d.toDateString() + ' ');
28 | else a += ('Today ');
29 | a += d.toTimeString().substr(0, 8);
30 | return a;
31 | }
32 |
33 | mapPost(post) {
34 | return (
35 |
36 |
37 |
{post.title}
38 |
{this.printTime(post.time)}
39 |
{'▲' + post.up + '/▼' + post.down}
40 |
41 | {this.context.router.push(`/user/${post.op}`)} }>
44 | {'By: ' + this.props.users[post.op].name}
45 |
46 | {post.content}
47 |
48 |
49 |
50 |
51 |
52 |
53 | )
54 | }
55 |
56 | componentDidMount() {
57 | fetch('/api/posts')
58 | .then(function(res) {
59 | return res.json();
60 | })
61 | .then(this.setPosts.bind(this));
62 | }
63 |
64 | render() {
65 | const users = this.state.users, posts = this.state.posts;
66 | if(users === null || posts === null) return null;
67 | return (
68 |
69 |
70 |
{this.state.posts.map(this.mapPost.bind(this))}
71 |
72 | )
73 | }
74 | }
--------------------------------------------------------------------------------
/ee_forum/src/components/UserInfoPage.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import 'babel-polyfill';
3 |
4 | import '../styles/UserInfoPage.css'
5 |
6 | export default class UserInfoPage extends Component {
7 | render() {
8 | const user = this.props.users[this.props.params.userid];
9 | return (
10 |
11 |

12 |
{user.name}
13 |
14 | )
15 | }
16 | }
--------------------------------------------------------------------------------
/ee_forum/src/components/UserStat.js:
--------------------------------------------------------------------------------
1 | import React, { Component, PropTypes } from 'react';
2 | import 'babel-polyfill';
3 | import fetch from 'isomorphic-fetch';
4 | import NotFoundPage from './NotFoundPage';
5 |
6 | import '../styles/UserStat.css'
7 |
8 | export default class UserStat extends Component {
9 | constructor(props, context) {
10 | super(props, context);
11 | }
12 | static propTypes = {
13 | children: PropTypes.any.isRequired
14 | };
15 | static contextTypes = {
16 | router: React.PropTypes.object.isRequired
17 | };
18 |
19 | Child() {
20 | const children = React.Children.map(this.props.children,
21 | (child) => React.cloneElement(child, {
22 | user: this.props.user,
23 | users: this.props.users,
24 | })
25 | );
26 | return children;
27 | }
28 |
29 | render() {
30 | const user = this.props.user;
31 | if(user === null) return null;
32 | return (
33 |
34 |
35 |

{this.context.router.push(`/user/${user.id}`)}
37 | }/>
38 |
{user.name}
39 |
42 |
43 |
44 |
45 | - Placeholder
46 | - Placeholder
47 | - Placeholder
48 | - Placeholder
49 | - Placeholder
50 | - Placeholder
51 |
52 |
53 |
{this.Child()}
54 |
55 | )
56 | }
57 | }
--------------------------------------------------------------------------------
/ee_forum/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from 'react-dom';
3 | import { Router, browserHistory } from 'react-router';
4 | import routes from './routes';
5 |
6 | render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/ee_forum/src/routes.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Route, IndexRedirect, IndexRoute } from 'react-router';
3 |
4 | import NotFoundPage from './components/NotFoundPage';
5 | import LoginPage from './components/LoginPage';
6 | import Header from './components/Header';
7 | import PostListPage from './components/PostListPage';
8 | import UserInfoPage from './components/UserInfoPage';
9 | import UserStat from './components/UserStat';
10 | import NewPostPage from './components/NewPostPage';
11 |
12 |
13 | export default (
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | );
26 |
--------------------------------------------------------------------------------
/ee_forum/src/styles/Header.css:
--------------------------------------------------------------------------------
1 | *{
2 | box-sizing: border-box;
3 | }
4 | body{
5 | font: 20px 'Helvetica Neue', Helvetica, Arial, sans-serif;
6 | line-height: 1.4em;
7 | background: #f5f5f5;
8 | color: #4d4d4d;
9 | margin: 0 auto;
10 | -webkit-font-smoothing: antialiased;
11 | -moz-font-smoothing: antialiased;
12 | font-smoothing: antialiased;
13 | font-weight: 300;
14 | }
15 | .v_center{
16 | position: relative;
17 | top: 50%;
18 | transform: translateY(-50%);
19 | }
20 | .topHeader{
21 | background-color: #D5D1FF ;
22 | height: 60px;
23 | }
24 | .slogan{
25 | position: relative;
26 | top: 50%;
27 | transform: translateY(-50%);
28 | color: gray;
29 | padding: 0 40px;
30 | font-size: 30px;
31 | font-weight: bold;
32 | cursor: pointer;
33 | display: inline-block;
34 | }
--------------------------------------------------------------------------------
/ee_forum/src/styles/LoginPage.css:
--------------------------------------------------------------------------------
1 | .hidden {
2 | visibility: hidden;
3 | }
4 | .logo {
5 | color: gray;
6 | font-size: 50px;
7 | font-weight: bold;
8 | width: 500px;
9 | margin: 100px auto 30px auto;
10 | text-align: center;
11 | }
12 | .error {
13 | color: red;
14 | width: 250px;
15 | text-align: center;
16 | margin: 0 auto;
17 | }
18 | .inputs{
19 | width: 50%;
20 | margin: 0 auto;
21 | }
22 | .inputs input{
23 | width: 100%;
24 | margin: 10px 0;
25 | /*background-color: #9D94FF;*/
26 | }
27 | .chk{
28 | width: 141px;
29 | margin: 0 auto;
30 | }
31 | .chk input{
32 | width: 14px;
33 | margin: 10px 10px;
34 | }
35 | .inputs button{
36 | display: block;
37 | width: 30%;
38 | margin: 10px auto;
39 | background-color: #9D94FF;
40 | color: white;
41 | border: none;
42 | }
43 |
--------------------------------------------------------------------------------
/ee_forum/src/styles/NewPostPage.css:
--------------------------------------------------------------------------------
1 | .post-inputs * {
2 | display: block;
3 | width: 70%;
4 | margin: 20px auto;
5 | }
6 |
7 | #post-title {
8 | font-size: 40px;
9 | font-weight: bold;
10 | }
11 |
12 | #post-content {
13 | height: 70vh;
14 | }
--------------------------------------------------------------------------------
/ee_forum/src/styles/PostListPage.css:
--------------------------------------------------------------------------------
1 | .float-button {
2 | position: absolute;
3 | right: 0;
4 | top: 60px;
5 | background-color: #00b359;
6 | width: 50px;
7 | height: 50px;
8 | border-radius: 30%;
9 | margin: 75px;
10 | }
11 | .postList {
12 | position: relative;
13 | display: block;
14 | margin: 75px auto 0 auto;
15 | width: 70%;
16 | list-style-type: none;
17 | padding: 0;
18 | }
19 | .postList li {
20 | border-style: solid;
21 | border-color: #C7C7C7;
22 | border-width: 2px;
23 | margin: 20px;
24 | background-color: #ADADAD;
25 | padding: 10px;
26 | }
27 | .post_header {
28 | height: 30px;
29 | }
30 | .post_title {
31 | font-size: 25px;
32 | font-weight: bold;
33 | float: left;
34 | }
35 | .post_votes {
36 | font-size: 15px;
37 | float: right;
38 | margin-right: 20px;
39 | }
40 | .post_time {
41 | font-size: 15px;
42 | float: right;
43 | margin-right: 20px;
44 | }
45 | .op {
46 | font-size: 15px;
47 | cursor: pointer;
48 | }
49 | .op:hover {
50 | text-decoration: underline;
51 | }
52 | .post_content {
53 | margin: 10px;
54 | white-space: pre;
55 | }
56 | .post_buttons button {
57 | margin: 5px;
58 | }
--------------------------------------------------------------------------------
/ee_forum/src/styles/UserInfoPage.css:
--------------------------------------------------------------------------------
1 | .info-img {
2 | display: block;
3 | border-radius: 50%;
4 | height: 200px;
5 | width: 200px;
6 | margin: 50px auto;
7 | box-sizing: border-box;
8 | }
9 | .info-name {
10 | text-align: center;
11 | font-size: 50px;
12 | }
--------------------------------------------------------------------------------
/ee_forum/src/styles/UserStat.css:
--------------------------------------------------------------------------------
1 | .status{
2 | height: 60px;
3 | z-index: 1;
4 | position: absolute;
5 | top: 0;
6 | right: 0;
7 | }
8 | .img-circle {
9 | border-radius: 50%;
10 | height: 55px;
11 | margin: auto;
12 | box-sizing: border-box;
13 | float: left;
14 | cursor: pointer;
15 | }
16 | .username{
17 | float: left;
18 | margin: 0 10px;
19 | }
20 | .logout {
21 | display: block;
22 | width: 75px;
23 | float: left;
24 | margin: 0 30px;
25 | background-color: #9D94FF;
26 | color: white;
27 | border: none;
28 | }
29 | .left_nav {
30 | width: 150px;
31 | height: calc(100vh - 60px);
32 | float: left;
33 | background-color: #DEDEDE;
34 | border-style: solid;
35 | border-color: #C7C7C7;
36 | border-width: 2px;
37 | }
38 | .left_nav ul {
39 | margin: 0;
40 | list-style-type: none;
41 | padding: 0;
42 | }
43 | .left_nav li {
44 | height: 50px;
45 | border-style: solid;
46 | border-color: #C7C7C7;
47 | border-width: 0px 0px 2px 0px;
48 | }
49 | .main{
50 | width: calc(100% - 150px);
51 | height: calc(100vh - 60px);
52 | float: right;
53 | overflow: auto
54 | }
--------------------------------------------------------------------------------
/ee_forum/webpack.config.dev.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var webpack = require('webpack');
3 |
4 | module.exports = {
5 | devtool: 'cheap-module-eval-source-map',
6 | entry: [
7 | 'webpack-hot-middleware/client',
8 | './src/index',
9 | ],
10 | output: {
11 | path: path.join(__dirname, 'public'),
12 | filename: 'bundle.js',
13 | publicPath: '/public/',
14 | },
15 | module: {
16 | loaders: [{
17 | test: /\.js$/,
18 | loaders: ['babel'],
19 | include: path.join(__dirname, 'src'),
20 | }, {
21 | test: /\.css$/,
22 | loaders: ['style', 'css'],
23 | }],
24 | },
25 | plugins: [
26 | new webpack.HotModuleReplacementPlugin(),
27 | new webpack.NoErrorsPlugin(),
28 | ],
29 | };
30 |
--------------------------------------------------------------------------------
/ee_forum/webpack.config.prod.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var webpack = require('webpack');
3 | var ExtractTextPlugin = require('extract-text-webpack-plugin');
4 |
5 | module.exports = {
6 | devtool: 'source-map',
7 | entry: './src/index',
8 | output: {
9 | path: path.join(__dirname, 'public'),
10 | filename: 'bundle.js',
11 | publicPath: '/public/',
12 | },
13 | module: {
14 | loaders: [{
15 | test: /\.js$/,
16 | loaders: ['babel'],
17 | include: path.join(__dirname, 'src'),
18 | }, {
19 | test: /\.css$/,
20 | loader: ExtractTextPlugin.extract('style-loader', 'css-loader'),
21 | }],
22 | },
23 | plugins: [
24 | new webpack.optimize.OccurenceOrderPlugin(),
25 | new webpack.optimize.UglifyJsPlugin({
26 | compress: {
27 | screw_ie8: true,
28 | warnings: false,
29 | },
30 | }),
31 | new ExtractTextPlugin('style.css', { allChunks: true }),
32 | ],
33 | };
34 |
--------------------------------------------------------------------------------
/hw1/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | TODOs
6 |
7 |
8 |
9 |
22 |
23 |
--------------------------------------------------------------------------------
/hw1/styles.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | margin: 0;
4 | padding: 0;
5 | }
6 |
7 | body {
8 | font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
9 | line-height: 1.4em;
10 | background: #f5f5f5;
11 | color: #4d4d4d;
12 | min-width: 230px;
13 | max-width: 550px;
14 | margin: 0 auto;
15 | -webkit-font-smoothing: antialiased;
16 | -moz-font-smoothing: antialiased;
17 | font-smoothing: antialiased;
18 | font-weight: 300;
19 | }
20 |
21 | button {
22 | margin: 0;
23 | padding: 0;
24 | border: 0;
25 | background: none;
26 | font-size: 100%;
27 | vertical-align: baseline;
28 | font-family: inherit;
29 | font-weight: inherit;
30 | color: inherit;
31 | -webkit-appearance: none;
32 | appearance: none;
33 | -webkit-font-smoothing: antialiased;
34 | -moz-font-smoothing: antialiased;
35 | font-smoothing: antialiased;
36 | }
37 |
38 | button,
39 | input[type="checkbox"] {
40 | outline: none;
41 | }
42 |
43 | .items {
44 | background: #fff;
45 | margin: 130px 0 40px 0;
46 | position: relative;
47 | box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
48 | 0 25px 50px 0 rgba(0, 0, 0, 0.1);
49 | }
50 |
51 | .items h1 {
52 | position: absolute;
53 | top: -155px;
54 | width: 100%;
55 | font-size: 100px;
56 | font-weight: 100;
57 | text-align: center;
58 | color: rgba(175, 47, 47, 0.15);
59 | -webkit-text-rendering: optimizeLegibility;
60 | -moz-text-rendering: optimizeLegibility;
61 | text-rendering: optimizeLegibility;
62 | }
63 |
64 | #input {
65 | position: relative;
66 | margin: 0;
67 | width: 100%;
68 | font-size: 24px;
69 | font-family: inherit;
70 | font-weight: inherit;
71 | line-height: 1.4em;
72 | border: 0;
73 | outline: none;
74 | color: inherit;
75 | padding: 6px;
76 | border: 1px solid #999;
77 | box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
78 | box-sizing: border-box;
79 | -webkit-font-smoothing: antialiased;
80 | -moz-font-smoothing: antialiased;
81 | font-smoothing: antialiased;
82 | padding: 16px 16px 16px 60px;
83 | border: none;
84 | background: rgba(0, 0, 0, 0.003);
85 | box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
86 | }
87 |
88 | #input::-webkit-input-placeholder {
89 | font-style: italic;
90 | font-weight: 300;
91 | color: #e6e6e6;
92 | }
93 |
94 | #input::-moz-placeholder {
95 | font-style: italic;
96 | font-weight: 300;
97 | color: #e6e6e6;
98 | }
99 |
100 | #input::input-placeholder {
101 | font-style: italic;
102 | font-weight: 300;
103 | color: #e6e6e6;
104 | }
105 |
106 | .main {
107 | position: relative;
108 | z-index: 2;
109 | border-top: 1px solid #e6e6e6;
110 | }
111 |
112 | #toggle-all {
113 | position: absolute;
114 | top: -50px;
115 | left: -12px;
116 | width: 60px;
117 | height: 34px;
118 | text-align: center;
119 | border: none; /* Mobile Safari */
120 | -webkit-appearance: none;
121 | -moz-appearance: none;
122 | appearance: none;
123 | }
124 |
125 | #toggle-all:before {
126 | content: '✓';
127 | font-size: 25px;
128 | color: #e6e6e6;
129 | padding: 10px 27px 10px 27px;
130 | }
131 |
132 | #toggle-all:checked:before {
133 | color: #737373;
134 | }
135 |
136 | #list {
137 | position: relative;
138 | z-index: 2;
139 | border-top: 1px solid #e6e6e6;
140 | margin: 0;
141 | padding: 0;
142 | list-style: none;
143 | }
144 |
145 | #list li {
146 | position: relative;
147 | font-size: 24px;
148 | border-bottom: 1px solid #ededed;
149 | }
150 |
151 | #list li:last-child {
152 | border-bottom: none;
153 | }
154 |
155 | #list li:hover {
156 | background-color: black;
157 | color: white;
158 | }
159 |
160 | #list li input {
161 | text-align: center;
162 | width: 40px;
163 | /* auto, since non-WebKit browsers doesn't support input styling */
164 | height: auto;
165 | position: absolute;
166 | top: 10px;
167 | bottom: 0;
168 | margin: auto 0;
169 | border: none; /* Mobile Safari */
170 | -webkit-appearance: none;
171 | appearance: none;
172 | }
173 |
174 | #list li input:after {
175 | content: url('data:image/svg+xml;utf8,');
176 | }
177 |
178 | #list li input:checked:after {
179 | content: url('data:image/svg+xml;utf8,');
180 | }
181 |
182 | #list li label {
183 | white-space: pre;
184 | word-break: break-word;
185 | padding: 15px 60px 15px 15px;
186 | margin-left: 45px;
187 | display: block;
188 | line-height: 1.2;
189 | transition: color 0.4s;
190 | }
191 |
192 | #list li label.complete {
193 | color: #d9d9d9;
194 | text-decoration: line-through;
195 | }
196 |
197 | #list li button {
198 | display: none;
199 | position: absolute;
200 | top: 0;
201 | right: 10px;
202 | bottom: 0;
203 | width: 40px;
204 | height: 40px;
205 | margin: auto 0;
206 | font-size: 30px;
207 | color: #cc9a9a;
208 | margin-bottom: 11px;
209 | transition: color 0.2s ease-out;
210 | }
211 |
212 | #list li button:hover {
213 | color: #af5b5e;
214 | }
215 |
216 | #list li button:after {
217 | /*content: '×';*/
218 | content: '×';
219 | }
220 |
221 | #list li:hover button {
222 | display: block;
223 | }
224 |
225 | #list li button
226 |
227 | #count {
228 | loat: left;
229 | text-align: left;
230 | }
231 |
232 | #foot {
233 | color: #777;
234 | padding: 10px 15px;
235 | height: 20px;
236 | text-align: center;
237 | border-top: 1px solid #e6e6e6;
238 | }
239 |
240 | #count {
241 | float: left;
242 | text-align: left;
243 | }
244 |
245 | #button,
246 | html #button:active {
247 | float: right;
248 | position: relative;
249 | line-height: 20px;
250 | text-decoration: none;
251 | cursor: pointer;
252 | position: relative;
253 | }
254 |
255 | #button:hover {
256 | text-decoration: underline;
257 | }
--------------------------------------------------------------------------------
/hw1/todo.js:
--------------------------------------------------------------------------------
1 | var input = document.getElementById('input');
2 | var button = document.getElementById('button');
3 | var list = document.getElementById('list');
4 | var count = document.getElementById('count');
5 | var toggle_all = document.getElementById('toggle-all');
6 |
7 | var array = list.childNodes;
8 | var num = 0;
9 |
10 | input.onkeydown = newItem;
11 | button.onclick = removeDone;
12 | toggle_all.onclick = toggleAll;
13 |
14 | function newItem() {
15 | if(event.keyCode != 13) return;
16 | var item = document.createElement('li');
17 | item.innerHTML =
18 | '' +
19 | '' +
20 | '
';
21 | input.value = '';
22 | item.childNodes[0].childNodes[0].onclick = function () { toggle(event.target); };
23 | item.childNodes[0].childNodes[2].onclick = function () {
24 | list.removeChild(event.target.parentElement.parentElement);
25 | };
26 | list.appendChild(item);
27 | ++ num;
28 | updateCount();
29 | }
30 |
31 | function removeDone() {
32 | for(var i = 0; i < array.length; ++i) {
33 | if(array[i].childNodes[0].childNodes[0].checked) {
34 | list.removeChild(array[i]);
35 | --i;
36 | }
37 | }
38 | updateCount();
39 | }
40 |
41 | function updateCount() {
42 | if (num === 0) {
43 | count.innerHTML = 'No item left';
44 | if(list.childElementCount) toggle_all.checked = true;
45 | else toggle_all.checked = false;
46 | }
47 | else if (num === 1) {
48 | count.innerHTML = num + ' item left';
49 | toggle_all.checked = false;
50 | }
51 | else {
52 | count.innerHTML = num + ' items left';
53 | toggle_all.checked = false;
54 | }
55 | }
56 |
57 | function toggle(target) {
58 | var label = target.nextSibling;
59 | if(target.checked) {
60 | label.className = 'complete';
61 | --num;
62 | }
63 | else {
64 | label.className = '';
65 | ++num;
66 | }
67 | updateCount();
68 | }
69 |
70 | function toggleAll() {
71 | if(list.childElementCount === 0) {
72 | toggle_all.checked = false;
73 | return;
74 | }
75 | var i;
76 | var full = true;
77 | for(i = 0; i < array.length; ++i) {
78 | if(!array[i].childNodes[0].childNodes[0].checked) {
79 | full = false;
80 | break;
81 | }
82 | }
83 | if(full) {
84 | for(i = 0; i < array.length; ++i) {
85 | array[i].childNodes[0].childNodes[0].checked = false;
86 | toggle(array[i].childNodes[0].childNodes[0]);
87 | }
88 | }
89 | else {
90 | for(i = 0; i < array.length; ++i) {
91 | if(!array[i].childNodes[0].childNodes[0].checked) {
92 | array[i].childNodes[0].childNodes[0].checked = true;
93 | toggle(array[i].childNodes[0].childNodes[0]);
94 | }
95 | }
96 | }
97 | }
--------------------------------------------------------------------------------
/hw11/script.sql:
--------------------------------------------------------------------------------
1 | CREATE DATABASE testDB;
2 | USE testDB;
3 | CREATE TABLE user (
4 | id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
5 | email VARCHAR(255) NOT NULL UNIQUE,
6 | name VARCHAR(255) NOT NULL,
7 | created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
8 | updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
9 | );
10 |
11 | CREATE TABLE post (
12 | id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
13 | user_id INT NOT NULL,
14 | FOREIGN KEY (user_id) REFERENCES user(id),
15 | title VARCHAR(255) NOT NULL,
16 | content TEXT NOT NULL,
17 | created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
18 | updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
19 | );
20 |
21 | CREATE TABLE tag (
22 | id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
23 | name VARCHAR(255) NOT NULL
24 | );
25 |
26 | CREATE TABLE post_tag (
27 | post_id INT NOT NULL,
28 | tag_id INT NOT NULL,
29 | FOREIGN KEY (post_id) REFERENCES post(id),
30 | FOREIGN KEY (tag_id) REFERENCES tag(id)
31 | );
32 |
33 | INSERT INTO user (email, name) VALUES ('topjohnwu@gmail.com', 'topjohnwu');
34 |
35 | INSERT INTO post (user_id, title, content) VALUES (1, 'Hello :)', 'Hello World!!');
36 |
37 | INSERT INTO tag (name) VALUES ('NTU');
38 |
39 | INSERT INTO post_tag (post_id, tag_id) VALUES (1, 1);
40 |
--------------------------------------------------------------------------------
/hw2/counter.js:
--------------------------------------------------------------------------------
1 | function counter() {
2 | var count = 0;
3 | return {
4 | getCount: function () { return count; },
5 | increase: function () { ++count; },
6 | decrease: function () { --count; }
7 | };
8 | }
--------------------------------------------------------------------------------
/hw2/curry_sum.js:
--------------------------------------------------------------------------------
1 | function curringSum (a) {
2 | return function (b) {
3 | return function (c) {
4 | return a + b + c;
5 | };
6 | };
7 | }
--------------------------------------------------------------------------------
/hw2/getType.js:
--------------------------------------------------------------------------------
1 | function getType(a) {
2 | if(a !== a) return 'NaN';
3 | else if(a === null) return 'null';
4 | else if(a instanceof(Array)) return 'array';
5 | else return typeof(a);
6 | }
--------------------------------------------------------------------------------
/hw2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | HW2
5 |
6 |
7 |
8 |
9 |
10 | Open console to interact with the functions!
11 |
12 |
--------------------------------------------------------------------------------
/hw3/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react", "es2015", "stage-0"]
3 | }
--------------------------------------------------------------------------------
/hw3/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | }
--------------------------------------------------------------------------------
/hw3/entry.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {render} from 'react-dom';
3 | import TodoApp from './todoapp'
4 | import './style.css'
5 |
6 | render(, document.getElementById('root'));
7 | render(
8 | , document.getElementById('footer')
11 | );
--------------------------------------------------------------------------------
/hw3/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | TODO App
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/hw3/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hw3",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "topjohnwu",
10 | "license": "ISC",
11 | "devDependencies": {
12 | "babel-loader": "^6.2.4",
13 | "babel-preset-es2015": "^6.6.0",
14 | "babel-preset-react": "^6.5.0",
15 | "babel-preset-stage-0": "^6.5.0",
16 | "css-loader": "^0.23.1",
17 | "react": "^15.0.1",
18 | "react-dom": "^15.0.1",
19 | "style-loader": "^0.13.1"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/hw3/style.css:
--------------------------------------------------------------------------------
1 | hr {
2 | margin: 20px 0;
3 | border: 0;
4 | border-top: 1px dashed #c5c5c5;
5 | border-bottom: 1px dashed #f7f7f7;
6 | }
7 |
8 | .learn a {
9 | font-weight: normal;
10 | text-decoration: none;
11 | color: #b83f45;
12 | }
13 |
14 | .learn a:hover {
15 | text-decoration: underline;
16 | color: #787e7e;
17 | }
18 |
19 | .learn h3,
20 | .learn h4,
21 | .learn h5 {
22 | margin: 10px 0;
23 | font-weight: 500;
24 | line-height: 1.2;
25 | color: #000;
26 | }
27 |
28 | .learn h3 {
29 | font-size: 24px;
30 | }
31 |
32 | .learn h4 {
33 | font-size: 18px;
34 | }
35 |
36 | .learn h5 {
37 | margin-bottom: 0;
38 | font-size: 14px;
39 | }
40 |
41 | .learn ul {
42 | padding: 0;
43 | margin: 0 0 30px 25px;
44 | }
45 |
46 | .learn li {
47 | line-height: 20px;
48 | }
49 |
50 | .learn p {
51 | font-size: 15px;
52 | font-weight: 300;
53 | line-height: 1.3;
54 | margin-top: 0;
55 | margin-bottom: 0;
56 | }
57 |
58 | #issue-count {
59 | display: none;
60 | }
61 |
62 | .quote {
63 | border: none;
64 | margin: 20px 0 60px 0;
65 | }
66 |
67 | .quote p {
68 | font-style: italic;
69 | }
70 |
71 | .quote p:before {
72 | content: '“';
73 | font-size: 50px;
74 | opacity: .15;
75 | position: absolute;
76 | top: -20px;
77 | left: 3px;
78 | }
79 |
80 | .quote p:after {
81 | content: '”';
82 | font-size: 50px;
83 | opacity: .15;
84 | position: absolute;
85 | bottom: -42px;
86 | right: 3px;
87 | }
88 |
89 | .quote footer {
90 | position: absolute;
91 | bottom: -40px;
92 | right: 0;
93 | }
94 |
95 | .quote footer img {
96 | border-radius: 3px;
97 | }
98 |
99 | .quote footer a {
100 | margin-left: 5px;
101 | vertical-align: middle;
102 | }
103 |
104 | .speech-bubble {
105 | position: relative;
106 | padding: 10px;
107 | background: rgba(0, 0, 0, .04);
108 | border-radius: 5px;
109 | }
110 |
111 | .speech-bubble:after {
112 | content: '';
113 | position: absolute;
114 | top: 100%;
115 | right: 30px;
116 | border: 13px solid transparent;
117 | border-top-color: rgba(0, 0, 0, .04);
118 | }
119 |
120 | .learn-bar > .learn {
121 | position: absolute;
122 | width: 272px;
123 | top: 8px;
124 | left: -300px;
125 | padding: 10px;
126 | border-radius: 5px;
127 | background-color: rgba(255, 255, 255, .6);
128 | transition-property: left;
129 | transition-duration: 500ms;
130 | }
131 |
132 | @media (min-width: 899px) {
133 | .learn-bar {
134 | width: auto;
135 | padding-left: 300px;
136 | }
137 |
138 | .learn-bar > .learn {
139 | left: 8px;
140 | }
141 | }
142 |
143 |
144 | html,
145 | body {
146 | margin: 0;
147 | padding: 0;
148 | }
149 |
150 | button {
151 | margin: 0;
152 | padding: 0;
153 | border: 0;
154 | background: none;
155 | font-size: 100%;
156 | vertical-align: baseline;
157 | font-family: inherit;
158 | font-weight: inherit;
159 | color: inherit;
160 | -webkit-appearance: none;
161 | appearance: none;
162 | -webkit-font-smoothing: antialiased;
163 | -moz-osx-font-smoothing: grayscale;
164 | }
165 |
166 | body {
167 | font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
168 | line-height: 1.4em;
169 | background: #f5f5f5;
170 | color: #4d4d4d;
171 | min-width: 230px;
172 | max-width: 550px;
173 | margin: 0 auto;
174 | -webkit-font-smoothing: antialiased;
175 | -moz-osx-font-smoothing: grayscale;
176 | font-weight: 300;
177 | }
178 |
179 | button,
180 | input[type="checkbox"] {
181 | outline: none;
182 | }
183 |
184 | .hidden {
185 | display: none;
186 | }
187 |
188 | .todoapp {
189 | background: #fff;
190 | margin: 130px 0 40px 0;
191 | position: relative;
192 | box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
193 | 0 25px 50px 0 rgba(0, 0, 0, 0.1);
194 | }
195 |
196 | .todoapp input::-webkit-input-placeholder {
197 | font-style: italic;
198 | font-weight: 300;
199 | color: #e6e6e6;
200 | }
201 |
202 | .todoapp input::-moz-placeholder {
203 | font-style: italic;
204 | font-weight: 300;
205 | color: #e6e6e6;
206 | }
207 |
208 | .todoapp input::input-placeholder {
209 | font-style: italic;
210 | font-weight: 300;
211 | color: #e6e6e6;
212 | }
213 |
214 | .todoapp h1 {
215 | position: absolute;
216 | top: -155px;
217 | width: 100%;
218 | font-size: 100px;
219 | font-weight: 100;
220 | text-align: center;
221 | color: rgba(175, 47, 47, 0.15);
222 | -webkit-text-rendering: optimizeLegibility;
223 | -moz-text-rendering: optimizeLegibility;
224 | text-rendering: optimizeLegibility;
225 | }
226 |
227 | .new-todo,
228 | .edit {
229 | position: relative;
230 | margin: 0;
231 | width: 100%;
232 | font-size: 24px;
233 | font-family: inherit;
234 | font-weight: inherit;
235 | line-height: 1.4em;
236 | border: 0;
237 | outline: none;
238 | color: inherit;
239 | padding: 6px;
240 | border: 1px solid #999;
241 | box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
242 | box-sizing: border-box;
243 | -webkit-font-smoothing: antialiased;
244 | -moz-osx-font-smoothing: grayscale;
245 | }
246 |
247 | .new-todo {
248 | padding: 16px 16px 16px 60px;
249 | border: none;
250 | background: rgba(0, 0, 0, 0.003);
251 | box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
252 | }
253 |
254 | .main {
255 | position: relative;
256 | z-index: 2;
257 | border-top: 1px solid #e6e6e6;
258 | }
259 |
260 | label[for='toggle-all'] {
261 | display: none;
262 | }
263 |
264 | .toggle-all {
265 | position: absolute;
266 | top: -55px;
267 | left: -12px;
268 | width: 60px;
269 | height: 34px;
270 | text-align: center;
271 | border: none; /* Mobile Safari */
272 | }
273 |
274 | .toggle-all:before {
275 | content: '❯';
276 | font-size: 22px;
277 | color: #e6e6e6;
278 | padding: 10px 27px 10px 27px;
279 | }
280 |
281 | .toggle-all:checked:before {
282 | color: #737373;
283 | }
284 |
285 | .todo-list {
286 | margin: 0;
287 | padding: 0;
288 | list-style: none;
289 | }
290 |
291 | .todo-list li {
292 | position: relative;
293 | font-size: 24px;
294 | border-bottom: 1px solid #ededed;
295 | }
296 |
297 | .todo-list li:hover {
298 | background-color: black;
299 | color: white;
300 | }
301 |
302 | .todo-list li:last-child {
303 | border-bottom: none;
304 | }
305 |
306 | .todo-list li.editing {
307 | border-bottom: none;
308 | padding: 0;
309 | }
310 |
311 | .todo-list li.editing .edit {
312 | display: block;
313 | width: 506px;
314 | padding: 13px 17px 12px 17px;
315 | margin: 0 0 0 43px;
316 | }
317 |
318 | .todo-list li.editing .view {
319 | display: none;
320 | }
321 |
322 | .todo-list li .toggle {
323 | text-align: center;
324 | width: 40px;
325 | /* auto, since non-WebKit browsers doesn't support input styling */
326 | height: auto;
327 | position: absolute;
328 | top: 0;
329 | bottom: 0;
330 | margin: auto 0;
331 | border: none; /* Mobile Safari */
332 | -webkit-appearance: none;
333 | appearance: none;
334 | }
335 |
336 | .todo-list li .toggle:after {
337 | content: url('data:image/svg+xml;utf8,');
338 | }
339 |
340 | .todo-list li .toggle:checked:after {
341 | content: url('data:image/svg+xml;utf8,');
342 | }
343 |
344 | .todo-list li label {
345 | white-space: pre-line;
346 | word-break: break-all;
347 | padding: 15px 60px 15px 15px;
348 | margin-left: 45px;
349 | display: block;
350 | line-height: 1.2;
351 | transition: color 0.4s;
352 | }
353 |
354 | .todo-list li.completed label {
355 | color: #d9d9d9;
356 | text-decoration: line-through;
357 | }
358 |
359 | .todo-list .removed {
360 | display: none;
361 | }
362 |
363 | .todo-list li .destroy {
364 | display: none;
365 | position: absolute;
366 | top: 0;
367 | right: 10px;
368 | bottom: 0;
369 | width: 40px;
370 | height: 40px;
371 | margin: auto 0;
372 | font-size: 30px;
373 | color: #cc9a9a;
374 | margin-bottom: 11px;
375 | transition: color 0.2s ease-out;
376 | }
377 |
378 | .todo-list li .destroy:hover {
379 | color: #af5b5e;
380 | }
381 |
382 | .todo-list li .destroy:after {
383 | content: '×';
384 | }
385 |
386 | .todo-list li:hover .destroy {
387 | display: block;
388 | }
389 |
390 | .todo-list li .edit {
391 | display: none;
392 | }
393 |
394 | .todo-list li.editing:last-child {
395 | margin-bottom: -1px;
396 | }
397 |
398 | .footer {
399 | color: #777;
400 | padding: 10px 15px;
401 | height: 20px;
402 | text-align: center;
403 | border-top: 1px solid #e6e6e6;
404 | }
405 |
406 | .footer:before {
407 | content: '';
408 | position: absolute;
409 | right: 0;
410 | bottom: 0;
411 | left: 0;
412 | height: 50px;
413 | overflow: hidden;
414 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
415 | 0 8px 0 -3px #f6f6f6,
416 | 0 9px 1px -3px rgba(0, 0, 0, 0.2),
417 | 0 16px 0 -6px #f6f6f6,
418 | 0 17px 2px -6px rgba(0, 0, 0, 0.2);
419 | }
420 |
421 | .todo-count {
422 | float: left;
423 | text-align: left;
424 | }
425 |
426 | .todo-count strong {
427 | font-weight: 300;
428 | }
429 |
430 | .filters {
431 | margin: 0;
432 | padding: 0;
433 | list-style: none;
434 | position: absolute;
435 | right: 0;
436 | left: 0;
437 | }
438 |
439 | .filters li {
440 | display: inline;
441 | }
442 |
443 | .filters li a {
444 | color: inherit;
445 | margin: 3px;
446 | padding: 3px 7px;
447 | text-decoration: none;
448 | border: 1px solid transparent;
449 | border-radius: 3px;
450 | }
451 |
452 | .filters li a.selected,
453 | .filters li a:hover {
454 | border-color: rgba(175, 47, 47, 0.1);
455 | }
456 |
457 | .filters li a.selected {
458 | border-color: rgba(175, 47, 47, 0.2);
459 | }
460 |
461 | .clear-completed,
462 | html .clear-completed:active {
463 | float: right;
464 | position: relative;
465 | line-height: 20px;
466 | text-decoration: none;
467 | cursor: pointer;
468 | }
469 |
470 | .clear-completed:hover {
471 | text-decoration: underline;
472 | }
473 |
474 | .info {
475 | margin: 65px auto 0;
476 | color: #bfbfbf;
477 | font-size: 10px;
478 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
479 | text-align: center;
480 | }
481 |
482 | .info p {
483 | line-height: 1;
484 | }
485 |
486 | .info a {
487 | color: inherit;
488 | text-decoration: none;
489 | font-weight: 400;
490 | }
491 |
492 | .info a:hover {
493 | text-decoration: underline;
494 | }
495 |
496 | /*
497 | Hack to remove background from Mobile Safari.
498 | Can't use it globally since it destroys checkboxes in Firefox
499 | */
500 | @media screen and (-webkit-min-device-pixel-ratio:0) {
501 | .toggle-all,
502 | .todo-list li .toggle {
503 | background: none;
504 | }
505 |
506 | .todo-list li .toggle {
507 | height: 40px;
508 | }
509 |
510 | .toggle-all {
511 | -webkit-transform: rotate(90deg);
512 | transform: rotate(90deg);
513 | -webkit-appearance: none;
514 | appearance: none;
515 | }
516 | }
517 |
518 | @media (max-width: 430px) {
519 | .footer {
520 | height: 50px;
521 | }
522 |
523 | .filters {
524 | bottom: 10px;
525 | }
526 | }
--------------------------------------------------------------------------------
/hw3/todoapp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class TodoApp extends React.Component {
4 | constructor() {
5 | super();
6 | this.state = {
7 | items: []
8 | }
9 | this.insert = this.insert.bind(this);
10 | this.clear = this.clear.bind(this);
11 | this.remain = this.remain.bind(this);
12 | this.genToggle = this.genToggle.bind(this);
13 | this.genRemove = this.genRemove.bind(this);
14 | this.toggleAll = this.toggleAll.bind(this);
15 | this.id = 0;
16 | }
17 |
18 | insert(event) {
19 | if(event.keyCode !== 13) return;
20 | if(event.target.value === "") return;
21 | this.state.items.push( {id: this.id++, checked: false, removed: false, label: event.target.value});
22 | this.setState({items: this.state.items});
23 | event.target.value = "";
24 | }
25 |
26 | clear() {
27 | for(let i = 0; i < this.state.items.length; ++i) {
28 | if(this.state.items[i].checked)
29 | this.state.items[i].removed = true;
30 | }
31 | this.setState({items: this.state.items});
32 | }
33 |
34 | remain() {
35 | let undone = 0, present = 0;
36 | for(let i = 0; i < this.state.items.length; ++i) {
37 | if(!this.state.items[i].removed) {
38 | present++;
39 | if(!this.state.items[i].checked) ++undone;
40 | }
41 | }
42 | return [present, undone];
43 | }
44 |
45 | toggleAll() {
46 | let remain = !!this.remain()[1];
47 | for(let i = 0; i < this.state.items.length; ++i) {
48 | this.state.items[i].checked = remain;
49 | }
50 | this.setState({items: this.state.items});
51 | }
52 |
53 | genToggle(key) {
54 | function toggle() {
55 | this.state.items[key].checked = !this.state.items[key].checked;
56 | this.setState({items: this.state.items});
57 | }
58 | toggle = toggle.bind(this);
59 | return toggle;
60 | }
61 |
62 | genRemove(key) {
63 | function remove() {
64 | this.state.items[key].removed = true;
65 | this.setState({items: this.state.items});
66 | }
67 | remove = remove.bind(this);
68 | return remove;
69 | }
70 |
71 | render() {
72 | return
77 | }
78 | }
79 |
80 | class Header extends React.Component {
81 | render() {
82 | return
86 | }
87 | }
88 |
89 | class NewToDo extends React.Component {
90 | render() {
91 | return
92 | }
93 | }
94 |
95 | class Main extends React.Component {
96 | render() {
97 | return
101 | }
102 | }
103 |
104 | class ToggleAll extends React.Component {
105 | render() {
106 | return
107 |
108 |
109 |
110 | }
111 | }
112 |
113 | class TodoList extends React.Component {
114 | constructor() {
115 | super();
116 | this.mapItem = this.mapItem.bind(this);
117 | }
118 | mapItem(item) {
119 | return
121 | }
122 | render() {
123 | return
124 | { this.props.items.map(this.mapItem) }
125 |
126 | }
127 | }
128 |
129 | class ListItem extends React.Component {
130 | render() {
131 | return
132 |
133 |
134 |
135 |
136 |
137 | }
138 | }
139 |
140 | class Footer extends React.Component {
141 | render() {
142 | let count = this.props.remain()[1];
143 | return
147 | }
148 | }
149 |
150 | class TodoCount extends React.Component {
151 | render() {
152 | return {this.props.remain}
153 | }
154 | }
155 |
156 | class ClearComplete extends React.Component {
157 | render() {
158 | return
159 | }
160 | }
161 |
162 | export default TodoApp;
--------------------------------------------------------------------------------
/hw3/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | devtool: 'cheap-module-eval-source-map',
3 | entry: './entry', // 進入點
4 | output: {
5 | filename: 'bundle.js', // 輸出的檔案名稱
6 | },
7 | module: {
8 | loaders: [{
9 | test: /\.js$/, // 針對 js 檔
10 | loaders: ['babel'],
11 | exclude: /node_modules/ // 不要處理 3rd party 的 code
12 | }, {
13 | test: /\.css$/, // 針對 css 檔
14 | loaders: ['style', 'css'],
15 | exclude: /node_modules/ // 不要處理 3rd party 的 code
16 | }]
17 | }
18 | };
--------------------------------------------------------------------------------
/hw4/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react", "es2015", "stage-0"]
3 | }
--------------------------------------------------------------------------------
/hw4/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | }
--------------------------------------------------------------------------------
/hw4/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ChatApp
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/hw4/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hw4",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "topjohnwu",
10 | "license": "ISC",
11 | "dependencies": {
12 | "react": "^15.0.1",
13 | "react-dom": "^15.0.1"
14 | },
15 | "devDependencies": {
16 | "babel-loader": "^6.2.4",
17 | "babel-preset-es2015": "^6.6.0",
18 | "babel-preset-react": "^6.5.0",
19 | "babel-preset-stage-0": "^6.5.0",
20 | "css-loader": "^0.23.1",
21 | "style-loader": "^0.13.1"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/hw4/src/component/ChatApp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ThreadItem from './ThreadItem'
3 | import MessageItem from './MessageItem'
4 |
5 | class ChatApp extends React.Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = {
9 | contacts: [{
10 | id: 0,
11 | name: "蔡英文",
12 | pic: "http://donate.iing.tw/images/iing.png",
13 | contents: [
14 | ["誒誒你知道你的貼圖現在很夯嗎XD", true],
15 | ["什麼鬼= =", false],
16 | [
, true],
17 | ["...........", false],
18 | ],
19 | time: "11:20pm",
20 | }, {
21 | id: 1,
22 | name: "蔣介石",
23 | pic: "http://goo.gl/Kgihrw",
24 | contents: [
25 | ["漢賊不兩立!", false],
26 | ["...?", true],
27 | ["退出聯合國!", false],
28 | ["...........?!", true],
29 | ],
30 | time: "2:24pm",
31 | }, {
32 | id: 2,
33 | name: "蔣經國",
34 | pic: "http://goo.gl/W7G3g0",
35 | contents: [
36 | ["快快快!十大建設!", false],
37 | ["好好好", true],
38 | ["讚讚讚!解嚴囉!", false],
39 | ["呵呵呵", true],
40 | ],
41 | time: "6:18pm",
42 | }, {
43 | id: 3,
44 | name: "李登輝",
45 | pic: "http://goo.gl/vVsKme",
46 | contents: [
47 | ["這麼晚了你怎麼還不睡?", true],
48 | ["我是第一任民選總統,啊你現在是想怎樣", false],
49 | ["...沒啊,關心你而已啊= =兇啥", true],
50 | ["爺可是日本皇民,休想污辱我", false],
51 | ["日本人可以當台灣總統?", true],
52 | ],
53 | time: "4:13am",
54 | }, {
55 | id: 4,
56 | name: "陳水扁",
57 | pic: "https://goo.gl/vgZhEo",
58 | contents: [
59 | ["阿扁錯了嗎?", false],
60 | ["誒...你要我怎麼回答", true],
61 | ["阿扁錯了嗎?", false],
62 | ["不要跳針好嗎= =", true],
63 | ["難道阿扁錯了嗎?", false],
64 | ["........你錯了....", true],
65 | ],
66 | time: "12:04am",
67 | }, {
68 | id: 5,
69 | name: "馬英九",
70 | pic: "http://goo.gl/Ftpij0",
71 | contents: [
72 | ["一個總統,施政滿意度只剩18%就可以下台了\
73 | ,不下台就是沒有羞恥心!", false],
74 | ["嗯...可是你只有9%誒", true],
75 | ["你說什麼?我聽不到", false],
76 | ["你耳朵長毛嗎?", true],
77 | ["你說什麼?", false],
78 | ],
79 | time: "3:21pm",
80 | },
81 |
82 | ],
83 | current: 0,
84 | }
85 | }
86 |
87 | getTime() {
88 | let d = new Date(),
89 | hour = d.getHours(),
90 | minute = d.getMinutes();
91 | return (hour % 12 ? hour % 12 : 12) + ":" +
92 | (minute < 10 ? "0" + minute : minute) +
93 | (hour < 12 ? "am" : "pm");
94 | }
95 |
96 | setContact(key) {
97 | function set() {
98 | this.setState({ current: key });
99 | }
100 | return set.bind(this);
101 | }
102 |
103 | mapContact(contact) {
104 | return
105 | }
106 |
107 | input(event) {
108 | if (event.keyCode !== 13) return;
109 | if (event.target.value === "") return;
110 | this.state.contacts[this.state.current].contents.push([event.target.value, true]);
111 | this.state.contacts[this.state.current].time = this.getTime();
112 | event.target.value = "";
113 | this.setState({ contacts: this.state.contacts });
114 | }
115 |
116 | render() {
117 | let i = 0;
118 | return (
119 |
120 |
121 |
122 |
中華民國總統會談
123 |
124 |
125 | {this.state.contacts.map(this.mapContact.bind(this))}
126 |
127 |
128 |
129 |
130 |
131 | {this.state.contacts[this.state.current].name}
132 |
133 |
134 |
135 | {
136 | this.state.contacts[this.state.current].contents.map(
137 | function(content) {
138 | return ;
139 | }
140 | )
141 | }
142 |
143 |
144 |
145 |
146 |
147 |
148 | );
149 | };
150 | };
151 |
152 | export default ChatApp;
153 |
--------------------------------------------------------------------------------
/hw4/src/component/MessageItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class MessageItem extends React.Component {
4 | render() {
5 | return (
6 |
7 | {this.props.text}
8 |
9 | );
10 | }
11 | }
12 |
13 | export default MessageItem;
--------------------------------------------------------------------------------
/hw4/src/component/ThreadItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class ThreadItem extends React.Component {
4 | render() {
5 | const {id, name, pic, contents, time} = this.props.contact;
6 | return (
7 |
8 |
9 |
10 |
11 |

12 |
13 |
14 |
{name}
15 |
16 |
17 | {contents.slice(-1)[0][0]}
18 |
19 |
20 |
{time}
21 |
22 |
23 |
24 |
25 | );
26 | }
27 | }
28 |
29 | export default ThreadItem;
--------------------------------------------------------------------------------
/hw4/src/entry.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {render} from 'react-dom';
3 | import ChatApp from './component/ChatApp'
4 | import './style.css'
5 |
6 | render(, document.getElementById('root'));
--------------------------------------------------------------------------------
/hw4/src/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | -webkit-box-sizing: border-box;
3 | -moz-box-sizing: border-box;
4 | box-sizing: border-box;
5 | }
6 |
7 | li {
8 | list-style: none;
9 | }
10 |
11 | a {
12 | text-decoration: none;
13 | }
14 |
15 | a:hover {
16 | text-decoration: none;
17 | cursor: pointer;
18 | }
19 |
20 |
21 | /* layout */
22 |
23 | .chat-app {
24 | height: 100vh;
25 | }
26 |
27 | .chat-app_left {
28 | float: left;
29 | width: calc(35% - 1px);
30 | height: inherit;
31 | border-right: 1px solid grey;
32 | }
33 |
34 | .chat-app_right {
35 | float: left;
36 | width: 65%;
37 | height: inherit;
38 | }
39 |
40 | .heading {
41 | height: 60px;
42 | text-align: center;
43 | border-bottom: 1px solid rgba(0, 0, 0, .10);
44 | }
45 |
46 |
47 | /* thread */
48 |
49 | .messenger-title {
50 | line-height: 60px;
51 | margin: 0;
52 | }
53 |
54 | .thread-list {
55 | height: calc(100% - 60px);
56 | overflow: auto;
57 | }
58 |
59 | .thread-item {
60 | position: relative;
61 | height: 80px;
62 | }
63 |
64 | .thread-item_left {
65 | float: left;
66 | width: 90px;
67 | padding: 15px 10px;
68 | height: 80px;
69 | }
70 |
71 | .thread-item_right {
72 | float: left;
73 | width: calc(100% - 90px);
74 | padding: 20px 10px;
75 | border-bottom: 1px solid rgba(0, 0, 0, .10);
76 | height: 80px;
77 | }
78 |
79 | .thread-from {
80 | font-weight: 400;
81 | line-height: 1.4em;
82 | color: black;
83 | }
84 |
85 | .thread-content {
86 | color: rgba(0, 0, 0, .40);
87 | font-size: 14px;
88 | }
89 |
90 | .thread-time {
91 | color: rgba(0, 0, 0, .40);
92 | position: absolute;
93 | top: 23px;
94 | right: 13px;
95 | font-size: 14px;
96 | }
97 |
98 | .img-circle {
99 | border-radius: 50%;
100 | max-width: 70px;
101 | max-height: 60px
102 | }
103 |
104 |
105 | /* message */
106 |
107 | .current-target {
108 | line-height: 60px;
109 | font-size: 16px;
110 | }
111 |
112 | .message-list {
113 | padding-top: 10px;
114 | height: calc(100% - 110px);
115 | overflow: auto;
116 | }
117 |
118 | .message-item {
119 | line-height: 2em;
120 | margin: 10px 0;
121 | }
122 |
123 | .footer {
124 | border-top: 1px solid rgba(0, 0, 0, .10);
125 | height: 50px;
126 | }
127 |
128 | .message-from-other {
129 | padding-left: 25px;
130 | text-align: left;
131 | }
132 |
133 | .message-from-me {
134 | padding-right: 25px;
135 | text-align: right;
136 | }
137 |
138 | .message-from-other span {
139 | display: inline-block;
140 | border-top-left-radius: 1.3em;
141 | border-top-right-radius: 1.3em;
142 | border-bottom-left-radius: 1.3em;
143 | border-bottom-right-radius: 1.3em;
144 | border: 1px solid rgba(0, 0, 0, .10);
145 | padding: 0 15px;
146 | color: black;
147 | background-color: rgba(255, 255, 255, .10);
148 | }
149 |
150 | .message-from-me span {
151 | display: inline-block;
152 | border-top-left-radius: 1.3em;
153 | border-top-right-radius: 1.3em;
154 | border-bottom-left-radius: 1.3em;
155 | border-bottom-right-radius: 1.3em;
156 | padding: 0 15px;
157 | color: white;
158 | background-color: #0084ff;
159 | }
160 |
161 | .new-message {
162 | width: 100%;
163 | height: 100%;
164 | }
165 |
166 |
167 | /* clearfix
168 | * http://stackoverflow.com/questions/211383/which-method-of-clearfix-is-best
169 | */
170 |
171 | .clearfix:before,
172 | .clearfix:after {
173 | content: "";
174 | display: table;
175 | }
176 |
177 | .clearfix:after {
178 | clear: both;
179 | }
180 |
181 | .clearfix {
182 | zoom: 1;
183 | /* For IE 6/7 (trigger hasLayout) */
184 | }
185 |
186 | .attach {
187 | padding-top: 10px;
188 | width: 250px;
189 | }
190 |
--------------------------------------------------------------------------------
/hw4/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 |
3 | module.exports = {
4 | devtool: 'cheap-module-eval-source-map',
5 | entry: './src/entry',
6 | output: {
7 | path: path.join(__dirname, 'dist'),
8 | filename: 'bundle.js',
9 | },
10 | module: {
11 | loaders: [{
12 | test: /\.js$/,
13 | loaders: ['babel'],
14 | exclude: /node_modules/
15 | }, {
16 | test: /\.css$/,
17 | loaders: ['style', 'css'],
18 | exclude: /node_modules/
19 | }]
20 | }
21 | };
22 |
--------------------------------------------------------------------------------
/hw5/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hw5",
3 | "version": "1.0.0",
4 | "description": "HW5",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "topjohnwu",
10 | "license": "ISC",
11 | "dependencies": {
12 | "body-parser": "^1.15.0",
13 | "express": "^4.13.4",
14 | "nunjucks": "^2.4.1",
15 | "path": "^0.12.7"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/hw5/public/example.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/hw5/public/example.jpg
--------------------------------------------------------------------------------
/hw5/server.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var bodyParser = require('body-parser');
3 | var nunjucks = require('nunjucks');
4 | var path = require('path');
5 | var app = express();
6 | var router = express.Router();
7 |
8 | function genError(status, message){
9 | var err = new Error();
10 | err.status = status;
11 | err.message = message;
12 | return err;
13 | }
14 |
15 | app.set('views', path.join(__dirname, 'views'));
16 | app.set('view engine', 'nunjucks');
17 | nunjucks.configure('views', {
18 | autoescape: true,
19 | express: app
20 | });
21 | app.use(bodyParser.urlencoded({ extended: false }));
22 | app.use(bodyParser.json());
23 |
24 | router.get('/', function(req, res, next) {
25 | res.render('index');
26 | });
27 |
28 | router.get('/api/query', function(req, res, next){
29 | res.json(req.query);
30 | });
31 |
32 | router.post('/api/body', function(req, res, next) {
33 | res.json(req.body);
34 | });
35 |
36 | router.get('/api/user/:id', function(req, res, next){
37 | if(Number(req.params.id) === 1) {
38 | var joe = {id: 1, name: "Joe", age: 18};
39 | res.json(joe);
40 | }
41 | else if(Number(req.params.id) === 2) {
42 | var john = {id: 2, name: "John", age: 22};
43 | res.json(john);
44 | }
45 | else next(genError(404, "ID: " + req.params.id + " not found!"));
46 | });
47 |
48 | router.use('/static', express.static('public'));
49 |
50 | router.use(function(req, res, next){
51 | next(genError(404, "Page not found!!"));
52 | });
53 |
54 | app.use('/', router);
55 |
56 | app.use(function(err, req, res, next){
57 | res.status(err.status).render('error', {
58 | error: err.status,
59 | message: err.message
60 | });
61 | });
62 |
63 | app.listen(3000);
--------------------------------------------------------------------------------
/hw5/views/error.nunjucks:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Error!
5 |
6 |
7 | Error {{error}}
8 | {{message}}
9 |
10 |
--------------------------------------------------------------------------------
/hw5/views/index.html:
--------------------------------------------------------------------------------
1 | {title}
--------------------------------------------------------------------------------
/hw5/views/index.nunjucks:
--------------------------------------------------------------------------------
1 | 首頁
--------------------------------------------------------------------------------
/hw6/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react", "es2015", "stage-0"]
3 | }
--------------------------------------------------------------------------------
/hw6/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | }
--------------------------------------------------------------------------------
/hw6/image/chen.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/hw6/image/chen.jpg
--------------------------------------------------------------------------------
/hw6/image/chiang1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/hw6/image/chiang1.jpg
--------------------------------------------------------------------------------
/hw6/image/chiang2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/hw6/image/chiang2.jpg
--------------------------------------------------------------------------------
/hw6/image/fun.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/hw6/image/fun.jpg
--------------------------------------------------------------------------------
/hw6/image/lee.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/hw6/image/lee.jpg
--------------------------------------------------------------------------------
/hw6/image/ma.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/hw6/image/ma.png
--------------------------------------------------------------------------------
/hw6/image/tsai.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/hw6/image/tsai.png
--------------------------------------------------------------------------------
/hw6/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ChatApp
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/hw6/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hw6",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "topjohnwu",
10 | "license": "ISC",
11 | "dependencies": {
12 | "react": "^15.0.1",
13 | "react-dom": "^15.0.1"
14 | },
15 | "devDependencies": {
16 | "babel-loader": "^6.2.4",
17 | "babel-preset-es2015": "^6.6.0",
18 | "babel-preset-react": "^6.5.0",
19 | "babel-preset-stage-0": "^6.5.0",
20 | "css-loader": "^0.23.1",
21 | "style-loader": "^0.13.1"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/hw6/src/component/ChatApp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ThreadItem from './ThreadItem'
3 | import MessageItem from './MessageItem'
4 |
5 | class ChatApp extends React.Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = {
9 | contacts: [{
10 | name: "蔡英文",
11 | pic: "image/tsai.png",
12 | contents: [
13 | ["誒誒你知道你的貼圖現在很夯嗎XD", true],
14 | ["什麼鬼= =", false],
15 | [
, true],
16 | ["...........", false],
17 | ],
18 | time: "11:20pm",
19 | }, {
20 | name: "蔣介石",
21 | pic: "image/chiang1.jpg",
22 | contents: [
23 | ["漢賊不兩立!", false],
24 | ["...?", true],
25 | ["退出聯合國!", false],
26 | ["...........?!", true],
27 | ],
28 | time: "2:24pm",
29 | }, {
30 | name: "蔣經國",
31 | pic: "image/chiang2.jpg",
32 | contents: [
33 | ["快快快!十大建設!", false],
34 | ["好好好", true],
35 | ["讚讚讚!解嚴囉!", false],
36 | ["呵呵呵", true],
37 | ],
38 | time: "6:18pm",
39 | }, {
40 | name: "李登輝",
41 | pic: "image/lee.jpg",
42 | contents: [
43 | ["這麼晚了你怎麼還不睡?", true],
44 | ["我是第一任民選總統,啊你現在是想怎樣", false],
45 | ["...沒啊,關心你而已啊= =兇啥", true],
46 | ["爺可是日本皇民,休想污辱我", false],
47 | ["日本人可以當台灣總統?", true],
48 | ],
49 | time: "4:13am",
50 | }, {
51 | name: "陳水扁",
52 | pic: "image/chen.jpg",
53 | contents: [
54 | ["阿扁錯了嗎?", false],
55 | ["誒...你要我怎麼回答", true],
56 | ["阿扁錯了嗎?", false],
57 | ["不要跳針好嗎= =", true],
58 | ["難道阿扁錯了嗎?", false],
59 | ["........你錯了....", true],
60 | ],
61 | time: "12:04am",
62 | }, {
63 | name: "馬英九",
64 | pic: "image/ma.png",
65 | contents: [
66 | ["一個總統,施政滿意度只剩18%就可以下台了,不下台就是沒有羞恥心!", false],
67 | ["嗯...可是你只有9%誒", true],
68 | ["你說什麼?我聽不到", false],
69 | ["你耳朵長毛嗎?", true],
70 | ["你說什麼?", false],
71 | ],
72 | time: "3:21pm",
73 | },
74 | ],
75 | current: 0,
76 | idList: [0, 1, 2, 3, 4, 5],
77 | }
78 | this.scroll = false;
79 | }
80 |
81 | /* Mapping functions */
82 |
83 | mapContact(id) {
84 | return ;
85 | }
86 |
87 | mapContent(content, index) {
88 | return ;
89 | }
90 |
91 | /* Function Generators */
92 |
93 | setContact(key) {
94 | function set() {
95 | let input = document.getElementById('input');
96 | input.value = "";
97 | this.setState({ current: key });
98 | }
99 | return set.bind(this);
100 | }
101 |
102 | /* Events */
103 |
104 | input(event) {
105 | if (event.keyCode !== 13) return;
106 | if (event.target.value === "") return;
107 | this.state.contacts[this.state.current].contents.push([event.target.value, true]);
108 | this.state.contacts[this.state.current].time = this.getTime();
109 | event.target.value = "";
110 | this.state.idList.splice(this.state.idList.indexOf(this.state.current), 1);
111 | this.state.idList.unshift(this.state.current);
112 | this.setState({ idList: this.state.idList });
113 | this.scroll = true;
114 | }
115 |
116 |
117 | /* Helper functions */
118 |
119 | getTime() {
120 | let d = new Date(),
121 | hour = d.getHours(),
122 | minute = d.getMinutes();
123 | return (hour % 12 ? hour % 12 : 12) + ":" +
124 | (minute < 10 ? "0" + minute : minute) +
125 | (hour < 12 ? "am" : "pm");
126 | }
127 |
128 | componentDidUpdate() {
129 | if(this.scroll){
130 | let mList = document.getElementById('message-list');
131 | let tList = document.getElementById('thread-list');
132 | mList.scrollTop = mList.scrollHeight;
133 | tList.scrollTop = 0;
134 | this.scroll = false;
135 | }
136 | }
137 |
138 | /* Render */
139 |
140 | render() {
141 | let i = 0;
142 | return (
143 |
144 |
145 |
146 |
中華民國總統會談
147 |
148 |
149 | {this.state.idList.map(this.mapContact.bind(this))}
150 |
151 |
152 |
153 |
154 |
155 | {this.state.contacts[this.state.current].name}
156 |
157 |
158 |
159 | {this.state.contacts[this.state.current].contents.map(this.mapContent.bind(this))}
160 |
161 |
162 |
163 |
164 |
165 |
166 | );
167 | };
168 | };
169 |
170 | export default ChatApp;
171 |
--------------------------------------------------------------------------------
/hw6/src/component/MessageItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class MessageItem extends React.Component {
4 | render() {
5 | return (
6 |
7 | {this.props.text}
8 |
9 | );
10 | }
11 | }
12 |
13 | export default MessageItem;
--------------------------------------------------------------------------------
/hw6/src/component/ThreadItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class ThreadItem extends React.Component {
4 | render() {
5 | const {name, pic, contents, time} = this.props.contact;
6 | return (
7 |
8 |
9 |
10 |
11 |

12 |
13 |
14 |
{name}
15 |
16 |
17 | {contents.slice(-1)[0][0]}
18 |
19 |
20 |
{time}
21 |
22 |
23 |
24 |
25 | );
26 | }
27 | }
28 |
29 | export default ThreadItem;
--------------------------------------------------------------------------------
/hw6/src/entry.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {render} from 'react-dom';
3 | import ChatApp from './component/ChatApp'
4 | import './style.css'
5 |
6 | render(, document.getElementById('root'));
--------------------------------------------------------------------------------
/hw6/src/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | -webkit-box-sizing: border-box;
3 | -moz-box-sizing: border-box;
4 | box-sizing: border-box;
5 | }
6 |
7 | li {
8 | list-style: none;
9 | }
10 |
11 | a {
12 | text-decoration: none;
13 | }
14 |
15 | a:hover {
16 | text-decoration: none;
17 | cursor: pointer;
18 | }
19 |
20 | .heading {
21 | height: 60px;
22 | text-align: center;
23 | border-bottom: 1px solid rgba(0, 0, 0, .10);
24 | }
25 |
26 | .chat-app {
27 | height: 100vh;
28 | }
29 |
30 | @media (min-width: 800px) {
31 | .chat-app_thread {
32 | float: left;
33 | width: calc(35% - 1px);
34 | height: inherit;
35 | border-right: 1px solid grey;
36 | }
37 | .chat-app_message {
38 | float: left;
39 | width: 65%;
40 | height: inherit;
41 | }
42 | }
43 |
44 | @media (max-width: 800px) {
45 | .chat-app_thread {
46 | float: top;
47 | height: calc(35% - 1px);
48 | width: inherit;
49 | border-bottom: 1px solid grey;
50 | }
51 | .chat-app_message {
52 | float: bottom;
53 | height: 65%;
54 | width: inherit;
55 | }
56 | }
57 |
58 |
59 | /* layout */
60 |
61 |
62 | /* thread */
63 |
64 | .messenger-title {
65 | line-height: 60px;
66 | margin: 0;
67 | }
68 |
69 | .thread-list {
70 | height: calc(100% - 60px);
71 | overflow: auto;
72 | }
73 |
74 | .thread-item {
75 | position: relative;
76 | height: 80px;
77 | }
78 |
79 | .thread-item_left {
80 | float: left;
81 | width: 90px;
82 | padding: 15px 10px;
83 | height: 80px;
84 | }
85 |
86 | .thread-item_right {
87 | float: left;
88 | width: calc(100% - 90px);
89 | padding: 20px 10px;
90 | border-bottom: 1px solid rgba(0, 0, 0, .10);
91 | height: 80px;
92 | }
93 |
94 | .thread-from {
95 | font-weight: 400;
96 | line-height: 1.4em;
97 | color: black;
98 | }
99 |
100 | .thread-content {
101 | color: rgba(0, 0, 0, .40);
102 | font-size: 14px;
103 | }
104 |
105 | .thread-time {
106 | color: rgba(0, 0, 0, .40);
107 | position: absolute;
108 | top: 23px;
109 | right: 13px;
110 | font-size: 14px;
111 | }
112 |
113 | .img-circle {
114 | border-radius: 50%;
115 | max-width: 70px;
116 | max-height: 60px
117 | }
118 |
119 |
120 | /* message */
121 |
122 | .current-target {
123 | line-height: 60px;
124 | font-size: 16px;
125 | }
126 |
127 | .message-list {
128 | padding-top: 10px;
129 | height: calc(100% - 110px);
130 | overflow: auto;
131 | }
132 |
133 | .message-item {
134 | line-height: 2em;
135 | margin: 10px 0;
136 | }
137 |
138 | .footer {
139 | border-top: 1px solid rgba(0, 0, 0, .10);
140 | height: 50px;
141 | }
142 |
143 | .message-from-other {
144 | padding-left: 25px;
145 | text-align: left;
146 | }
147 |
148 | .message-from-me {
149 | padding-right: 25px;
150 | text-align: right;
151 | }
152 |
153 | .message-from-other span {
154 | display: inline-block;
155 | border-top-left-radius: 1.3em;
156 | border-top-right-radius: 1.3em;
157 | border-bottom-left-radius: 1.3em;
158 | border-bottom-right-radius: 1.3em;
159 | border: 1px solid rgba(0, 0, 0, .10);
160 | padding: 0 15px;
161 | color: black;
162 | background-color: rgba(255, 255, 255, .10);
163 | }
164 |
165 | .message-from-me span {
166 | display: inline-block;
167 | border-top-left-radius: 1.3em;
168 | border-top-right-radius: 1.3em;
169 | border-bottom-left-radius: 1.3em;
170 | border-bottom-right-radius: 1.3em;
171 | padding: 0 15px;
172 | color: white;
173 | background-color: #0084ff;
174 | }
175 |
176 | .new-message {
177 | width: 100%;
178 | height: 100%;
179 | }
180 |
181 |
182 | /* clearfix
183 | * http://stackoverflow.com/questions/211383/which-method-of-clearfix-is-best
184 | */
185 |
186 | .clearfix:before,
187 | .clearfix:after {
188 | content: "";
189 | display: table;
190 | }
191 |
192 | .clearfix:after {
193 | clear: both;
194 | }
195 |
196 | .clearfix {
197 | zoom: 1;
198 | /* For IE 6/7 (trigger hasLayout) */
199 | }
200 |
201 | .attach {
202 | padding-top: 10px;
203 | width: 250px;
204 | }
205 |
--------------------------------------------------------------------------------
/hw6/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 |
3 | module.exports = {
4 | devtool: 'cheap-module-eval-source-map',
5 | entry: './src/entry',
6 | output: {
7 | path: path.join(__dirname, 'dist'),
8 | filename: 'bundle.js',
9 | },
10 | module: {
11 | loaders: [{
12 | test: /\.js$/,
13 | loaders: ['babel'],
14 | exclude: /node_modules/
15 | }, {
16 | test: /\.css$/,
17 | loaders: ['style', 'css'],
18 | exclude: /node_modules/
19 | }]
20 | }
21 | };
22 |
--------------------------------------------------------------------------------
/hw7/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react", "es2015", "stage-0"],
3 | "env": {
4 | "development": {
5 | "presets": ["react-hmre"]
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/hw7/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | }
--------------------------------------------------------------------------------
/hw7/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ChatApp
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/hw7/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hw7",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "topjohnwu",
10 | "license": "ISC",
11 | "dependencies": {
12 | "classnames": "^2.2.4",
13 | "react": "^15.0.1",
14 | "react-dom": "^15.0.1",
15 | "react-router": "^2.3.0",
16 | "webpack": "^1.13.0"
17 | },
18 | "devDependencies": {
19 | "babel-loader": "^6.2.4",
20 | "babel-preset-es2015": "^6.6.0",
21 | "babel-preset-react": "^6.5.0",
22 | "babel-preset-react-hmre": "^1.1.1",
23 | "babel-preset-stage-0": "^6.5.0",
24 | "css-loader": "^0.23.1",
25 | "express": "^4.13.4",
26 | "style-loader": "^0.13.1",
27 | "webpack-dev-middleware": "^1.6.1",
28 | "webpack-hot-middleware": "^2.10.0"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/hw7/server.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var express = require('express');
3 | var webpack = require('webpack');
4 | var config = require('./webpack.config.dev');
5 |
6 | var app = express();
7 | var compiler = webpack(config);
8 |
9 | app.use(require('webpack-dev-middleware')(compiler, {
10 | noInfo: true,
11 | publicPath: config.output.publicPath
12 | }));
13 |
14 | app.use(require('webpack-hot-middleware')(compiler));
15 |
16 | app.get('*', function(req, res) {
17 | res.sendFile(path.join(__dirname, 'index.html'));
18 | });
19 |
20 | app.listen(3000, 'localhost', function(err) {
21 | if (err) { return console.log(err); }
22 | console.log('Listening at http://localhost:3000');
23 | });
--------------------------------------------------------------------------------
/hw7/src/component/ChatApp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ThreadItem from './ThreadItem'
3 | import MessageItem from './MessageItem'
4 | import UserData from './UserData'
5 |
6 | export default class ChatApp extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | this.state = {
10 | contacts: UserData,
11 | current: 0,
12 | idList: [0, 1, 2, 3, 4, 5],
13 | }
14 | this.scroll = false;
15 | }
16 |
17 | /* Mapping functions */
18 |
19 | mapContact(id) {
20 | return ;
21 | }
22 |
23 | mapContent(content, index) {
24 | return ;
25 | }
26 |
27 | /* Function Generators */
28 |
29 | setContact(key) {
30 | function set() {
31 | let input = document.getElementById('input');
32 | input.value = "";
33 | this.setState({ current: key });
34 | }
35 | return set.bind(this);
36 | }
37 |
38 | /* Events */
39 |
40 | input(event) {
41 | if (event.keyCode !== 13) return;
42 | if (event.target.value === "") return;
43 | this.state.contacts[this.state.current].contents.push([event.target.value, true]);
44 | this.state.contacts[this.state.current].time = this.getTime();
45 | event.target.value = "";
46 | this.state.idList.splice(this.state.idList.indexOf(this.state.current), 1);
47 | this.state.idList.unshift(this.state.current);
48 | this.setState({ idList: this.state.idList });
49 | this.scroll = true;
50 | }
51 |
52 |
53 | /* Helper functions */
54 |
55 | getTime() {
56 | let d = new Date(),
57 | hour = d.getHours(),
58 | minute = d.getMinutes();
59 | return (hour % 12 ? hour % 12 : 12) + ":" +
60 | (minute < 10 ? "0" + minute : minute) +
61 | (hour < 12 ? "am" : "pm");
62 | }
63 |
64 | componentDidUpdate() {
65 | if(this.scroll){
66 | let mList = document.getElementById('message-list');
67 | let tList = document.getElementById('thread-list');
68 | mList.scrollTop = mList.scrollHeight;
69 | tList.scrollTop = 0;
70 | this.scroll = false;
71 | }
72 | }
73 |
74 | /* Render */
75 |
76 | render() {
77 | let i = 0;
78 | return (
79 |
80 |
81 |
82 |
中華民國總統會談
83 |
84 |
85 | {this.state.idList.map(this.mapContact.bind(this))}
86 |
87 |
88 |
89 |
90 |
91 | {this.state.contacts[this.state.current].name}
92 |
93 |
94 |
95 | {this.state.contacts[this.state.current].contents.map(this.mapContent.bind(this))}
96 |
97 |
98 |
99 |
100 |
101 |
102 | );
103 | };
104 | };
105 |
--------------------------------------------------------------------------------
/hw7/src/component/MessageItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class MessageItem extends React.Component {
4 | render() {
5 | return (
6 |
7 | {this.props.text}
8 |
9 | );
10 | }
11 | }
12 |
13 | export default MessageItem;
--------------------------------------------------------------------------------
/hw7/src/component/ThreadItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class ThreadItem extends React.Component {
4 | constructor(props, context) {
5 | super(props, context);
6 | }
7 |
8 | static contextTypes = {
9 | router: React.PropTypes.object.isRequired
10 | };
11 |
12 | newPage() {
13 | this.context.router.push(`/users/${this.props.id}`);
14 | }
15 |
16 | render() {
17 | const {name, pic, contents, time} = this.props.contact;
18 | return (
19 |
20 |
21 |
22 |
23 |

24 |
25 |
26 |
{name}
27 |
28 |
29 | {contents.slice(-1)[0][0]}
30 |
31 |
32 |
{time}
33 |
34 |
35 |
36 |
37 | );
38 | }
39 | }
40 |
41 | export default ThreadItem;
--------------------------------------------------------------------------------
/hw7/src/component/UserData.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const UserData =
4 | [{
5 | name: "蔡英文",
6 | pic: "http://i.imgur.com/tSfIYtw.png",
7 | contents: [
8 | ["誒誒你知道你的貼圖現在很夯嗎XD", true],
9 | ["什麼鬼= =", false],
10 | [
, true],
11 | ["...........", false],
12 | ],
13 | time: "11:20pm",
14 | info: "蔡英文(1956年8月31日-)是中華民國政治人物,現任民主進步黨主席,同時為中華民國候任總統(第14任;預計2016年5月20日就任。\
15 | 本籍屏東縣枋山鄉,生於臺北市中山區,學歷至臺灣大學法律學士、美國康乃爾大學法學碩士和英國倫敦政治經濟學院法學博士。\
16 | 留學歸國後,在東吳大學和國立政治大學擔任法學教授,專長為國際貿易法、競爭法等,擔任教職期間亦曾受聘於央行與經濟部擔任關貿總協定以及世貿組織的談判顧問。\
17 | 1990年代在李登輝政府期間擔任智慧財產局委員和國安會經濟諮詢委員;2000年正式踏入政壇,擔任陳水扁政府時期第一任陸委會主委、同時兼任政務委員。\
18 | 2004年加入民主進步黨,並接受黨內提名為不分區立法委員,2006年被延攬擔任行政院副院長至2008年馬英九政府執政止。"
19 | }, {
20 | name: "蔣介石",
21 | pic: "http://i.imgur.com/eb1dwwf.jpg",
22 | contents: [
23 | ["漢賊不兩立!", false],
24 | ["...?", true],
25 | ["退出聯合國!", false],
26 | ["...........?!", true],
27 | ],
28 | time: "2:24pm",
29 | info: "蔣中正(1887年10月31日-1975年4月5日),字介石,原名瑞元,譜名周泰,學名志清。\
30 | 中國近代史著名政治家及軍事家。中華民國國軍特級上將,生於浙江省奉化溪口,逝世於臺北市的士林官邸。\
31 | 早年赴日本學習軍事,並加入中國同盟會。蔣首先是反抗清朝,接著是軍閥混戰,而後是抵抗日本帝國主義入侵。\
32 | 蔣歷任大元帥府參謀長、大本營參謀長、陸軍軍官學校(黃埔軍校)校長、國民革命軍總司令、行政院院長、\
33 | 國民政府軍事委員會委員長、中國國民黨總裁、國民政府主席、三民主義青年團團長、第二次世界大戰同盟國中緬印戰區最高統帥、\
34 | 中華民國總統等職。一再連任第一至五任中華民國總統,並連續當選中國國民黨總裁。蔣中正統治中國大陸近二十年直至中共建政。\
35 | 1950年3月1日,蔣宣布復行視事,直至1975年去世。"
36 | }, {
37 | name: "蔣經國",
38 | pic: "http://i.imgur.com/4ROT3HG.jpg",
39 | contents: [
40 | ["快快快!十大建設!", false],
41 | ["好好好", true],
42 | ["讚讚讚!解嚴囉!", false],
43 | ["呵呵呵", true],
44 | ],
45 | time: "6:18pm",
46 | info: "蔣經國(1910年4月27日-1988年1月13日),字建豐。\
47 | 他是中國國民黨總裁及中華民國總統蔣中正的長子,1975年蔣中正逝世後的中國國民黨主席,\
48 | 同時也是中華民國第六、第七兩任總統,於1988年1月13日的第七任總統任期內逝世。\
49 | 在蘇聯期間,蔣經國接受正統馬列主義教育。回國後他成為三民主義忠實信徒。\
50 | 自1972年擔任行政院院長起,蔣經國於1978年接任中華民國總統,至1988年逝世為止。\
51 | 蔣經國在國際上孤立情勢中,大力發展經濟,解除臺灣多年戒嚴,促進政治民主。"
52 | }, {
53 | name: "李登輝",
54 | pic: "http://i.imgur.com/6QapKnL.jpg",
55 | contents: [
56 | ["這麼晚了你怎麼還不睡?", true],
57 | ["我是第一任民選總統,啊你現在是想怎樣", false],
58 | ["...沒啊,關心你而已啊= =兇啥", true],
59 | ["爺可是日本皇民,休想污辱我", false],
60 | ["日本人可以當台灣總統?", true],
61 | ],
62 | time: "4:13am",
63 | info: "李登輝,(1923年1月15日- ),生於日治臺灣臺北州淡水郡三芝莊下的埔頭坑聚落「源興居」(今新北市三芝區埔坪里)\
64 | ,福佬客家人,農業經濟學家出身,臺灣政治人物。曾任農村復興委員會薦任官員、臺北市長、\
65 | 臺灣省政府主席、副總統等職,並於1988年至2000年擔任中華民國總統以及中國國民黨主席。"
66 | }, {
67 | name: "陳水扁",
68 | pic: "http://i.imgur.com/YcMPPxS.jpg",
69 | contents: [
70 | ["阿扁錯了嗎?", false],
71 | ["誒...你要我怎麼回答", true],
72 | ["阿扁錯了嗎?", false],
73 | ["不要跳針好嗎= =", true],
74 | ["難道阿扁錯了嗎?", false],
75 | ["........你錯了....", true],
76 | ],
77 | time: "12:04am",
78 | info: "陳水扁(1950年10月12日-),臺南市官田人,生於中華民國臺灣省臺南縣官田鄉西莊村(今臺南市官田區西莊里)\
79 | ,律師出身,民主進步黨籍政治人物。曾任海商法律師、中華民國第十、十一任總統(2000年-2008年)。\
80 | 歷任民主進步黨第十屆主席、民主進步黨第十一屆主席、臺北市議會議員、立法委員、臺北市市長、\
81 | 中華民國總統等職。由於涉及龍潭購地案而被判刑20年,三審定讞發監執行,\
82 | 2015年1月5日核准暫時出獄,進行保外就醫。[3][4]2016年2月4日第5次延長保外就醫至2016年5月4日止。"
83 | }, {
84 | name: "馬英九",
85 | pic: "http://i.imgur.com/jJ3bYTi.png",
86 | contents: [
87 | ["一個總統,施政滿意度只剩18%就可以下台了,不下台就是沒有羞恥心!", false],
88 | ["嗯...可是你只有9%誒", true],
89 | ["你說什麼?我聽不到", false],
90 | ["你耳朵長毛嗎?", true],
91 | ["你說什麼?", false],
92 | ],
93 | time: "3:21pm",
94 | info: "馬英九(1950年7月13日-),是中華民國第12任及第13任總統,生於英屬香港九龍油麻地,\
95 | 籍貫湖南省衡山縣,1952年隨雙親定居台灣。中國國民黨籍,曾任中國國民黨副秘書長與黨主席、\
96 | 總統府第一局副局長、行政院研考會主委、陸委會副主委、法務部長與台北市長等職位。"
97 | }]
98 |
99 | export default UserData;
100 |
--------------------------------------------------------------------------------
/hw7/src/entry.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {render} from 'react-dom';
3 | import { Router, Route, browserHistory, IndexRoute } from 'react-router';
4 |
5 | import ChatApp from './component/ChatApp'
6 | import Root from './pages/Root'
7 | import User from './pages/User'
8 | import NotFound from './pages/NotFound'
9 |
10 | import './style.css'
11 |
12 | render(
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | , document.getElementById('root')
24 | );
25 |
26 | // render(, document.getElementById('root'));
--------------------------------------------------------------------------------
/hw7/src/pages/NotFound.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 |
4 | const NotFound = () =>
5 |
6 |
404 Not Found
7 |
8 |
9 |
10 | export default NotFound;
--------------------------------------------------------------------------------
/hw7/src/pages/Root.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router';
3 |
4 | export default class Root extends React.Component {
5 | constructor() {
6 | super();
7 | }
8 | render() {
9 | return (
10 |
11 | Go To Chat app
12 |
13 | );
14 | }
15 | }
--------------------------------------------------------------------------------
/hw7/src/pages/User.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import UserData from '../component/UserData'
3 |
4 | export default class User extends React.Component {
5 | constructor(props) {
6 | super(props);
7 | this.id = this.props.params.username;
8 | }
9 | render() {
10 | return(
11 |
12 |
13 |
14 |

15 |
16 |
{UserData[this.id].name}
17 | {UserData[this.id].info}
18 |
19 |
20 |
21 |
22 |
23 | );
24 | }
25 | }
26 |
27 | // {UserData[this.id].info}
--------------------------------------------------------------------------------
/hw7/src/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | -webkit-box-sizing: border-box;
3 | -moz-box-sizing: border-box;
4 | box-sizing: border-box;
5 | }
6 |
7 | li {
8 | list-style: none;
9 | }
10 |
11 | a {
12 | text-decoration: none;
13 | }
14 |
15 | a:hover {
16 | text-decoration: none;
17 | cursor: pointer;
18 | }
19 |
20 | .heading {
21 | height: 60px;
22 | text-align: center;
23 | border-bottom: 1px solid rgba(0, 0, 0, .10);
24 | }
25 |
26 | .chat-app {
27 | height: 100vh;
28 | }
29 |
30 | @media (min-width: 800px) {
31 | .chat-app_thread {
32 | float: left;
33 | width: calc(35% - 1px);
34 | height: inherit;
35 | border-right: 1px solid grey;
36 | }
37 | .chat-app_message {
38 | float: left;
39 | width: 65%;
40 | height: inherit;
41 | }
42 | }
43 |
44 | @media (max-width: 800px) {
45 | .chat-app_thread {
46 | float: top;
47 | height: calc(35% - 1px);
48 | width: inherit;
49 | border-bottom: 1px solid grey;
50 | }
51 | .chat-app_message {
52 | float: bottom;
53 | height: 65%;
54 | width: inherit;
55 | }
56 | }
57 |
58 |
59 | /* layout */
60 |
61 |
62 | /* thread */
63 |
64 | .messenger-title {
65 | line-height: 60px;
66 | margin: 0;
67 | }
68 |
69 | .thread-list {
70 | height: calc(100% - 60px);
71 | overflow: auto;
72 | }
73 |
74 | .thread-item {
75 | position: relative;
76 | height: 80px;
77 | }
78 |
79 | .thread-item_left {
80 | float: left;
81 | width: 90px;
82 | padding: 15px 10px;
83 | height: 80px;
84 | }
85 |
86 | .thread-item_right {
87 | float: left;
88 | width: calc(100% - 90px);
89 | padding: 20px 10px;
90 | border-bottom: 1px solid rgba(0, 0, 0, .10);
91 | height: 80px;
92 | }
93 |
94 | .thread-from {
95 | font-weight: 400;
96 | line-height: 1.4em;
97 | color: black;
98 | }
99 |
100 | .thread-content {
101 | color: rgba(0, 0, 0, .40);
102 | font-size: 14px;
103 | }
104 |
105 | .thread-time {
106 | color: rgba(0, 0, 0, .40);
107 | position: absolute;
108 | top: 23px;
109 | right: 13px;
110 | font-size: 14px;
111 | }
112 |
113 | .img-circle {
114 | border-radius: 50%;
115 | max-width: 70px;
116 | max-height: 60px
117 | }
118 |
119 |
120 | /* message */
121 |
122 | .current-target {
123 | line-height: 60px;
124 | font-size: 16px;
125 | }
126 |
127 | .message-list {
128 | padding-top: 10px;
129 | height: calc(100% - 110px);
130 | overflow: auto;
131 | }
132 |
133 | .message-item {
134 | line-height: 2em;
135 | margin: 10px 0;
136 | }
137 |
138 | .footer {
139 | border-top: 1px solid rgba(0, 0, 0, .10);
140 | height: 50px;
141 | }
142 |
143 | .message-from-other {
144 | padding-left: 25px;
145 | text-align: left;
146 | }
147 |
148 | .message-from-me {
149 | padding-right: 25px;
150 | text-align: right;
151 | }
152 |
153 | .message-from-other span {
154 | display: inline-block;
155 | border-top-left-radius: 1.3em;
156 | border-top-right-radius: 1.3em;
157 | border-bottom-left-radius: 1.3em;
158 | border-bottom-right-radius: 1.3em;
159 | border: 1px solid rgba(0, 0, 0, .10);
160 | padding: 0 15px;
161 | color: black;
162 | background-color: rgba(255, 255, 255, .10);
163 | }
164 |
165 | .message-from-me span {
166 | display: inline-block;
167 | border-top-left-radius: 1.3em;
168 | border-top-right-radius: 1.3em;
169 | border-bottom-left-radius: 1.3em;
170 | border-bottom-right-radius: 1.3em;
171 | padding: 0 15px;
172 | color: white;
173 | background-color: #0084ff;
174 | }
175 |
176 | .new-message {
177 | width: 100%;
178 | height: 100%;
179 | }
180 |
181 |
182 | /* clearfix
183 | * http://stackoverflow.com/questions/211383/which-method-of-clearfix-is-best
184 | */
185 |
186 | .clearfix:before,
187 | .clearfix:after {
188 | content: "";
189 | display: table;
190 | }
191 |
192 | .clearfix:after {
193 | clear: both;
194 | }
195 |
196 | .clearfix {
197 | zoom: 1;
198 | /* For IE 6/7 (trigger hasLayout) */
199 | }
200 |
201 | .attach {
202 | padding-top: 10px;
203 | width: 250px;
204 | }
205 |
--------------------------------------------------------------------------------
/hw7/webpack.config.dev.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var webpack = require('webpack');
3 |
4 | module.exports = {
5 | devtool: 'cheap-module-eval-source-map',
6 | entry: [
7 | 'webpack-hot-middleware/client',
8 | './src/entry'
9 | ],
10 | output: {
11 | path: path.join(__dirname, 'dist'),
12 | filename: 'bundle.js',
13 | publicPath: '/dist/'
14 | },
15 | plugins: [
16 | new webpack.HotModuleReplacementPlugin(),
17 | new webpack.NoErrorsPlugin()
18 | ],
19 | module: {
20 | loaders: [{
21 | test: /\.js$/,
22 | loaders: ['babel'],
23 | exclude: /node_modules/
24 | },{
25 | test: /\.css$/,
26 | loaders: ['style', 'css'],
27 | exclude: /node_modules/
28 | }]
29 | }
30 | };
--------------------------------------------------------------------------------
/hw7/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 |
3 | module.exports = {
4 | devtool: 'cheap-module-eval-source-map',
5 | entry: './src/entry',
6 | output: {
7 | path: path.join(__dirname, 'dist'),
8 | filename: 'bundle.js',
9 | },
10 | module: {
11 | loaders: [{
12 | test: /\.js$/,
13 | loaders: ['babel'],
14 | exclude: /node_modules/
15 | }, {
16 | test: /\.css$/,
17 | loaders: ['style', 'css'],
18 | exclude: /node_modules/
19 | }],
20 | },
21 | };
22 |
--------------------------------------------------------------------------------
/hw8/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react", "es2015", "stage-0"],
3 | "env": {
4 | "development": {
5 | "presets": ["react-hmre"]
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/hw8/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | public/bundle.js
3 |
--------------------------------------------------------------------------------
/hw8/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extend": "airbnb",
4 | "rules": {
5 | "react/prefer-stateless-function": 0
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/hw8/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 |
--------------------------------------------------------------------------------
/hw8/README.md:
--------------------------------------------------------------------------------
1 | # react-with-express-starter
2 |
3 | > This is a project starter for web seminar course homework.
4 |
5 | ## Run dev server
6 |
7 | ```sh
8 | npm start
9 | ```
10 |
11 | ## Production
12 |
13 | ```sh
14 | npm run build
15 | npm run start:prod
16 | ```
17 |
18 | ## folder structure
19 |
20 | - server/api <- Write your server api code
21 | - src/routes <- Write your react-router routes
22 | - src/components <- Write your components
23 |
--------------------------------------------------------------------------------
/hw8/devServer.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console: 0 */
2 | const path = require('path');
3 | const express = require('express');
4 | const webpack = require('webpack');
5 | const proxy = require('proxy-middleware');
6 | const config = require('./webpack.config.dev');
7 | require('./server/run');
8 |
9 | const API_PORT = 8080;
10 | const DEV_PORT = 3000;
11 |
12 | const app = express();
13 | const compiler = webpack(config);
14 |
15 | app.use(require('webpack-dev-middleware')(compiler, {
16 | noInfo: true,
17 | publicPath: config.output.publicPath,
18 | }));
19 |
20 | app.use(require('webpack-hot-middleware')(compiler));
21 |
22 | app.use('/public', express.static('public'));
23 | app.use('/api', proxy(`http://localhost:${API_PORT}/api`));
24 |
25 | app.get('*', (req, res) => {
26 | res.sendFile(path.join(__dirname, 'index.html'));
27 | });
28 |
29 | app.listen(DEV_PORT, (err) => {
30 | if (err) {
31 | console.log(err);
32 | return;
33 | }
34 |
35 | console.log('Listening at http://localhost:3000');
36 | });
37 |
--------------------------------------------------------------------------------
/hw8/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Chat Room
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/hw8/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-with-express-starter",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "lint": "eslint .",
8 | "start": "node devServer",
9 | "build": "NODE_ENV=production webpack --config webpack.config.prod.js",
10 | "start:prod": "NODE_ENV=production node server/run.js",
11 | "test": "echo \"Error: no test specified\" && exit 1"
12 | },
13 | "keywords": [],
14 | "author": "",
15 | "license": "ISC",
16 | "dependencies": {
17 | "babel-polyfill": "^6.8.0",
18 | "express": "^4.13.4",
19 | "isomorphic-fetch": "^2.2.1",
20 | "morgan": "^1.7.0",
21 | "react": "^15.0.2",
22 | "react-dom": "^15.0.2",
23 | "react-router": "^2.4.0"
24 | },
25 | "devDependencies": {
26 | "babel-eslint": "^6.0.4",
27 | "babel-loader": "^6.2.4",
28 | "babel-preset-es2015": "^6.6.0",
29 | "babel-preset-react": "^6.5.0",
30 | "babel-preset-react-hmre": "^1.1.1",
31 | "babel-preset-stage-0": "^6.5.0",
32 | "css-loader": "^0.23.1",
33 | "eslint": "^2.9.0",
34 | "eslint-config-airbnb": "^8.0.0",
35 | "eslint-plugin-import": "^1.6.1",
36 | "eslint-plugin-jsx-a11y": "^1.0.4",
37 | "eslint-plugin-react": "^5.0.1",
38 | "extract-text-webpack-plugin": "^1.0.1",
39 | "proxy-middleware": "^0.15.0",
40 | "style-loader": "^0.13.1",
41 | "webpack": "^1.13.0",
42 | "webpack-dev-middleware": "^1.6.1",
43 | "webpack-hot-middleware": "^2.10.0"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/hw8/public/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/hw8/public/.keep
--------------------------------------------------------------------------------
/hw8/public/style.css:
--------------------------------------------------------------------------------
1 |
2 | /*# sourceMappingURL=style.css.map*/
--------------------------------------------------------------------------------
/hw8/public/style.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"style.css","sourceRoot":""}
--------------------------------------------------------------------------------
/hw8/server/api.js:
--------------------------------------------------------------------------------
1 | const Router = require('express').Router;
2 | const router = new Router();
3 |
4 | users = [
5 | { name: 'John', age: 23 },
6 | { name: 'Amy', age: 18 },
7 | ]
8 |
9 | router.get('/users/', function(req, res) {
10 | res.json(users);
11 | });
12 |
13 | router.get('/users/:username', function(req, res, next) {
14 | let index = -1;
15 | for (let i = 0; i < users.length; ++i) {
16 | if (req.params.username === users[i].name) {
17 | console.log(users[i]);
18 | index = i;
19 | break;
20 | }
21 | }
22 | if(index !== -1) {
23 | res.json(users[index]);
24 | }
25 | else {
26 | var err = new Error();
27 | err.status = 404;
28 | err.message = "No such user with username: " + req.params.username;
29 | next(err);
30 | }
31 | });
32 |
33 | router.use(function(err, req, res, next) {
34 | console.log("error occurs: " + err.message);
35 | res.status(err.status || 500);
36 | res.send(err);
37 | });
38 |
39 | module.exports = router;
40 |
--------------------------------------------------------------------------------
/hw8/server/app.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const path = require('path');
3 | const logger = require('morgan');
4 | const api = require('./api');
5 |
6 | const app = express();
7 |
8 | app.use(logger('dev'));
9 | app.use('/public', express.static(path.join(__dirname, '..', 'public')));
10 |
11 |
12 | app.use('/api', api);
13 | app.use('*', (req, res) => {
14 | res.sendFile(path.join(__dirname, '..', 'index.html'));
15 | });
16 |
17 |
18 | // error handlers
19 |
20 | // development error handler
21 | // will print stacktrace
22 | if (app.get('env') === 'development') {
23 | app.use((err, req, res, next) => { // eslint-disable-line no-unused-vars
24 | res.status(err.status || 500);
25 | res.render('error', {
26 | message: err.message,
27 | error: err,
28 | });
29 | });
30 | }
31 |
32 | // production error handler
33 | // no stacktraces leaked to user
34 | app.use((err, req, res, next) => { // eslint-disable-line no-unused-vars
35 | res.status(err.status || 500);
36 | res.render('error', {
37 | message: err.message,
38 | error: {},
39 | });
40 | });
41 |
42 |
43 | module.exports = app;
44 |
--------------------------------------------------------------------------------
/hw8/server/run.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console: 0 */
2 | const APIServer = require('./app');
3 |
4 | const API_PORT = 8080;
5 |
6 | APIServer.listen(API_PORT, () => {
7 | console.log(
8 | `API Server is now running on http://localhost:${API_PORT}`
9 | );
10 | });
11 |
--------------------------------------------------------------------------------
/hw8/src/components/NotFoundPage.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class NotFoundPage extends Component {
4 | render() {
5 | return (
6 | NotFoundPage
7 | );
8 | }
9 | }
10 |
11 | export default NotFoundPage;
12 |
--------------------------------------------------------------------------------
/hw8/src/components/SingleUserPage.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/hw8/src/components/SingleUserPage.css
--------------------------------------------------------------------------------
/hw8/src/components/SingleUserPage.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import 'babel-polyfill';
3 | import fetch from 'isomorphic-fetch';
4 |
5 | import './SingleUserPage.css';
6 | import NotFoundPage from './NotFoundPage'
7 |
8 | class SingleUserPage extends Component {
9 | constructor(props, context) {
10 | super(props, context);
11 | this.state = {
12 | user: null,
13 | };
14 | }
15 |
16 | setUser(json) {
17 | console.log(json.status);
18 | this.setState( {user: json} );
19 | }
20 |
21 | componentDidMount() {
22 | fetch(`/api/users/${this.props.params.username}`)
23 | .then(function(res) {
24 | return res.json();
25 | })
26 | .then(this.setUser.bind(this))
27 | .catch(function(err) {
28 | console.log("Error!!!!!");
29 | });
30 | }
31 |
32 |
33 | render() {
34 | if(this.state.user === null) return null;
35 | return (
36 |
37 |
SingleUserPage
38 |
{'Name: ' + this.state.user.name + ' / Age: ' + this.state.user.age}
39 |
40 | );
41 | }
42 | }
43 |
44 | export default SingleUserPage;
45 |
--------------------------------------------------------------------------------
/hw8/src/components/UsersPage.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/hw8/src/components/UsersPage.css
--------------------------------------------------------------------------------
/hw8/src/components/UsersPage.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import 'babel-polyfill';
3 | import fetch from 'isomorphic-fetch';
4 |
5 | import './UsersPage.css';
6 |
7 | class UsersPage extends Component {
8 | constructor(props, context) {
9 | super(props, context);
10 | this.state = {
11 | users: [],
12 | };
13 | }
14 |
15 | static contextTypes = {
16 | router: React.PropTypes.object.isRequired
17 | };
18 |
19 | setUsers(json) {
20 | console.log(json);
21 | this.setState( {users: json} );
22 | }
23 |
24 | mapUser(user) {
25 | return (
26 | {this.context.router.push(`/users/${user.name}`)} }>
27 | {'Name: ' + user.name}
28 | )
29 | }
30 |
31 | componentDidMount() {
32 | fetch('/api/users')
33 | .then(function(res) {
34 | return res.json();
35 | })
36 | .then(this.setUsers.bind(this))
37 | .catch(function(err) {
38 | console.log(err);
39 | });
40 | }
41 |
42 | render() {
43 | return (
44 |
45 |
UsersPage
46 | {this.state.users.map(this.mapUser.bind(this))}
47 |
48 | );
49 | }
50 | }
51 |
52 | export default UsersPage;
53 |
--------------------------------------------------------------------------------
/hw8/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from 'react-dom';
3 | import { Router, browserHistory } from 'react-router';
4 | import routes from './routes';
5 |
6 | render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/hw8/src/routes.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Route, IndexRedirect, IndexRoute } from 'react-router';
3 | import UsersPage from './components/UsersPage';
4 | import SingleUserPage from './components/SingleUserPage';
5 | import NotFoundPage from './components/NotFoundPage';
6 |
7 |
8 | export default (
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | );
18 |
--------------------------------------------------------------------------------
/hw8/webpack.config.dev.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var webpack = require('webpack');
3 |
4 | module.exports = {
5 | devtool: 'cheap-module-eval-source-map',
6 | entry: [
7 | 'webpack-hot-middleware/client',
8 | './src/index',
9 | ],
10 | output: {
11 | path: path.join(__dirname, 'public'),
12 | filename: 'bundle.js',
13 | publicPath: '/public/',
14 | },
15 | module: {
16 | loaders: [{
17 | test: /\.js$/,
18 | loaders: ['babel'],
19 | include: path.join(__dirname, 'src'),
20 | }, {
21 | test: /\.css$/,
22 | loaders: ['style', 'css'],
23 | }],
24 | },
25 | plugins: [
26 | new webpack.HotModuleReplacementPlugin(),
27 | new webpack.NoErrorsPlugin(),
28 | ],
29 | };
30 |
--------------------------------------------------------------------------------
/hw8/webpack.config.prod.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var webpack = require('webpack');
3 | var ExtractTextPlugin = require('extract-text-webpack-plugin');
4 |
5 | module.exports = {
6 | devtool: 'source-map',
7 | entry: './src/index',
8 | output: {
9 | path: path.join(__dirname, 'public'),
10 | filename: 'bundle.js',
11 | publicPath: '/public/',
12 | },
13 | module: {
14 | loaders: [{
15 | test: /\.js$/,
16 | loaders: ['babel'],
17 | include: path.join(__dirname, 'src'),
18 | }, {
19 | test: /\.css$/,
20 | loader: ExtractTextPlugin.extract('style-loader', 'css-loader'),
21 | }],
22 | },
23 | plugins: [
24 | new webpack.optimize.OccurenceOrderPlugin(),
25 | new webpack.optimize.UglifyJsPlugin({
26 | compress: {
27 | screw_ie8: true,
28 | warnings: false,
29 | },
30 | }),
31 | new ExtractTextPlugin('style.css', { allChunks: true }),
32 | ],
33 | };
34 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
14 | Web-programming-project by topjohnwu
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Web-programming-project
23 | A central repo for all assignments for the Web Programming Project
24 |
25 |
26 |
32 |
33 |
34 |
35 |
36 |
40 |
41 |
54 |
55 |
56 |
57 |
58 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/index/images/body-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/index/images/body-bg.png
--------------------------------------------------------------------------------
/index/images/highlight-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/index/images/highlight-bg.jpg
--------------------------------------------------------------------------------
/index/images/hr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/index/images/hr.png
--------------------------------------------------------------------------------
/index/images/octocat-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/index/images/octocat-icon.png
--------------------------------------------------------------------------------
/index/images/tar-gz-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/index/images/tar-gz-icon.png
--------------------------------------------------------------------------------
/index/images/zip-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/topjohnwu/Web-Programming-Project/822ff112c0c1e0ac143a986fffb5064344c8540f/index/images/zip-icon.png
--------------------------------------------------------------------------------
/index/javascripts/main.js:
--------------------------------------------------------------------------------
1 | console.log('This would be the main JS file.');
2 |
--------------------------------------------------------------------------------
/index/stylesheets/github-dark.css:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2014 GitHub Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | */
17 |
18 | .pl-c /* comment */ {
19 | color: #969896;
20 | }
21 |
22 | .pl-c1 /* constant, markup.raw, meta.diff.header, meta.module-reference, meta.property-name, support, support.constant, support.variable, variable.other.constant */,
23 | .pl-s .pl-v /* string variable */ {
24 | color: #0099cd;
25 | }
26 |
27 | .pl-e /* entity */,
28 | .pl-en /* entity.name */ {
29 | color: #9774cb;
30 | }
31 |
32 | .pl-s .pl-s1 /* string source */,
33 | .pl-smi /* storage.modifier.import, storage.modifier.package, storage.type.java, variable.other, variable.parameter.function */ {
34 | color: #ddd;
35 | }
36 |
37 | .pl-ent /* entity.name.tag */ {
38 | color: #7bcc72;
39 | }
40 |
41 | .pl-k /* keyword, storage, storage.type */ {
42 | color: #cc2372;
43 | }
44 |
45 | .pl-pds /* punctuation.definition.string, string.regexp.character-class */,
46 | .pl-s /* string */,
47 | .pl-s .pl-pse .pl-s1 /* string punctuation.section.embedded source */,
48 | .pl-sr /* string.regexp */,
49 | .pl-sr .pl-cce /* string.regexp constant.character.escape */,
50 | .pl-sr .pl-sra /* string.regexp string.regexp.arbitrary-repitition */,
51 | .pl-sr .pl-sre /* string.regexp source.ruby.embedded */ {
52 | color: #3c66e2;
53 | }
54 |
55 | .pl-v /* variable */ {
56 | color: #fb8764;
57 | }
58 |
59 | .pl-id /* invalid.deprecated */ {
60 | color: #e63525;
61 | }
62 |
63 | .pl-ii /* invalid.illegal */ {
64 | background-color: #e63525;
65 | color: #f8f8f8;
66 | }
67 |
68 | .pl-sr .pl-cce /* string.regexp constant.character.escape */ {
69 | color: #7bcc72;
70 | font-weight: bold;
71 | }
72 |
73 | .pl-ml /* markup.list */ {
74 | color: #c26b2b;
75 | }
76 |
77 | .pl-mh /* markup.heading */,
78 | .pl-mh .pl-en /* markup.heading entity.name */,
79 | .pl-ms /* meta.separator */ {
80 | color: #264ec5;
81 | font-weight: bold;
82 | }
83 |
84 | .pl-mq /* markup.quote */ {
85 | color: #00acac;
86 | }
87 |
88 | .pl-mi /* markup.italic */ {
89 | color: #ddd;
90 | font-style: italic;
91 | }
92 |
93 | .pl-mb /* markup.bold */ {
94 | color: #ddd;
95 | font-weight: bold;
96 | }
97 |
98 | .pl-md /* markup.deleted, meta.diff.header.from-file */ {
99 | background-color: #ffecec;
100 | color: #bd2c00;
101 | }
102 |
103 | .pl-mi1 /* markup.inserted, meta.diff.header.to-file */ {
104 | background-color: #eaffea;
105 | color: #55a532;
106 | }
107 |
108 | .pl-mdr /* meta.diff.range */ {
109 | color: #9774cb;
110 | font-weight: bold;
111 | }
112 |
113 | .pl-mo /* meta.output */ {
114 | color: #264ec5;
115 | }
116 |
117 |
--------------------------------------------------------------------------------
/index/stylesheets/print.css:
--------------------------------------------------------------------------------
1 | html, body, div, span, applet, object, iframe,
2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
3 | a, abbr, acronym, address, big, cite, code,
4 | del, dfn, em, img, ins, kbd, q, s, samp,
5 | small, strike, strong, sub, sup, tt, var,
6 | b, u, i, center,
7 | dl, dt, dd, ol, ul, li,
8 | fieldset, form, label, legend,
9 | table, caption, tbody, tfoot, thead, tr, th, td,
10 | article, aside, canvas, details, embed,
11 | figure, figcaption, footer, header, hgroup,
12 | menu, nav, output, ruby, section, summary,
13 | time, mark, audio, video {
14 | padding: 0;
15 | margin: 0;
16 | font: inherit;
17 | font-size: 100%;
18 | vertical-align: baseline;
19 | border: 0;
20 | }
21 | /* HTML5 display-role reset for older browsers */
22 | article, aside, details, figcaption, figure,
23 | footer, header, hgroup, menu, nav, section {
24 | display: block;
25 | }
26 | body {
27 | line-height: 1;
28 | }
29 | ol, ul {
30 | list-style: none;
31 | }
32 | blockquote, q {
33 | quotes: none;
34 | }
35 | blockquote:before, blockquote:after,
36 | q:before, q:after {
37 | content: '';
38 | content: none;
39 | }
40 | table {
41 | border-spacing: 0;
42 | border-collapse: collapse;
43 | }
44 | body {
45 | font-family: 'Helvetica Neue', Helvetica, Arial, serif;
46 | font-size: 13px;
47 | line-height: 1.5;
48 | color: #000;
49 | }
50 |
51 | a {
52 | font-weight: bold;
53 | color: #d5000d;
54 | }
55 |
56 | header {
57 | padding-top: 35px;
58 | padding-bottom: 10px;
59 | }
60 |
61 | header h1 {
62 | font-size: 48px;
63 | font-weight: bold;
64 | line-height: 1.2;
65 | color: #303030;
66 | letter-spacing: -1px;
67 | }
68 |
69 | header h2 {
70 | font-size: 24px;
71 | font-weight: normal;
72 | line-height: 1.3;
73 | color: #aaa;
74 | letter-spacing: -1px;
75 | }
76 | #downloads {
77 | display: none;
78 | }
79 | #main_content {
80 | padding-top: 20px;
81 | }
82 |
83 | code, pre {
84 | margin-bottom: 30px;
85 | font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal;
86 | font-size: 12px;
87 | color: #222;
88 | }
89 |
90 | code {
91 | padding: 0 3px;
92 | }
93 |
94 | pre {
95 | padding: 20px;
96 | overflow: auto;
97 | border: solid 1px #ddd;
98 | }
99 | pre code {
100 | padding: 0;
101 | }
102 |
103 | ul, ol, dl {
104 | margin-bottom: 20px;
105 | }
106 |
107 |
108 | /* COMMON STYLES */
109 |
110 | table {
111 | width: 100%;
112 | border: 1px solid #ebebeb;
113 | }
114 |
115 | th {
116 | font-weight: 500;
117 | }
118 |
119 | td {
120 | font-weight: 300;
121 | text-align: center;
122 | border: 1px solid #ebebeb;
123 | }
124 |
125 | form {
126 | padding: 20px;
127 | background: #f2f2f2;
128 |
129 | }
130 |
131 |
132 | /* GENERAL ELEMENT TYPE STYLES */
133 |
134 | h1 {
135 | font-size: 2.8em;
136 | }
137 |
138 | h2 {
139 | margin-bottom: 8px;
140 | font-size: 22px;
141 | font-weight: bold;
142 | color: #303030;
143 | }
144 |
145 | h3 {
146 | margin-bottom: 8px;
147 | font-size: 18px;
148 | font-weight: bold;
149 | color: #d5000d;
150 | }
151 |
152 | h4 {
153 | font-size: 16px;
154 | font-weight: bold;
155 | color: #303030;
156 | }
157 |
158 | h5 {
159 | font-size: 1em;
160 | color: #303030;
161 | }
162 |
163 | h6 {
164 | font-size: .8em;
165 | color: #303030;
166 | }
167 |
168 | p {
169 | margin-bottom: 20px;
170 | font-weight: 300;
171 | }
172 |
173 | a {
174 | text-decoration: none;
175 | }
176 |
177 | p a {
178 | font-weight: 400;
179 | }
180 |
181 | blockquote {
182 | padding: 0 0 0 30px;
183 | margin-bottom: 20px;
184 | font-size: 1.6em;
185 | border-left: 10px solid #e9e9e9;
186 | }
187 |
188 | ul li {
189 | list-style-position: inside;
190 | list-style: disc;
191 | padding-left: 20px;
192 | }
193 |
194 | ol li {
195 | list-style-position: inside;
196 | list-style: decimal;
197 | padding-left: 3px;
198 | }
199 |
200 | dl dd {
201 | font-style: italic;
202 | font-weight: 100;
203 | }
204 |
205 | footer {
206 | padding-top: 20px;
207 | padding-bottom: 30px;
208 | margin-top: 40px;
209 | font-size: 13px;
210 | color: #aaa;
211 | }
212 |
213 | footer a {
214 | color: #666;
215 | }
216 |
217 | /* MISC */
218 | .clearfix:after {
219 | display: block;
220 | height: 0;
221 | clear: both;
222 | visibility: hidden;
223 | content: '.';
224 | }
225 |
226 | .clearfix {display: inline-block;}
227 | * html .clearfix {height: 1%;}
228 | .clearfix {display: block;}
229 |
--------------------------------------------------------------------------------
/index/stylesheets/selfdefine.css:
--------------------------------------------------------------------------------
1 | .self a {
2 | color: black;
3 | font-size: 23px;
4 | }
5 |
6 | .self a:hover {
7 | text-decoration: underline;
8 | }
--------------------------------------------------------------------------------
/index/stylesheets/stylesheet.css:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/
2 | v2.0 | 20110126
3 | License: none (public domain)
4 | */
5 | html, body, div, span, applet, object, iframe,
6 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
7 | a, abbr, acronym, address, big, cite, code,
8 | del, dfn, em, img, ins, kbd, q, s, samp,
9 | small, strike, strong, sub, sup, tt, var,
10 | b, u, i, center,
11 | dl, dt, dd, ol, ul, li,
12 | fieldset, form, label, legend,
13 | table, caption, tbody, tfoot, thead, tr, th, td,
14 | article, aside, canvas, details, embed,
15 | figure, figcaption, footer, header, hgroup,
16 | menu, nav, output, ruby, section, summary,
17 | time, mark, audio, video {
18 | padding: 0;
19 | margin: 0;
20 | font: inherit;
21 | font-size: 100%;
22 | vertical-align: baseline;
23 | border: 0;
24 | }
25 | /* HTML5 display-role reset for older browsers */
26 | article, aside, details, figcaption, figure,
27 | footer, header, hgroup, menu, nav, section {
28 | display: block;
29 | }
30 | body {
31 | line-height: 1;
32 | }
33 | ol, ul {
34 | list-style: none;
35 | }
36 | blockquote, q {
37 | quotes: none;
38 | }
39 | blockquote:before, blockquote:after,
40 | q:before, q:after {
41 | content: '';
42 | content: none;
43 | }
44 | table {
45 | border-spacing: 0;
46 | border-collapse: collapse;
47 | }
48 |
49 | /* LAYOUT STYLES */
50 | body {
51 | font-family: 'Helvetica Neue', Helvetica, Arial, serif;
52 | font-size: 1em;
53 | line-height: 1.5;
54 | color: #6d6d6d;
55 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8);
56 | background: #e7e7e7 url(../images/body-bg.png) 0 0 repeat;
57 | }
58 |
59 | a {
60 | color: #d5000d;
61 | }
62 | a:hover {
63 | color: #c5000c;
64 | }
65 |
66 | header {
67 | padding-top: 35px;
68 | padding-bottom: 25px;
69 | }
70 |
71 | header h1 {
72 | font-family: 'Chivo', 'Helvetica Neue', Helvetica, Arial, serif;
73 | font-size: 48px; font-weight: 900;
74 | line-height: 1.2;
75 | color: #303030;
76 | letter-spacing: -1px;
77 | }
78 |
79 | header h2 {
80 | font-size: 24px;
81 | font-weight: normal;
82 | line-height: 1.3;
83 | color: #aaa;
84 | letter-spacing: -1px;
85 | }
86 |
87 | #container {
88 | min-height: 595px;
89 | background: transparent url(../images/highlight-bg.jpg) 50% 0 no-repeat;
90 | }
91 |
92 | .inner {
93 | width: 620px;
94 | margin: 0 auto;
95 | }
96 |
97 | #container .inner img {
98 | max-width: 100%;
99 | }
100 |
101 | #downloads {
102 | margin-bottom: 40px;
103 | }
104 |
105 | a.button {
106 | display: block;
107 | float: left;
108 | width: 179px;
109 | padding: 12px 8px 12px 8px;
110 | margin-right: 14px;
111 | font-size: 15px;
112 | font-weight: bold;
113 | line-height: 25px;
114 | color: #303030;
115 | background: #fdfdfd; /* Old browsers */
116 | background: -moz-linear-gradient(top, #fdfdfd 0%, #f2f2f2 100%); /* FF3.6+ */
117 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#fdfdfd), color-stop(100%,#f2f2f2)); /* Chrome,Safari4+ */
118 | background: -webkit-linear-gradient(top, #fdfdfd 0%,#f2f2f2 100%); /* Chrome10+,Safari5.1+ */
119 | background: -o-linear-gradient(top, #fdfdfd 0%,#f2f2f2 100%); /* Opera 11.10+ */
120 | background: -ms-linear-gradient(top, #fdfdfd 0%,#f2f2f2 100%); /* IE10+ */
121 | background: linear-gradient(top, #fdfdfd 0%,#f2f2f2 100%); /* W3C */
122 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fdfdfd', endColorstr='#f2f2f2',GradientType=0 ); /* IE6-9 */
123 | border-top: solid 1px #cbcbcb;
124 | border-right: solid 1px #b7b7b7;
125 | border-bottom: solid 1px #b3b3b3;
126 | border-left: solid 1px #b7b7b7;
127 | border-radius: 30px;
128 | -webkit-box-shadow: 10px 10px 5px #888;
129 | -moz-box-shadow: 10px 10px 5px #888;
130 | box-shadow: 0px 1px 5px #e8e8e8;
131 | -moz-border-radius: 30px;
132 | -webkit-border-radius: 30px;
133 | }
134 | a.button:hover {
135 | background: #fafafa; /* Old browsers */
136 | background: -moz-linear-gradient(top, #fdfdfd 0%, #f6f6f6 100%); /* FF3.6+ */
137 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#fdfdfd), color-stop(100%,#f6f6f6)); /* Chrome,Safari4+ */
138 | background: -webkit-linear-gradient(top, #fdfdfd 0%,#f6f6f6 100%); /* Chrome10+,Safari5.1+ */
139 | background: -o-linear-gradient(top, #fdfdfd 0%,#f6f6f6 100%); /* Opera 11.10+ */
140 | background: -ms-linear-gradient(top, #fdfdfd 0%,#f6f6f6 100%); /* IE10+ */
141 | background: linear-gradient(top, #fdfdfd 0%,#f6f6f6, 100%); /* W3C */
142 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fdfdfd', endColorstr='#f6f6f6',GradientType=0 ); /* IE6-9 */
143 | border-top: solid 1px #b7b7b7;
144 | border-right: solid 1px #b3b3b3;
145 | border-bottom: solid 1px #b3b3b3;
146 | border-left: solid 1px #b3b3b3;
147 | }
148 |
149 | a.button span {
150 | display: block;
151 | height: 23px;
152 | padding-left: 50px;
153 | }
154 |
155 | #download-zip span {
156 | background: transparent url(../images/zip-icon.png) 12px 50% no-repeat;
157 | }
158 | #download-tar-gz span {
159 | background: transparent url(../images/tar-gz-icon.png) 12px 50% no-repeat;
160 | }
161 | #view-on-github span {
162 | background: transparent url(../images/octocat-icon.png) 12px 50% no-repeat;
163 | }
164 | #view-on-github {
165 | margin-right: 0;
166 | }
167 |
168 | code, pre {
169 | margin-bottom: 30px;
170 | font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal;
171 | font-size: 14px;
172 | color: #222;
173 | }
174 |
175 | code {
176 | padding: 0 3px;
177 | background-color: #f2f2f2;
178 | border: solid 1px #ddd;
179 | }
180 |
181 | pre {
182 | padding: 20px;
183 | overflow: auto;
184 | color: #f2f2f2;
185 | text-shadow: none;
186 | background: #303030;
187 | }
188 | pre code {
189 | padding: 0;
190 | color: #f2f2f2;
191 | background-color: #303030;
192 | border: none;
193 | }
194 |
195 | ul, ol, dl {
196 | margin-bottom: 20px;
197 | }
198 |
199 |
200 | /* COMMON STYLES */
201 |
202 | hr {
203 | height: 1px;
204 | padding-bottom: 1em;
205 | margin-top: 1em;
206 | line-height: 1px;
207 | background: transparent url('../images/hr.png') 50% 0 no-repeat;
208 | border: none;
209 | }
210 |
211 | strong {
212 | font-weight: bold;
213 | }
214 |
215 | em {
216 | font-style: italic;
217 | }
218 |
219 | table {
220 | width: 100%;
221 | border: 1px solid #ebebeb;
222 | }
223 |
224 | th {
225 | font-weight: 500;
226 | }
227 |
228 | td {
229 | font-weight: 300;
230 | text-align: center;
231 | border: 1px solid #ebebeb;
232 | }
233 |
234 | form {
235 | padding: 20px;
236 | background: #f2f2f2;
237 |
238 | }
239 |
240 |
241 | /* GENERAL ELEMENT TYPE STYLES */
242 |
243 | h1 {
244 | font-size: 32px;
245 | }
246 |
247 | h2 {
248 | margin-bottom: 8px;
249 | font-size: 22px;
250 | font-weight: bold;
251 | color: #303030;
252 | }
253 |
254 | h3 {
255 | margin-bottom: 8px;
256 | font-size: 18px;
257 | font-weight: bold;
258 | color: #d5000d;
259 | }
260 |
261 | h4 {
262 | font-size: 16px;
263 | font-weight: bold;
264 | color: #303030;
265 | }
266 |
267 | h5 {
268 | font-size: 1em;
269 | color: #303030;
270 | }
271 |
272 | h6 {
273 | font-size: .8em;
274 | color: #303030;
275 | }
276 |
277 | p {
278 | margin-bottom: 20px;
279 | font-weight: 300;
280 | }
281 |
282 | a {
283 | text-decoration: none;
284 | }
285 |
286 | p a {
287 | font-weight: 400;
288 | }
289 |
290 | blockquote {
291 | padding: 0 0 0 30px;
292 | margin-bottom: 20px;
293 | font-size: 1.6em;
294 | border-left: 10px solid #e9e9e9;
295 | }
296 |
297 | ul li {
298 | list-style-position: inside;
299 | list-style: disc;
300 | padding-left: 20px;
301 | }
302 |
303 | ol li {
304 | list-style-position: inside;
305 | list-style: decimal;
306 | padding-left: 3px;
307 | }
308 |
309 | dl dt {
310 | color: #303030;
311 | }
312 |
313 | footer {
314 | padding-top: 20px;
315 | padding-bottom: 30px;
316 | margin-top: 40px;
317 | font-size: 13px;
318 | color: #aaa;
319 | background: transparent url('../images/hr.png') 0 0 no-repeat;
320 | }
321 |
322 | footer a {
323 | color: #666;
324 | }
325 | footer a:hover {
326 | color: #444;
327 | }
328 |
329 | /* MISC */
330 | .clearfix:after {
331 | display: block;
332 | height: 0;
333 | clear: both;
334 | visibility: hidden;
335 | content: '.';
336 | }
337 |
338 | .clearfix {display: inline-block;}
339 | * html .clearfix {height: 1%;}
340 | .clearfix {display: block;}
341 |
342 | /* #Media Queries
343 | ================================================== */
344 |
345 | /* Smaller than standard 960 (devices and browsers) */
346 | @media only screen and (max-width: 959px) { }
347 |
348 | /* Tablet Portrait size to standard 960 (devices and browsers) */
349 | @media only screen and (min-width: 768px) and (max-width: 959px) { }
350 |
351 | /* All Mobile Sizes (devices and browser) */
352 | @media only screen and (max-width: 767px) {
353 | header {
354 | padding-top: 10px;
355 | padding-bottom: 10px;
356 | }
357 | #downloads {
358 | margin-bottom: 25px;
359 | }
360 | #download-zip, #download-tar-gz {
361 | display: none;
362 | }
363 | .inner {
364 | width: 94%;
365 | margin: 0 auto;
366 | }
367 | }
368 |
369 | /* Mobile Landscape Size to Tablet Portrait (devices and browsers) */
370 | @media only screen and (min-width: 480px) and (max-width: 767px) { }
371 |
372 | /* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) */
373 | @media only screen and (max-width: 479px) { }
374 |
--------------------------------------------------------------------------------
/params.json:
--------------------------------------------------------------------------------
1 | {"name":"Web-programming-project","tagline":"","body":"#Web Programming Project\r\n\r\nA central repo for all assignments.","google":"","note":"Don't delete this file! It's used internally to help with page regeneration."}
--------------------------------------------------------------------------------