├── .gitignore
├── BeautyBot
├── app.js
├── config
│ └── default.json
└── package.json
├── BeautyTab.zip
├── BeautyTab
├── _locales
│ └── en
│ │ └── messages.json
├── icons
│ ├── icon128.png
│ ├── icon16.png
│ ├── icon19.png
│ └── icon48.png
├── manifest.json
└── src
│ ├── bg
│ ├── background.html
│ └── background.js
│ ├── browser_action
│ └── browser_action.html
│ ├── options
│ └── index.html
│ └── override
│ ├── main.js
│ └── override.html
├── CountdownTimer
└── index.html
├── CurrencyExchange
├── index.html
└── main.js
├── MosquitoFight
├── images
│ └── mosquito.png
├── index.html
└── main.css
├── OpenData
├── index.html
└── loading.gif
├── PTTCrawler
├── app.js
├── package.json
└── results.json
├── QA
└── mosquito.html
├── README.md
├── ReactTodo
└── index.html
├── SimepleJS
└── index.html
├── SimplejQuery
├── 1.jpg
├── 2.jpg
├── 3.jpg
├── index.html
└── jquery.bxslider
│ ├── LICENSE.md
│ ├── README.md
│ ├── images
│ ├── bx_loader.gif
│ └── controls.png
│ ├── jquery.bxslider.css
│ ├── jquery.bxslider.js
│ ├── jquery.bxslider.min.css
│ ├── jquery.bxslider.min.js
│ └── vendor
│ ├── jquery.easing.1.3.js
│ └── jquery.fitvids.js
├── SlideShow
├── 1.jpg
├── 2.jpg
├── 3.jpg
└── index.html
├── SocketChat
├── app.js
├── index.html
└── package.json
├── WifiMap
├── index.html
└── itw_tw.json
└── lectures
├── README.md
├── Unit01
└── examples
│ └── PokemonFight
│ ├── index.html
│ ├── main.css
│ └── main.js
├── Unit02
└── examples
│ └── SimpleJS
│ └── index.html
├── Unit03
└── examples
│ ├── example.json
│ ├── index.html
│ └── main.js
├── Unit06
└── examples
│ ├── CurrencyExchange
│ ├── index.html
│ └── main.js
│ └── MosquitoFight
│ ├── css
│ └── main.css
│ ├── images
│ └── mosquito.png
│ └── index.html
├── Unit07
└── examples
│ └── TodoJS
│ └── index.html
├── Unit08
├── README.md
└── examples
│ └── CountdownTimer
│ └── index.html
├── Unit09
├── README.md
└── examples
│ └── MosquitoFight
│ ├── css
│ └── main.css
│ ├── images
│ └── mosquito.png
│ └── index.html
├── Unit10
└── examples
│ └── SlideShow
│ ├── 1.jpg
│ ├── 2.jpg
│ ├── 3.jpg
│ └── index.html
├── Unit11
├── README.md
└── examples
│ └── OpenData
│ ├── index.html
│ └── loading.gif
├── Unit12
└── SimpleJQuery
│ ├── 1.jpg
│ ├── 2.jpg
│ ├── 3.jpg
│ ├── index.html
│ └── jquery.bxslider
│ ├── LICENSE.md
│ ├── README.md
│ ├── images
│ ├── bx_loader.gif
│ └── controls.png
│ ├── jquery.bxslider.css
│ ├── jquery.bxslider.js
│ ├── jquery.bxslider.min.css
│ ├── jquery.bxslider.min.js
│ └── vendor
│ ├── jquery.easing.1.3.js
│ └── jquery.fitvids.js
├── Unit13
└── examples
│ └── TodoJS
│ └── index.html
├── Unit14
├── README.md
└── examples
│ └── BeautyTab
│ ├── _locales
│ └── en
│ │ └── messages.json
│ ├── icons
│ ├── icon128.png
│ ├── icon16.png
│ ├── icon19.png
│ └── icon48.png
│ ├── manifest.json
│ └── src
│ ├── bg
│ ├── background.html
│ └── background.js
│ ├── options
│ └── index.html
│ └── override
│ ├── main.js
│ └── override.html
├── Unit15
└── README.md
├── Unit16
├── README.md
├── examples
│ └── node-irich
│ │ ├── 127.0.0.1
│ │ ├── app.js
│ │ ├── bin
│ │ └── www
│ │ ├── config
│ │ └── config.json
│ │ ├── models
│ │ ├── account.js
│ │ └── index.js
│ │ ├── package.json
│ │ ├── public
│ │ └── stylesheets
│ │ │ └── style.css
│ │ ├── routes
│ │ ├── accounts.js
│ │ └── index.js
│ │ └── views
│ │ ├── account.ejs
│ │ ├── create_account.ejs
│ │ ├── error.ejs
│ │ ├── index.ejs
│ │ └── update_account.ejs
└── node-irich
│ ├── 127.0.0.1
│ ├── app.js
│ ├── bin
│ └── www
│ ├── config
│ └── config.json
│ ├── models
│ ├── account.js
│ └── index.js
│ ├── package.json
│ ├── public
│ └── stylesheets
│ │ └── style.css
│ ├── routes
│ ├── accounts.js
│ └── index.js
│ └── views
│ ├── account.ejs
│ ├── create_account.ejs
│ ├── error.ejs
│ ├── index.ejs
│ └── update_account.ejs
├── Unit17
├── README.md
└── examples
│ └── socket-chat
│ ├── app.js
│ ├── index.html
│ ├── package-lock.json
│ └── package.json
├── Unit18
├── README.md
└── examples
│ └── BeautyBot
│ ├── app.js
│ ├── config
│ └── default.json
│ └── package.json
├── Unit20
└── README.md
├── Unit21
└── examples
│ ├── index.html
│ └── itw_tw.json
├── Unit22
└── examples
│ ├── app.js
│ ├── package.json
│ └── result.json
├── Unit23
├── ajax-node-irich
│ ├── .gitignore
│ ├── 127.0.0.1
│ ├── Profile
│ ├── app.js
│ ├── bin
│ │ └── www
│ ├── config
│ │ └── config.json
│ ├── migrations
│ │ └── 20170418152012-create-task.js
│ ├── models
│ │ ├── account.js
│ │ └── index.js
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ │ └── stylesheets
│ │ │ └── style.css
│ ├── routes
│ │ ├── accounts.js
│ │ ├── apiRoutes.js
│ │ └── index.js
│ └── views
│ │ ├── account.ejs
│ │ ├── create_account.ejs
│ │ ├── error.ejs
│ │ ├── index.ejs
│ │ └── update_account.ejs
└── examples
│ └── ajax-node-irich
│ ├── .gitignore
│ ├── 127.0.0.1
│ ├── Profile
│ ├── app.js
│ ├── bin
│ └── www
│ ├── config
│ └── config.json
│ ├── migrations
│ └── 20170418152012-create-task.js
│ ├── models
│ ├── account.js
│ └── index.js
│ ├── package.json
│ ├── public
│ └── stylesheets
│ │ └── style.css
│ ├── routes
│ ├── accounts.js
│ ├── apiRoutes.js
│ └── index.js
│ └── views
│ ├── account.ejs
│ ├── create_account.ejs
│ ├── error.ejs
│ ├── index.ejs
│ └── update_account.ejs
├── Unit24
└── examples
│ └── BeautyPlus
│ ├── .gitignore
│ ├── LICENSE.md
│ ├── README.md
│ ├── bootstrap.min.css
│ ├── index.html
│ ├── main.js
│ ├── package.json
│ └── renderer.js
└── Unit25
└── examples
├── .bowerrc
├── .gitignore
└── ReactTodo
└── index.html
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 | electron-quick-start-darwin-x64
--------------------------------------------------------------------------------
/BeautyBot/app.js:
--------------------------------------------------------------------------------
1 | var config = require('config');
2 | var express = require('express');
3 | var request = require('request');
4 | var bodyParser = require('body-parser');
5 |
6 | var app = express();
7 |
8 | app.use(bodyParser.json());
9 |
10 | const PAGE_ACCESS_TOKEN = config.get('devConfig.pageAccessToken');
11 | const VERIFY_TOKEN = config.get('devConfig.verifyToken');
12 |
13 | app.get('/webhook', function(req, res) {
14 | if (req.query['hub.mode'] === 'subscribe' &&
15 | req.query['hub.verify_token'] === VERIFY_TOKEN) {
16 | console.log("Validating webhook");
17 | res.status(200).send(req.query['hub.challenge']);
18 | } else {
19 | console.error("Failed validation. Make sure the validation tokens match.");
20 | res.sendStatus(403);
21 | }
22 | });
23 |
24 | app.post('/webhook', function (req, res) {
25 | var data = req.body;
26 |
27 | // Make sure this is a page subscription
28 | if (data.object === 'page') {
29 |
30 | // Iterate over each entry - there may be multiple if batched
31 | data.entry.forEach(function(entry) {
32 | var pageID = entry.id;
33 | var timeOfEvent = entry.time;
34 |
35 | // Iterate over each messaging event
36 | entry.messaging.forEach(function(event) {
37 | if (event.message) {
38 | receivedMessage(event);
39 | } else {
40 | console.log("Webhook received unknown event: ", event);
41 | }
42 | });
43 | });
44 |
45 | // Assume all went well.
46 | //
47 | // You must send back a 200, within 20 seconds, to let us know
48 | // you've successfully received the callback. Otherwise, the request
49 | // will time out and we will keep trying to resend.
50 | res.sendStatus(200);
51 | }
52 | });
53 |
54 | function receivedMessage(event) {
55 | var senderID = event.sender.id;
56 | var recipientID = event.recipient.id;
57 | var timeOfMessage = event.timestamp;
58 | var message = event.message;
59 |
60 | console.log("Received message for user %d and page %d at %d with message:",
61 | senderID, recipientID, timeOfMessage);
62 | console.log(JSON.stringify(message));
63 |
64 | var messageId = message.mid;
65 |
66 | var messageText = message.text;
67 | var messageAttachments = message.attachments;
68 |
69 | if (messageText) {
70 |
71 | // If we receive a text message, check to see if it matches a keyword
72 | // and send back the example. Otherwise, just echo the text we received.
73 | switch (messageText) {
74 | case 'generic':
75 | sendGenericMessage(senderID);
76 | break;
77 |
78 | case '給我美圖':
79 | sendImageMessage(senderID);
80 | sendTextMessage(senderID, '美圖來了!請稍後!');
81 | break;
82 |
83 | default:
84 | sendTextMessage(senderID, messageText);
85 | }
86 | } else if (messageAttachments) {
87 | sendTextMessage(senderID, "Message with attachment received");
88 | }
89 | }
90 |
91 | function sendImageMessage(recipientId) {
92 | request({
93 | 'method': 'GET',
94 | 'uri': 'http://gank.io/api/data/%E7%A6%8F%E5%88%A9/100/1'
95 | }, function(error, response, body) {
96 | var data = JSON.parse(body);
97 | var index = Math.floor(Math.random() * data.results.length);
98 | var url = data.results[index].url;
99 | console.log('data', data);
100 | console.log('index', index);
101 | var messageData = {
102 | recipient: {
103 | id: recipientId
104 | },
105 | message: {
106 | attachment: {
107 | type: 'image',
108 | payload: {
109 | url: url
110 | }
111 | }
112 | }
113 | };
114 |
115 | callSendAPI(messageData);
116 |
117 | });
118 | }
119 |
120 | function sendTextMessage(recipientId, messageText) {
121 | var messageData = {
122 | recipient: {
123 | id: recipientId
124 | },
125 | message: {
126 | text: messageText
127 | }
128 | };
129 |
130 | callSendAPI(messageData);
131 | }
132 |
133 | function callSendAPI(messageData) {
134 | request({
135 | uri: 'https://graph.facebook.com/v2.6/me/messages',
136 | qs: { access_token: PAGE_ACCESS_TOKEN },
137 | method: 'POST',
138 | json: messageData
139 |
140 | }, function (error, response, body) {
141 | if (!error && response.statusCode == 200) {
142 | var recipientId = body.recipient_id;
143 | var messageId = body.message_id;
144 |
145 | console.log("Successfully sent generic message with id %s to recipient %s",
146 | messageId, recipientId);
147 | } else {
148 | console.error("Unable to send message.");
149 | console.error(response);
150 | console.error(error);
151 | }
152 | });
153 | }
154 |
155 | function sendGenericMessage(recipientId) {
156 | var messageData = {
157 | recipient: {
158 | id: recipientId
159 | },
160 | message: {
161 | attachment: {
162 | type: "template",
163 | payload: {
164 | template_type: "generic",
165 | elements: [{
166 | title: "rift",
167 | subtitle: "Next-generation virtual reality",
168 | item_url: "https://www.oculus.com/en-us/rift/",
169 | image_url: "http://messengerdemo.parseapp.com/img/rift.png",
170 | buttons: [{
171 | type: "web_url",
172 | url: "https://www.oculus.com/en-us/rift/",
173 | title: "Open Web URL"
174 | }, {
175 | type: "postback",
176 | title: "Call Postback",
177 | payload: "Payload for first bubble",
178 | }],
179 | }, {
180 | title: "touch",
181 | subtitle: "Your Hands, Now in VR",
182 | item_url: "https://www.oculus.com/en-us/touch/",
183 | image_url: "http://messengerdemo.parseapp.com/img/touch.png",
184 | buttons: [{
185 | type: "web_url",
186 | url: "https://www.oculus.com/en-us/touch/",
187 | title: "Open Web URL"
188 | }, {
189 | type: "postback",
190 | title: "Call Postback",
191 | payload: "Payload for second bubble",
192 | }]
193 | }]
194 | }
195 | }
196 | }
197 | };
198 |
199 | callSendAPI(messageData);
200 | }
201 |
202 | app.listen(4000, function() {
203 | console.log('listening 4000!!');
204 | });
--------------------------------------------------------------------------------
/BeautyBot/config/default.json:
--------------------------------------------------------------------------------
1 | {
2 | "devConfig": {
3 | "pageAccessToken": "",
4 | "verifyToken": ""
5 | }
6 | }
--------------------------------------------------------------------------------
/BeautyBot/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "beauty-bot",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "app.js",
6 | "scripts": {
7 | "start": "node app.js"
8 | },
9 | "author": "kdchang",
10 | "license": "MIT",
11 | "dependencies": {
12 | "body-parser": "^1.17.1",
13 | "config": "^1.25.1",
14 | "express": "^4.15.2",
15 | "request": "^2.81.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/BeautyTab.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/BeautyTab.zip
--------------------------------------------------------------------------------
/BeautyTab/_locales/en/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "l10nTabName": {
3 | "message":"Localization"
4 | ,"description":"name of the localization tab"
5 | }
6 | ,"l10nHeader": {
7 | "message":"It does localization too! (this whole tab is, actually)"
8 | ,"description":"Header text for the localization section"
9 | }
10 | ,"l10nIntro": {
11 | "message":"'L10n' refers to 'Localization' - 'L' an 'n' are obvious, and 10 comes from the number of letters between those two. It is the process/whatever of displaying something in the language of choice. It uses 'I18n', 'Internationalization', which refers to the tools / framework supporting L10n. I.e., something is internationalized if it has I18n support, and can be localized. Something is localized for you if it is in your language / dialect."
12 | ,"description":"introduce the basic idea."
13 | }
14 | ,"l10nProd": {
15 | "message":"You are planning to allow localization, right? You have no idea who will be using your extension! You have no idea who will be translating it! At least support the basics, it's not hard, and having the framework in place will let you transition much more easily later on."
16 | ,"description":"drive the point home. It's good for you."
17 | }
18 | ,"l10nFirstParagraph": {
19 | "message":"When the options page loads, elements decorated with data-l10n will automatically be localized!"
20 | ,"description":"inform that elements will be localized on load"
21 | }
22 | ,"l10nSecondParagraph": {
23 | "message":"If you need more complex localization, you can also define data-l10n-args . This should contain $containerType$ filled with $dataType$ , which will be passed into Chrome's i18n API as $functionArgs$ . In fact, this paragraph does just that, and wraps the args in mono-space font. Easy!"
24 | ,"description":"introduce the data-l10n-args attribute. End on a lame note."
25 | ,"placeholders": {
26 | "containerType": {
27 | "content":"$1"
28 | ,"example":"'array', 'list', or something similar"
29 | ,"description":"type of the args container"
30 | }
31 | ,"dataType": {
32 | "content":"$2"
33 | ,"example":"string"
34 | ,"description":"type of data in each array index"
35 | }
36 | ,"functionArgs": {
37 | "content":"$3"
38 | ,"example":"arguments"
39 | ,"description":"whatever you call what you pass into a function/method. args, params, etc."
40 | }
41 | }
42 | }
43 | ,"l10nThirdParagraph": {
44 | "message":"Message contents are passed right into innerHTML without processing - include any tags (or even scripts) that you feel like. If you have an input field, the placeholder will be set instead, and buttons will have the value attribute set."
45 | ,"description":"inform that we handle placeholders, buttons, and direct HTML input"
46 | }
47 | ,"l10nButtonsBefore": {
48 | "message":"Different types of buttons are handled as well. <button> elements have their html set:"
49 | }
50 | ,"l10nButton": {
51 | "message":"in a button "
52 | }
53 | ,"l10nButtonsBetween": {
54 | "message":"while <input type='submit'> and <input type='button'> get their 'value' set (note: no HTML):"
55 | }
56 | ,"l10nSubmit": {
57 | "message":"a submit value"
58 | }
59 | ,"l10nButtonsAfter": {
60 | "message":"Awesome, no?"
61 | }
62 | ,"l10nExtras": {
63 | "message":"You can even set data-l10n on things like the <title> tag, which lets you have translatable page titles, or fieldset <legend> tags, or anywhere else - the default Boil.localize() behavior will check every tag in the document, not just the body."
64 | ,"description":"inform about places which may not be obvious, like
, etc"
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/BeautyTab/icons/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/BeautyTab/icons/icon128.png
--------------------------------------------------------------------------------
/BeautyTab/icons/icon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/BeautyTab/icons/icon16.png
--------------------------------------------------------------------------------
/BeautyTab/icons/icon19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/BeautyTab/icons/icon19.png
--------------------------------------------------------------------------------
/BeautyTab/icons/icon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/BeautyTab/icons/icon48.png
--------------------------------------------------------------------------------
/BeautyTab/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "BeautyTab",
3 | "version": "0.0.1",
4 | "manifest_version": 2,
5 | "description": "This extension was created with the awesome extensionizr.com",
6 | "homepage_url": "http://extensionizr.com",
7 | "icons": {
8 | "16": "icons/icon16.png",
9 | "48": "icons/icon48.png",
10 | "128": "icons/icon128.png"
11 | },
12 | "default_locale": "en",
13 | "background": {
14 | "page": "src/bg/background.html",
15 | "persistent": false
16 | },
17 | "options_page": "src/options/index.html",
18 | "browser_action": {
19 | "default_icon": "icons/icon19.png",
20 | "default_title": "browser action demo",
21 | "default_popup": "src/browser_action/browser_action.html"
22 | },
23 | "chrome_url_overrides": {
24 | "newtab": "src/override/override.html"
25 | }
26 | }
--------------------------------------------------------------------------------
/BeautyTab/src/bg/background.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/BeautyTab/src/bg/background.js:
--------------------------------------------------------------------------------
1 | // if you checked "fancy-settings" in extensionizr.com, uncomment this lines
2 |
3 | // var settings = new Store("settings", {
4 | // "sample_setting": "This is how you use Store.js to remember values"
5 | // });
6 |
7 |
8 | //example of using a message handler from the inject scripts
9 | chrome.extension.onMessage.addListener(
10 | function(request, sender, sendResponse) {
11 | chrome.pageAction.show(sender.tab.id);
12 | sendResponse();
13 | });
--------------------------------------------------------------------------------
/BeautyTab/src/browser_action/browser_action.html:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
Hello extensionizr!
16 |
To shut this popup down, edit the manifest file and remove the "default popup" key. To edit it, just edit ext/browser_action/browser_action.html. The CSS is there, too.
17 |
--------------------------------------------------------------------------------
/BeautyTab/src/options/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/BeautyTab/src/override/main.js:
--------------------------------------------------------------------------------
1 | function showImages(data, index) {
2 | var result = document.getElementById('result');
3 | var image = document.createElement('img');
4 | image.src = data.results[index].url;
5 | image.className = 'thumbnail';
6 | result.appendChild(image);
7 | }
8 |
9 | function initLoad() {
10 | var xhr = new XMLHttpRequest();
11 | xhr.open('GET', 'http://gank.io/api/data/%E7%A6%8F%E5%88%A9/100/1');
12 | xhr.onreadystatechange = function() {
13 | if(xhr.readyState === 4) {
14 | var data = JSON.parse(xhr.responseText);
15 | var index = Math.floor(Math.random() * data.results.length);
16 | console.log(data);
17 | showImages(data, index);
18 | }
19 | };
20 | xhr.send();
21 | }
22 |
23 | initLoad();
--------------------------------------------------------------------------------
/BeautyTab/src/override/override.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BeautyTab
6 |
7 |
8 |
9 |
10 |
BeautyTab 表特分頁
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/CountdownTimer/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CountdownTimer
5 |
6 |
7 | CountdownTimer
8 |
9 |
29 |
30 |
--------------------------------------------------------------------------------
/CurrencyExchange/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 我家銀行換匯服務
5 |
6 |
7 | 我家銀行換匯服務
8 |
9 |
10 | 台幣換美元
11 | 美元換台幣
12 |
13 |
14 | 換算
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/CurrencyExchange/main.js:
--------------------------------------------------------------------------------
1 | var optionSelect = document.getElementById('option-select');
2 |
3 |
4 | var submitBtn = document.getElementById('submit-btn');
5 |
6 | submitBtn.addEventListener('click', function() {
7 | var option = optionSelect.value;
8 | var currency = document.getElementById('currency').value;
9 | var result = document.getElementById('result');
10 |
11 | if(currency === NaN || currency === '') {
12 | result.innerHTML = '請輸入正確數字!';
13 | } else if (option === 'nt2us') {
14 | var outcome = parseFloat(currency) / 30;
15 | result.innerHTML = 'US ' + outcome.toFixed(2);
16 | } else if(option === 'us2nt') {
17 | var outcome = parseFloat(currency) * 30;
18 | result.innerHTML = 'TW ' + outcome.toFixed(2);
19 | }
20 |
21 | });
--------------------------------------------------------------------------------
/MosquitoFight/images/mosquito.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/MosquitoFight/images/mosquito.png
--------------------------------------------------------------------------------
/MosquitoFight/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MosquitoFight
5 |
6 |
7 |
8 |
9 | Score: 0
10 | Time:
11 |
12 |
66 |
67 |
--------------------------------------------------------------------------------
/MosquitoFight/main.css:
--------------------------------------------------------------------------------
1 | #mosquito {
2 | width: 180px;
3 | }
--------------------------------------------------------------------------------
/OpenData/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | OpenData
5 |
6 |
7 |
8 |
9 |
10 |
30 |
31 |
--------------------------------------------------------------------------------
/OpenData/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/OpenData/loading.gif
--------------------------------------------------------------------------------
/PTTCrawler/app.js:
--------------------------------------------------------------------------------
1 | var request = require('request');
2 | var cheerio = require('cheerio');
3 | var fs = require('fs');
4 |
5 | request({
6 | uri: 'https://www.ptt.cc/bbs/Soft_Job/index.html',
7 | method: 'GET'
8 | }, function(error, response, body) {
9 | if(error) {
10 | return;
11 | }
12 | var $ = cheerio.load(body);
13 |
14 | var results = [];
15 | var titles = $('.r-ent a');
16 | // console.log(title);
17 | for(var i = 0; i < titles.length; i++) {
18 | results.push({ title: $(titles[i]).text(), link: $(titles[i]).attr('href')});
19 | }
20 | console.log(results);
21 | fs.writeFileSync('results.json', JSON.stringify(results));
22 | });
23 |
24 |
--------------------------------------------------------------------------------
/PTTCrawler/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ptt-crawler",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "app.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "kdchang",
10 | "license": "MIT",
11 | "dependencies": {
12 | "cheerio": "^0.22.0",
13 | "request": "^2.81.0"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/PTTCrawler/results.json:
--------------------------------------------------------------------------------
1 | [{"title":"Re: [請益] 純軟外派職缺","link":"/bbs/Soft_Job/M.1492745595.A.5A1.html"},{"title":"Re: [請益] 關於TutorABC的研發部門","link":"/bbs/Soft_Job/M.1492746928.A.B04.html"},{"title":"[請益] 一卡通面試請益","link":"/bbs/Soft_Job/M.1492749853.A.4A3.html"},{"title":"Fw: [北美] 美國軟體工程師生活分享","link":"/bbs/Soft_Job/M.1492751613.A.026.html"},{"title":"Re: [請益] 對面試感到恐懼","link":"/bbs/Soft_Job/M.1492761540.A.021.html"},{"title":"Re: [請益] 對面試感到恐懼","link":"/bbs/Soft_Job/M.1492763015.A.461.html"},{"title":"Re: [請益] 對面試感到恐懼","link":"/bbs/Soft_Job/M.1492766330.A.3F8.html"},{"title":"Re: [請益] 對面試感到恐懼","link":"/bbs/Soft_Job/M.1492778716.A.656.html"},{"title":"Fw: [聘書] offer抉擇","link":"/bbs/Soft_Job/M.1492782020.A.189.html"},{"title":"[討論] 關於負載平衡","link":"/bbs/Soft_Job/M.1492784147.A.19A.html"},{"title":"[請益] offer請益","link":"/bbs/Soft_Job/M.1492789791.A.524.html"},{"title":"[請益] offer選擇 現職/台塑/台銀","link":"/bbs/Soft_Job/M.1492823790.A.1EC.html"},{"title":"[公告] 2017年4月10日 面試心得文需附上時間點","link":"/bbs/Soft_Job/M.1451578149.A.2F4.html"},{"title":"[公告] 徵才不符板規或徵才自刪公司","link":"/bbs/Soft_Job/M.1453196050.A.D41.html"},{"title":"[情報] 訓練課程與付費APP與網站分享","link":"/bbs/Soft_Job/M.1459783651.A.DBE.html"},{"title":"[情報] 社群活動與免費APP與網站分享","link":"/bbs/Soft_Job/M.1459784168.A.0C8.html"}]
--------------------------------------------------------------------------------
/QA/mosquito.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Document
9 |
10 |
11 |
12 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 從零開始學 JavaScript(JavaScript 程式設計新手村 Lite)
2 | 由淺入深系統性學習原生 JavaScript 和程式設計的重要觀念, 讓你不只會用 jQuery 還了解它背後使用的原理,並為未來離開新手村出發挑戰前端進階學習打好堅實基礎知識,培養自學各種前端框架和工具的能力。
3 |
4 | # 課程大綱(Syllabus)
5 | 1. 單元1 JavaScript 程式設計初體驗(Pokemon Fight 精靈快打)
6 |
7 | 2. 單元2 JavaScript 開發環境建置、Github 與瀏覽器 DevTool 教學
8 |
9 | 3. 單元3 JavaScript 快速基礎入門(變數、流程控制、函式、物件)
10 |
11 | 4. 單元4 實戰範例:匯率計算應用程式(JavaScript 函數 Function 基礎)
12 |
13 | 5. 單元5 實戰範例:TodoList 代辦事項應用程式(JavaScript 函數 Function 基礎)
14 |
15 | 6. 單元6 實戰範例:倒數計時(BOM & DOM 操作基礎與事件處理 Event Handle、SetInterval)
16 |
17 | 7. 單元7 實戰範例:蟲蟲大戰:打蚊子遊戲(BOM & DOM 操作基礎與事件處理 Event Handle)
18 |
19 | 8. 單元8 實戰範例:幻燈片相簿(BOM & DOM 操作基礎與事件處理 Event Handle)
20 |
21 | 9. 單元9 實戰範例:政府開放資料 API 範例(流程控制、Ajax / JSON 基礎介紹)
22 |
23 | 10. 單元10 實戰範例:jQuery 入門範例(套件使用)
24 |
25 | 11. 單元11 實戰範例:部屬 JavaScript 應用程式到 Github Page
26 |
27 | 12. 單元12 實戰範例:Chrome Extensions 基礎(表特分頁,Ajax,Cookie,LocalStorage/SessionStorage 本地端資料儲存)
28 |
29 | 13. 單元13 實戰範例:上架自己的 Chrome Extensions
30 |
31 | 14. 單元14 實戰範例:NodeJS Web 基礎(Sequelize)
32 |
33 | 15. 單元15 實戰範例:NodeJS Web 基礎前後端分離(TodoList)
34 |
35 | 16. 單元16 實戰範例:NodeJS 與 Socket.io 基礎(雲端聊天室)
36 |
37 | 17. 單元17 實戰範例:NodeJS Web 基礎(Chatbot)
38 |
39 | 18. 單元18 實戰範例:部屬應用程式到 Heroku 雲端伺服器
40 |
41 | 19. 募資金額 100% 解鎖:前端開發面試常見問題研討
42 |
43 | 20. 募資金額 200% 解鎖:Google Map API / Facebook API 新手入門
44 |
45 | 21. 募資金額 400% 解鎖:NodeJS 網路爬蟲入門實戰
46 |
47 | 22. 募資金額 600% 解鎖:NodeJS / Express / MongoDB 新手入門 JavaScript 後端開發
48 |
49 | 23. 募資金額 800% 解鎖:Electron 桌面應用程式開發入門(beauty+)
50 |
51 | 24. 募資金額 1000% 解鎖:JavaScript ReactJS 應用程式開發入門初體驗
--------------------------------------------------------------------------------
/ReactTodo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ReactTodo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/SimepleJS/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SimpleJS
6 |
10 |
11 |
12 | Hello World!!!
13 |
14 |
--------------------------------------------------------------------------------
/SimplejQuery/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/SimplejQuery/1.jpg
--------------------------------------------------------------------------------
/SimplejQuery/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/SimplejQuery/2.jpg
--------------------------------------------------------------------------------
/SimplejQuery/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/SimplejQuery/3.jpg
--------------------------------------------------------------------------------
/SimplejQuery/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | SimplejQuery
5 |
6 |
7 |
8 |
9 |
10 | SimplejQuery
11 | List
12 | 1
13 | 2
14 | 3
15 |
16 |
21 |
22 |
32 |
33 |
--------------------------------------------------------------------------------
/SimplejQuery/jquery.bxslider/LICENSE.md:
--------------------------------------------------------------------------------
1 | License
2 | -------
3 |
4 | The MIT License (MIT)
5 |
6 | Copyright © 2014 [Steven Wanderski](https://twitter.com/stevenwanderski)
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/SimplejQuery/jquery.bxslider/images/bx_loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/SimplejQuery/jquery.bxslider/images/bx_loader.gif
--------------------------------------------------------------------------------
/SimplejQuery/jquery.bxslider/images/controls.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/SimplejQuery/jquery.bxslider/images/controls.png
--------------------------------------------------------------------------------
/SimplejQuery/jquery.bxslider/jquery.bxslider.css:
--------------------------------------------------------------------------------
1 | /** VARIABLES
2 | ===================================*/
3 | /** RESET AND LAYOUT
4 | ===================================*/
5 | .bx-wrapper {
6 | position: relative;
7 | margin-bottom: 60px;
8 | padding: 0;
9 | *zoom: 1;
10 | -ms-touch-action: pan-y;
11 | touch-action: pan-y;
12 | }
13 | .bx-wrapper img {
14 | max-width: 100%;
15 | display: block;
16 | }
17 | .bxslider {
18 | margin: 0;
19 | padding: 0;
20 | }
21 | ul.bxslider {
22 | list-style: none;
23 | }
24 | .bx-viewport {
25 | /*fix other elements on the page moving (on Chrome)*/
26 | -webkit-transform: translatez(0);
27 | }
28 | /** THEME
29 | ===================================*/
30 | .bx-wrapper {
31 | -moz-box-shadow: 0 0 5px #ccc;
32 | -webkit-box-shadow: 0 0 5px #ccc;
33 | box-shadow: 0 0 5px #ccc;
34 | border: 5px solid #fff;
35 | background: #fff;
36 | }
37 | .bx-wrapper .bx-pager,
38 | .bx-wrapper .bx-controls-auto {
39 | position: absolute;
40 | bottom: -30px;
41 | width: 100%;
42 | }
43 | /* LOADER */
44 | .bx-wrapper .bx-loading {
45 | min-height: 50px;
46 | background: url('images/bx_loader.gif') center center no-repeat #ffffff;
47 | height: 100%;
48 | width: 100%;
49 | position: absolute;
50 | top: 0;
51 | left: 0;
52 | z-index: 2000;
53 | }
54 | /* PAGER */
55 | .bx-wrapper .bx-pager {
56 | text-align: center;
57 | font-size: .85em;
58 | font-family: Arial;
59 | font-weight: bold;
60 | color: #666;
61 | padding-top: 20px;
62 | }
63 | .bx-wrapper .bx-pager.bx-default-pager a {
64 | background: #666;
65 | text-indent: -9999px;
66 | display: block;
67 | width: 10px;
68 | height: 10px;
69 | margin: 0 5px;
70 | outline: 0;
71 | -moz-border-radius: 5px;
72 | -webkit-border-radius: 5px;
73 | border-radius: 5px;
74 | }
75 | .bx-wrapper .bx-pager.bx-default-pager a:hover,
76 | .bx-wrapper .bx-pager.bx-default-pager a.active,
77 | .bx-wrapper .bx-pager.bx-default-pager a:focus {
78 | background: #000;
79 | }
80 | .bx-wrapper .bx-pager-item,
81 | .bx-wrapper .bx-controls-auto .bx-controls-auto-item {
82 | display: inline-block;
83 | vertical-align: bottom;
84 | *zoom: 1;
85 | *display: inline;
86 | }
87 | .bx-wrapper .bx-pager-item {
88 | font-size: 0;
89 | line-height: 0;
90 | }
91 | /* DIRECTION CONTROLS (NEXT / PREV) */
92 | .bx-wrapper .bx-prev {
93 | left: 10px;
94 | background: url('images/controls.png') no-repeat 0 -32px;
95 | }
96 | .bx-wrapper .bx-prev:hover,
97 | .bx-wrapper .bx-prev:focus {
98 | background-position: 0 0;
99 | }
100 | .bx-wrapper .bx-next {
101 | right: 10px;
102 | background: url('images/controls.png') no-repeat -43px -32px;
103 | }
104 | .bx-wrapper .bx-next:hover,
105 | .bx-wrapper .bx-next:focus {
106 | background-position: -43px 0;
107 | }
108 | .bx-wrapper .bx-controls-direction a {
109 | position: absolute;
110 | top: 50%;
111 | margin-top: -16px;
112 | outline: 0;
113 | width: 32px;
114 | height: 32px;
115 | text-indent: -9999px;
116 | z-index: 9999;
117 | }
118 | .bx-wrapper .bx-controls-direction a.disabled {
119 | display: none;
120 | }
121 | /* AUTO CONTROLS (START / STOP) */
122 | .bx-wrapper .bx-controls-auto {
123 | text-align: center;
124 | }
125 | .bx-wrapper .bx-controls-auto .bx-start {
126 | display: block;
127 | text-indent: -9999px;
128 | width: 10px;
129 | height: 11px;
130 | outline: 0;
131 | background: url('images/controls.png') -86px -11px no-repeat;
132 | margin: 0 3px;
133 | }
134 | .bx-wrapper .bx-controls-auto .bx-start:hover,
135 | .bx-wrapper .bx-controls-auto .bx-start.active,
136 | .bx-wrapper .bx-controls-auto .bx-start:focus {
137 | background-position: -86px 0;
138 | }
139 | .bx-wrapper .bx-controls-auto .bx-stop {
140 | display: block;
141 | text-indent: -9999px;
142 | width: 9px;
143 | height: 11px;
144 | outline: 0;
145 | background: url('images/controls.png') -86px -44px no-repeat;
146 | margin: 0 3px;
147 | }
148 | .bx-wrapper .bx-controls-auto .bx-stop:hover,
149 | .bx-wrapper .bx-controls-auto .bx-stop.active,
150 | .bx-wrapper .bx-controls-auto .bx-stop:focus {
151 | background-position: -86px -33px;
152 | }
153 | /* PAGER WITH AUTO-CONTROLS HYBRID LAYOUT */
154 | .bx-wrapper .bx-controls.bx-has-controls-auto.bx-has-pager .bx-pager {
155 | text-align: left;
156 | width: 80%;
157 | }
158 | .bx-wrapper .bx-controls.bx-has-controls-auto.bx-has-pager .bx-controls-auto {
159 | right: 0;
160 | width: 35px;
161 | }
162 | /* IMAGE CAPTIONS */
163 | .bx-wrapper .bx-caption {
164 | position: absolute;
165 | bottom: 0;
166 | left: 0;
167 | background: #666;
168 | background: rgba(80, 80, 80, 0.75);
169 | width: 100%;
170 | }
171 | .bx-wrapper .bx-caption span {
172 | color: #fff;
173 | font-family: Arial;
174 | display: block;
175 | font-size: .85em;
176 | padding: 10px;
177 | }
178 |
--------------------------------------------------------------------------------
/SimplejQuery/jquery.bxslider/jquery.bxslider.min.css:
--------------------------------------------------------------------------------
1 | .bx-wrapper{position:relative;margin-bottom:60px;padding:0;-ms-touch-action:pan-y;touch-action:pan-y;-moz-box-shadow:0 0 5px #ccc;-webkit-box-shadow:0 0 5px #ccc;box-shadow:0 0 5px #ccc;border:5px solid #fff;background:#fff}.bx-wrapper img{max-width:100%;display:block}.bxslider{margin:0;padding:0}ul.bxslider{list-style:none}.bx-viewport{-webkit-transform:translatez(0)}.bx-wrapper .bx-controls-auto,.bx-wrapper .bx-pager{position:absolute;bottom:-30px;width:100%}.bx-wrapper .bx-loading{min-height:50px;background:url(images/bx_loader.gif) center center no-repeat #fff;height:100%;width:100%;position:absolute;top:0;left:0;z-index:2000}.bx-wrapper .bx-pager{text-align:center;font-size:.85em;font-family:Arial;font-weight:700;color:#666;padding-top:20px}.bx-wrapper .bx-pager.bx-default-pager a{background:#666;text-indent:-9999px;display:block;width:10px;height:10px;margin:0 5px;outline:0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.bx-wrapper .bx-pager.bx-default-pager a.active,.bx-wrapper .bx-pager.bx-default-pager a:focus,.bx-wrapper .bx-pager.bx-default-pager a:hover{background:#000}.bx-wrapper .bx-controls-auto .bx-controls-auto-item,.bx-wrapper .bx-pager-item{display:inline-block;vertical-align:bottom}.bx-wrapper .bx-pager-item{font-size:0;line-height:0}.bx-wrapper .bx-prev{left:10px;background:url(images/controls.png) 0 -32px no-repeat}.bx-wrapper .bx-prev:focus,.bx-wrapper .bx-prev:hover{background-position:0 0}.bx-wrapper .bx-next{right:10px;background:url(images/controls.png) -43px -32px no-repeat}.bx-wrapper .bx-next:focus,.bx-wrapper .bx-next:hover{background-position:-43px 0}.bx-wrapper .bx-controls-direction a{position:absolute;top:50%;margin-top:-16px;outline:0;width:32px;height:32px;text-indent:-9999px;z-index:9999}.bx-wrapper .bx-controls-direction a.disabled{display:none}.bx-wrapper .bx-controls-auto{text-align:center}.bx-wrapper .bx-controls-auto .bx-start{display:block;text-indent:-9999px;width:10px;height:11px;outline:0;background:url(images/controls.png) -86px -11px no-repeat;margin:0 3px}.bx-wrapper .bx-controls-auto .bx-start.active,.bx-wrapper .bx-controls-auto .bx-start:focus,.bx-wrapper .bx-controls-auto .bx-start:hover{background-position:-86px 0}.bx-wrapper .bx-controls-auto .bx-stop{display:block;text-indent:-9999px;width:9px;height:11px;outline:0;background:url(images/controls.png) -86px -44px no-repeat;margin:0 3px}.bx-wrapper .bx-controls-auto .bx-stop.active,.bx-wrapper .bx-controls-auto .bx-stop:focus,.bx-wrapper .bx-controls-auto .bx-stop:hover{background-position:-86px -33px}.bx-wrapper .bx-controls.bx-has-controls-auto.bx-has-pager .bx-pager{text-align:left;width:80%}.bx-wrapper .bx-controls.bx-has-controls-auto.bx-has-pager .bx-controls-auto{right:0;width:35px}.bx-wrapper .bx-caption{position:absolute;bottom:0;left:0;background:#666;background:rgba(80,80,80,.75);width:100%}.bx-wrapper .bx-caption span{color:#fff;font-family:Arial;display:block;font-size:.85em;padding:10px}
--------------------------------------------------------------------------------
/SimplejQuery/jquery.bxslider/vendor/jquery.fitvids.js:
--------------------------------------------------------------------------------
1 | /*global jQuery */
2 | /*jshint multistr:true browser:true */
3 | /*!
4 | * FitVids 1.0
5 | *
6 | * Copyright 2011, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com
7 | * Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/
8 | * Released under the WTFPL license - http://sam.zoy.org/wtfpl/
9 | *
10 | * Date: Thu Sept 01 18:00:00 2011 -0500
11 | */
12 |
13 | (function( $ ){
14 |
15 | "use strict";
16 |
17 | $.fn.fitVids = function( options ) {
18 | var settings = {
19 | customSelector: null
20 | };
21 |
22 | var div = document.createElement('div'),
23 | ref = document.getElementsByTagName('base')[0] || document.getElementsByTagName('script')[0];
24 |
25 | div.className = 'fit-vids-style';
26 | div.innerHTML = '';
43 |
44 | ref.parentNode.insertBefore(div,ref);
45 |
46 | if ( options ) {
47 | $.extend( settings, options );
48 | }
49 |
50 | return this.each(function(){
51 | var selectors = [
52 | "iframe[src*='player.vimeo.com']",
53 | "iframe[src*='www.youtube.com']",
54 | "iframe[src*='www.kickstarter.com']",
55 | "object",
56 | "embed"
57 | ];
58 |
59 | if (settings.customSelector) {
60 | selectors.push(settings.customSelector);
61 | }
62 |
63 | var $allVideos = $(this).find(selectors.join(','));
64 |
65 | $allVideos.each(function(){
66 | var $this = $(this);
67 | if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; }
68 | var height = ( this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10))) ) ? parseInt($this.attr('height'), 10) : $this.height(),
69 | width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(),
70 | aspectRatio = height / width;
71 | if(!$this.attr('id')){
72 | var videoID = 'fitvid' + Math.floor(Math.random()*999999);
73 | $this.attr('id', videoID);
74 | }
75 | $this.wrap('
').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+"%");
76 | $this.removeAttr('height').removeAttr('width');
77 | });
78 | });
79 | };
80 | })( jQuery );
81 |
--------------------------------------------------------------------------------
/SlideShow/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/SlideShow/1.jpg
--------------------------------------------------------------------------------
/SlideShow/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/SlideShow/2.jpg
--------------------------------------------------------------------------------
/SlideShow/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/SlideShow/3.jpg
--------------------------------------------------------------------------------
/SlideShow/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | SlideShow
5 |
24 |
25 |
26 | SlideShow
27 |
28 |
29 |
30 |
1
31 |
32 |
33 |
34 |
35 |
36 |
2
37 |
38 |
39 |
40 |
41 |
42 |
3
43 |
44 |
45 | Prev
46 | Next
47 |
81 |
82 |
--------------------------------------------------------------------------------
/SocketChat/app.js:
--------------------------------------------------------------------------------
1 | var app = require('express')();
2 | var http = require('http').Server(app);
3 | var io = require('socket.io')(http);
4 |
5 | app.get('/', function(req, res) {
6 | res.sendFile(__dirname + '/index.html');
7 | });
8 |
9 | io.on('connection', function(socket) {
10 | socket.on('chat message', function(msg) {
11 | console.log(msg);
12 | io.emit('chat message', msg);
13 | });
14 | console.log('a user connected');
15 | });
16 |
17 | http.listen(3000, function() {
18 | console.log('listening on 3000');
19 | });
--------------------------------------------------------------------------------
/SocketChat/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SocketChat
6 |
16 |
17 |
18 |
19 |
23 |
24 |
25 |
38 |
39 |
--------------------------------------------------------------------------------
/SocketChat/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "socket-chat",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "app.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "kdchang",
10 | "license": "MIT",
11 | "dependencies": {
12 | "express": "^4.15.2",
13 | "socket.io": "^1.7.3"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/WifiMap/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | WifiMap
6 |
12 |
13 |
14 | WifiMap
15 |
16 |
53 |
56 |
57 |
--------------------------------------------------------------------------------
/lectures/README.md:
--------------------------------------------------------------------------------
1 | # 從零開始學 JavaScript(JavaScript 程式設計新手村 Lite)
2 | 由淺入深系統性學習原生 JavaScript 和程式設計的重要觀念, 讓你不只會用 jQuery 還了解它背後使用的原理,並為未來離開新手村出發挑戰前端進階學習打好堅實基礎知識,培養自學各種前端框架和工具的能力。
3 |
4 | # 課程大綱(Syllabus)
5 | 1. 單元1 JavaScript 程式設計初體驗(Pokemon Fight 精靈快打)
6 |
7 | 2. 單元2 JavaScript 開發環境建置、Github 與瀏覽器 DevTool 教學
8 |
9 | 3. 單元3 JavaScript 快速基礎入門(變數、流程控制、函式、物件)
10 |
11 | 4. 單元4 實戰範例:匯率計算應用程式(JavaScript 函數 Function 基礎)
12 |
13 | 5. 單元5 實戰範例:TodoList 代辦事項應用程式(JavaScript 函數 Function 基礎)
14 |
15 | 6. 單元6 實戰範例:倒數計時(BOM & DOM 操作基礎與事件處理 Event Handle、SetInterval)
16 |
17 | 7. 單元7 實戰範例:蟲蟲大戰:打蚊子遊戲(BOM & DOM 操作基礎與事件處理 Event Handle)
18 |
19 | 8. 單元8 實戰範例:幻燈片相簿(BOM & DOM 操作基礎與事件處理 Event Handle)
20 |
21 | 9. 單元9 實戰範例:政府開放資料 API 範例(流程控制、Ajax / JSON 基礎介紹)
22 |
23 | 10. 單元10 實戰範例:jQuery 入門範例(套件使用)
24 |
25 | 11. 單元11 實戰範例:部屬 JavaScript 應用程式到 Github Page
26 |
27 | 12. 單元12 實戰範例:Chrome Extensions 基礎(表特分頁,Ajax,Cookie,LocalStorage/SessionStorage 本地端資料儲存)
28 |
29 | 13. 單元13 實戰範例:上架自己的 Chrome Extensions
30 |
31 | 14. 單元14 實戰範例:NodeJS Web 基礎(Sequelize)
32 |
33 | 15. 單元15 實戰範例:NodeJS Web 基礎前後端分離(TodoList)
34 |
35 | 16. 單元16 實戰範例:NodeJS 與 Socket.io 基礎(雲端聊天室)
36 |
37 | 17. 單元17 實戰範例:NodeJS Web 基礎(Chatbot)
38 |
39 | 18. 單元18 實戰範例:部屬應用程式到 Heroku 雲端伺服器
40 |
41 | 19. 募資金額 100% 解鎖:前端開發面試常見問題研討
42 |
43 | 20. 募資金額 200% 解鎖:Google Map API / Facebook API 新手入門
44 |
45 | 21. 募資金額 400% 解鎖:NodeJS 網路爬蟲入門實戰
46 |
47 | 22. 募資金額 600% 解鎖:NodeJS / Express / MongoDB 新手入門 JavaScript 後端開發
48 |
49 | 23. 募資金額 800% 解鎖:Electron 桌面應用程式開發入門(beauty+)
50 |
51 | 24. 募資金額 1000% 解鎖:JavaScript ReactJS 應用程式開發入門初體驗
--------------------------------------------------------------------------------
/lectures/Unit01/examples/PokemonFight/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | 寶可夢對戰遊戲!
4 |
5 |
6 |
7 | 寶可夢對戰遊戲
8 | 開始對戰
9 |
10 |
11 |
--------------------------------------------------------------------------------
/lectures/Unit01/examples/PokemonFight/main.css:
--------------------------------------------------------------------------------
1 | #start-btn {
2 | width: 200px;
3 | height: 50px;
4 | background-color: orange;
5 | border-radius: 5%;
6 | }
--------------------------------------------------------------------------------
/lectures/Unit01/examples/PokemonFight/main.js:
--------------------------------------------------------------------------------
1 | // 程式 = 資料結構 + 演算法
2 | /*
3 | 目標:設計一個寶可夢對戰遊戲
4 |
5 | 資料結構設計:儲存遊戲狀態、玩家和電腦選擇的神奇寶貝
6 |
7 | 演算法設計:隨機產生電腦選擇的寶貝,並依玩家和電腦所派出的寶貝判斷誰勝誰負
8 |
9 | 0. 菊草葉:草系
10 | 1. 火球鼠:火系
11 | 2. 小鋸鱷:水系
12 | */
13 |
14 | var startBtn = document.querySelector('#start-btn');
15 | var choice = 0;
16 |
17 | startBtn.addEventListener('click', function() {
18 | var comChoice = Math.floor(parseFloat(Math.random() * 3));
19 | choice = parseInt(prompt('請輸入您想派出的神奇寶貝! 0. 菊草葉 1. 火球鼠 2. 小鋸鱷', 0));
20 | if(choice === 0) {
21 | alert('你派出了菊草葉!');
22 | if(comChoice === 0) {
23 | alert('對手派出菊草葉,平分秋色!');
24 | } else if (comChoice === 1) {
25 | alert('對手派出火球鼠,屬性相剋,你輸了!');
26 | } else if (comChoice === 2) {
27 | alert('對手派出小鋸鱷,耶,你贏了!');
28 | }
29 | } else if(choice === 1) {
30 | alert('你派出了火球鼠!');
31 | if(comChoice === 0) {
32 | alert('對手派出菊草葉,耶,你贏了!');
33 | } else if (comChoice === 1) {
34 | alert('對手派出火球鼠,平分秋色!');
35 | } else if (comChoice === 2) {
36 | alert('對手派出小鋸鱷,屬性相剋,你輸了!');
37 | }
38 | } else if(choice === 2) {
39 | alert('你派出了小鋸鱷!');
40 | if(comChoice === 0) {
41 | alert('對手派出菊草葉,屬性相剋,你輸了!');
42 | } else if (comChoice === 1) {
43 | alert('對手派出火球鼠,耶,你贏了!');
44 | } else if (comChoice === 2) {
45 | alert('對手派出小鋸鱷,平分秋色!');
46 | }
47 | }
48 | });
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/lectures/Unit02/examples/SimpleJS/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SimpleJS
6 |
10 |
11 |
12 | Hello World!!!
13 |
14 |
--------------------------------------------------------------------------------
/lectures/Unit03/examples/example.json:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit03/examples/example.json
--------------------------------------------------------------------------------
/lectures/Unit03/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 點我點我!
8 |
9 |
10 |
--------------------------------------------------------------------------------
/lectures/Unit03/examples/main.js:
--------------------------------------------------------------------------------
1 | /* 變數
2 |
3 | 1. 變數是一個暫時儲存資料的盒子
4 |
5 | 2. 顧名思義是一個裡面內容是可以『變』的
6 |
7 | 3. 當我們宣告一個變數時,系統會配置一塊記憶體區塊給它,而因為資料型別(數字、字串)不同,配置大小也有所不同
8 |
9 | 4. 變數名稱可以使用大小寫字母、數字和 _ 、英文大小寫字母視為不同變數,注意不要使用到 JavaScript 保留字(Ex. if, function)
10 |
11 | var name = 'Eric';
12 | name = 'Amy';
13 |
14 | var a = 1;
15 | b = a;
16 |
17 | b += 1;
18 |
19 | console.log(name);
20 |
21 |
22 | const PI = '3.1415';
23 |
24 | console.log(PI);
25 |
26 | */
27 |
28 | /*
29 | 資料型別:基本資料型態:1. number, 2. string 3. boolean 4. null 5. undefined 複合: 物件
30 | console.log(typeof name);
31 | */
32 |
33 |
34 |
35 | /* 運算式和運算子
36 | 指定資料做哪一種運算的是運算子,進行運算的資料稱為運算元
37 |
38 | 1. 賦值
39 | var result = 0;
40 |
41 | 2. 算術
42 |
43 | result = 1 + 2;
44 | console.log(result);
45 |
46 | 3. 邏輯
47 |
48 | var isTrue = true && true;
49 |
50 | 4. 關係
51 |
52 | var outcome = 1 > 2;
53 |
54 |
55 | */
56 |
57 |
58 |
59 | /*
60 |
61 | 條件判斷
62 |
63 | var grade = 70;
64 |
65 | if(grade >= 90 && grade < 100) {
66 | console.log('A');
67 | } else if(grade >= 80 && grade < 90) {
68 | console.log('B');
69 | } else {
70 | console.log('C');
71 | }
72 |
73 | */
74 |
75 |
76 |
77 | /*
78 | 迴圈
79 |
80 | for(var i = 1; i < 11; i++) {
81 | console.log(i); // 1...10
82 | }
83 |
84 | var i = 1;
85 | while(i < 11) {
86 | console.log(i);
87 | i += 1;
88 | }
89 |
90 | do {
91 | console.log(i);
92 | i += 1;
93 | } while(i < 1);
94 |
95 | */
96 |
97 |
98 | /* 函式:區域變數、全域變數
99 |
100 | function sum(a, b) {
101 | var name = 'eric';
102 | return a + b;
103 | }
104 |
105 | var sum = function(a, b) {
106 | return a + b;
107 | };
108 |
109 | sum(1, 2);
110 |
111 | console.log(name);
112 |
113 | */
114 |
115 | /* 陣列與物件:儲存資料的結構,物件則是對應到真實世界
116 |
117 |
118 | var languages = ['JavaScript', 'Python', 'Java'];
119 | languages[0]
120 | languages.push('Swift');
121 |
122 | console.log(languages);
123 |
124 | var p1 = {
125 | name: '志明'
126 | };
127 |
128 | console.log(p1.name); // "志明"
129 |
130 | var p2 = p1;
131 | p2.name = '春嬌';
132 | console.log(p2.name); // "春嬌"
133 | console.log(p1.name); // "春嬌"
134 |
135 | var annie = {
136 | name: 'annie',
137 | wow: function() {
138 | console.log('yami');
139 | }
140 | }
141 |
142 | function Cat(name) {
143 | this.name = name;
144 | this.wow = function() {
145 | console.log('yami');
146 | }
147 | }
148 |
149 | var annie = new Cat('annie');
150 |
151 | */
152 |
153 |
154 | /* 事件處理:綁定事件,回應事件
155 |
156 | btn.addEventListener('click', function() {
157 | alert('click!');
158 | });
159 | */
160 |
161 | /* 非同步處理,JSON
162 | var xhr = XMLHttpRequest();
163 | xhr.open('GET', 'http://gank.io/api/data/%E7%A6%8F%E5%88%A9/100/1');
164 | xhr.onreadystatechange = function() {
165 | var data1 = JSON.parse(xhr.responseText);
166 | console.log(xhr.responseText);
167 | console.log(data1);
168 |
169 | var data2 = JSON.stringify({ name: 'amy' });
170 | console.log(data);
171 | };
172 | xhr.send();
173 | */
174 |
175 |
176 |
--------------------------------------------------------------------------------
/lectures/Unit06/examples/CurrencyExchange/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 我家銀行換匯服務
5 |
6 |
7 | 我家銀行換匯服務
8 |
9 |
10 | 台幣換美元
11 | 美元換台幣
12 |
13 |
14 | 換算
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
--------------------------------------------------------------------------------
/lectures/Unit06/examples/CurrencyExchange/main.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit06/examples/CurrencyExchange/main.js
--------------------------------------------------------------------------------
/lectures/Unit06/examples/MosquitoFight/css/main.css:
--------------------------------------------------------------------------------
1 | #mosquito {
2 | width: 180px;
3 | }
--------------------------------------------------------------------------------
/lectures/Unit06/examples/MosquitoFight/images/mosquito.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit06/examples/MosquitoFight/images/mosquito.png
--------------------------------------------------------------------------------
/lectures/Unit06/examples/MosquitoFight/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Document
6 |
7 |
8 |
9 |
10 | Score: 0
11 | Time:
12 |
13 |
61 |
62 |
--------------------------------------------------------------------------------
/lectures/Unit07/examples/TodoJS/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Document
6 |
7 |
8 | TodoJS
9 |
13 |
14 |
37 |
38 |
--------------------------------------------------------------------------------
/lectures/Unit08/README.md:
--------------------------------------------------------------------------------
1 | [Ajax](https://developer.mozilla.org/zh-TW/docs/AJAX/Getting_Started)
--------------------------------------------------------------------------------
/lectures/Unit08/examples/CountdownTimer/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CountdownTimer
6 |
7 |
8 | CounterTimer
9 |
10 |
28 |
29 |
--------------------------------------------------------------------------------
/lectures/Unit09/README.md:
--------------------------------------------------------------------------------
1 | [bxslider](http://bxslider.com/)
2 | [innerwidth](http://stackoverflow.com/questions/17845027/what-is-difference-between-width-innerwidth-and-outerwidth-height-innerheight)
--------------------------------------------------------------------------------
/lectures/Unit09/examples/MosquitoFight/css/main.css:
--------------------------------------------------------------------------------
1 | #mosquito {
2 | width: 180px;
3 | }
--------------------------------------------------------------------------------
/lectures/Unit09/examples/MosquitoFight/images/mosquito.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit09/examples/MosquitoFight/images/mosquito.png
--------------------------------------------------------------------------------
/lectures/Unit09/examples/MosquitoFight/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Document
6 |
7 |
8 |
9 |
10 | Score: 0
11 | Time:
12 |
13 |
61 |
62 |
--------------------------------------------------------------------------------
/lectures/Unit10/examples/SlideShow/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit10/examples/SlideShow/1.jpg
--------------------------------------------------------------------------------
/lectures/Unit10/examples/SlideShow/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit10/examples/SlideShow/2.jpg
--------------------------------------------------------------------------------
/lectures/Unit10/examples/SlideShow/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit10/examples/SlideShow/3.jpg
--------------------------------------------------------------------------------
/lectures/Unit10/examples/SlideShow/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Document
6 |
23 |
24 |
25 | SlideShow
26 |
27 |
28 |
1
29 |
30 |
31 |
32 |
2
33 |
34 |
35 |
36 |
3
37 |
38 | Prev
39 | Next
40 |
67 |
68 |
--------------------------------------------------------------------------------
/lectures/Unit11/README.md:
--------------------------------------------------------------------------------
1 |
2 | 1. $ git init
3 | 2. $ git remote add origin https://github.com/happycodergit/MosquitoFight.git
4 | 3. $ git checkout --orphan gh-pages
5 | 4. $ git add .
6 | 5. $ git commit -a -m "init commit"
7 | 6. $ git push origin gh-pages
8 |
9 | [extensionizr](https://extensionizr.com/!#{"modules":["hidden-mode","with-bg","with-persistent-bg","no-options","no-override"],"boolean_perms":[],"match_ptrns":[]})
--------------------------------------------------------------------------------
/lectures/Unit11/examples/OpenData/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Document
6 |
7 |
8 |
9 |
10 |
11 |
31 |
32 |
--------------------------------------------------------------------------------
/lectures/Unit11/examples/OpenData/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit11/examples/OpenData/loading.gif
--------------------------------------------------------------------------------
/lectures/Unit12/SimpleJQuery/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit12/SimpleJQuery/1.jpg
--------------------------------------------------------------------------------
/lectures/Unit12/SimpleJQuery/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit12/SimpleJQuery/2.jpg
--------------------------------------------------------------------------------
/lectures/Unit12/SimpleJQuery/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit12/SimpleJQuery/3.jpg
--------------------------------------------------------------------------------
/lectures/Unit12/SimpleJQuery/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Document
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | SimpleJQuery
14 | List
15 | 1
16 | 2
17 | 3
18 |
19 |
24 |
25 |
34 |
35 |
--------------------------------------------------------------------------------
/lectures/Unit12/SimpleJQuery/jquery.bxslider/LICENSE.md:
--------------------------------------------------------------------------------
1 | License
2 | -------
3 |
4 | The MIT License (MIT)
5 |
6 | Copyright © 2014 [Steven Wanderski](https://twitter.com/stevenwanderski)
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/lectures/Unit12/SimpleJQuery/jquery.bxslider/images/bx_loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit12/SimpleJQuery/jquery.bxslider/images/bx_loader.gif
--------------------------------------------------------------------------------
/lectures/Unit12/SimpleJQuery/jquery.bxslider/images/controls.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit12/SimpleJQuery/jquery.bxslider/images/controls.png
--------------------------------------------------------------------------------
/lectures/Unit12/SimpleJQuery/jquery.bxslider/jquery.bxslider.css:
--------------------------------------------------------------------------------
1 | /** VARIABLES
2 | ===================================*/
3 | /** RESET AND LAYOUT
4 | ===================================*/
5 | .bx-wrapper {
6 | position: relative;
7 | margin-bottom: 60px;
8 | padding: 0;
9 | *zoom: 1;
10 | -ms-touch-action: pan-y;
11 | touch-action: pan-y;
12 | }
13 | .bx-wrapper img {
14 | max-width: 100%;
15 | display: block;
16 | }
17 | .bxslider {
18 | margin: 0;
19 | padding: 0;
20 | }
21 | ul.bxslider {
22 | list-style: none;
23 | }
24 | .bx-viewport {
25 | /*fix other elements on the page moving (on Chrome)*/
26 | -webkit-transform: translatez(0);
27 | }
28 | /** THEME
29 | ===================================*/
30 | .bx-wrapper {
31 | -moz-box-shadow: 0 0 5px #ccc;
32 | -webkit-box-shadow: 0 0 5px #ccc;
33 | box-shadow: 0 0 5px #ccc;
34 | border: 5px solid #fff;
35 | background: #fff;
36 | }
37 | .bx-wrapper .bx-pager,
38 | .bx-wrapper .bx-controls-auto {
39 | position: absolute;
40 | bottom: -30px;
41 | width: 100%;
42 | }
43 | /* LOADER */
44 | .bx-wrapper .bx-loading {
45 | min-height: 50px;
46 | background: url('images/bx_loader.gif') center center no-repeat #ffffff;
47 | height: 100%;
48 | width: 100%;
49 | position: absolute;
50 | top: 0;
51 | left: 0;
52 | z-index: 2000;
53 | }
54 | /* PAGER */
55 | .bx-wrapper .bx-pager {
56 | text-align: center;
57 | font-size: .85em;
58 | font-family: Arial;
59 | font-weight: bold;
60 | color: #666;
61 | padding-top: 20px;
62 | }
63 | .bx-wrapper .bx-pager.bx-default-pager a {
64 | background: #666;
65 | text-indent: -9999px;
66 | display: block;
67 | width: 10px;
68 | height: 10px;
69 | margin: 0 5px;
70 | outline: 0;
71 | -moz-border-radius: 5px;
72 | -webkit-border-radius: 5px;
73 | border-radius: 5px;
74 | }
75 | .bx-wrapper .bx-pager.bx-default-pager a:hover,
76 | .bx-wrapper .bx-pager.bx-default-pager a.active,
77 | .bx-wrapper .bx-pager.bx-default-pager a:focus {
78 | background: #000;
79 | }
80 | .bx-wrapper .bx-pager-item,
81 | .bx-wrapper .bx-controls-auto .bx-controls-auto-item {
82 | display: inline-block;
83 | vertical-align: bottom;
84 | *zoom: 1;
85 | *display: inline;
86 | }
87 | .bx-wrapper .bx-pager-item {
88 | font-size: 0;
89 | line-height: 0;
90 | }
91 | /* DIRECTION CONTROLS (NEXT / PREV) */
92 | .bx-wrapper .bx-prev {
93 | left: 10px;
94 | background: url('images/controls.png') no-repeat 0 -32px;
95 | }
96 | .bx-wrapper .bx-prev:hover,
97 | .bx-wrapper .bx-prev:focus {
98 | background-position: 0 0;
99 | }
100 | .bx-wrapper .bx-next {
101 | right: 10px;
102 | background: url('images/controls.png') no-repeat -43px -32px;
103 | }
104 | .bx-wrapper .bx-next:hover,
105 | .bx-wrapper .bx-next:focus {
106 | background-position: -43px 0;
107 | }
108 | .bx-wrapper .bx-controls-direction a {
109 | position: absolute;
110 | top: 50%;
111 | margin-top: -16px;
112 | outline: 0;
113 | width: 32px;
114 | height: 32px;
115 | text-indent: -9999px;
116 | z-index: 9999;
117 | }
118 | .bx-wrapper .bx-controls-direction a.disabled {
119 | display: none;
120 | }
121 | /* AUTO CONTROLS (START / STOP) */
122 | .bx-wrapper .bx-controls-auto {
123 | text-align: center;
124 | }
125 | .bx-wrapper .bx-controls-auto .bx-start {
126 | display: block;
127 | text-indent: -9999px;
128 | width: 10px;
129 | height: 11px;
130 | outline: 0;
131 | background: url('images/controls.png') -86px -11px no-repeat;
132 | margin: 0 3px;
133 | }
134 | .bx-wrapper .bx-controls-auto .bx-start:hover,
135 | .bx-wrapper .bx-controls-auto .bx-start.active,
136 | .bx-wrapper .bx-controls-auto .bx-start:focus {
137 | background-position: -86px 0;
138 | }
139 | .bx-wrapper .bx-controls-auto .bx-stop {
140 | display: block;
141 | text-indent: -9999px;
142 | width: 9px;
143 | height: 11px;
144 | outline: 0;
145 | background: url('images/controls.png') -86px -44px no-repeat;
146 | margin: 0 3px;
147 | }
148 | .bx-wrapper .bx-controls-auto .bx-stop:hover,
149 | .bx-wrapper .bx-controls-auto .bx-stop.active,
150 | .bx-wrapper .bx-controls-auto .bx-stop:focus {
151 | background-position: -86px -33px;
152 | }
153 | /* PAGER WITH AUTO-CONTROLS HYBRID LAYOUT */
154 | .bx-wrapper .bx-controls.bx-has-controls-auto.bx-has-pager .bx-pager {
155 | text-align: left;
156 | width: 80%;
157 | }
158 | .bx-wrapper .bx-controls.bx-has-controls-auto.bx-has-pager .bx-controls-auto {
159 | right: 0;
160 | width: 35px;
161 | }
162 | /* IMAGE CAPTIONS */
163 | .bx-wrapper .bx-caption {
164 | position: absolute;
165 | bottom: 0;
166 | left: 0;
167 | background: #666;
168 | background: rgba(80, 80, 80, 0.75);
169 | width: 100%;
170 | }
171 | .bx-wrapper .bx-caption span {
172 | color: #fff;
173 | font-family: Arial;
174 | display: block;
175 | font-size: .85em;
176 | padding: 10px;
177 | }
178 |
--------------------------------------------------------------------------------
/lectures/Unit12/SimpleJQuery/jquery.bxslider/jquery.bxslider.min.css:
--------------------------------------------------------------------------------
1 | .bx-wrapper{position:relative;margin-bottom:60px;padding:0;-ms-touch-action:pan-y;touch-action:pan-y;-moz-box-shadow:0 0 5px #ccc;-webkit-box-shadow:0 0 5px #ccc;box-shadow:0 0 5px #ccc;border:5px solid #fff;background:#fff}.bx-wrapper img{max-width:100%;display:block}.bxslider{margin:0;padding:0}ul.bxslider{list-style:none}.bx-viewport{-webkit-transform:translatez(0)}.bx-wrapper .bx-controls-auto,.bx-wrapper .bx-pager{position:absolute;bottom:-30px;width:100%}.bx-wrapper .bx-loading{min-height:50px;background:url(images/bx_loader.gif) center center no-repeat #fff;height:100%;width:100%;position:absolute;top:0;left:0;z-index:2000}.bx-wrapper .bx-pager{text-align:center;font-size:.85em;font-family:Arial;font-weight:700;color:#666;padding-top:20px}.bx-wrapper .bx-pager.bx-default-pager a{background:#666;text-indent:-9999px;display:block;width:10px;height:10px;margin:0 5px;outline:0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.bx-wrapper .bx-pager.bx-default-pager a.active,.bx-wrapper .bx-pager.bx-default-pager a:focus,.bx-wrapper .bx-pager.bx-default-pager a:hover{background:#000}.bx-wrapper .bx-controls-auto .bx-controls-auto-item,.bx-wrapper .bx-pager-item{display:inline-block;vertical-align:bottom}.bx-wrapper .bx-pager-item{font-size:0;line-height:0}.bx-wrapper .bx-prev{left:10px;background:url(images/controls.png) 0 -32px no-repeat}.bx-wrapper .bx-prev:focus,.bx-wrapper .bx-prev:hover{background-position:0 0}.bx-wrapper .bx-next{right:10px;background:url(images/controls.png) -43px -32px no-repeat}.bx-wrapper .bx-next:focus,.bx-wrapper .bx-next:hover{background-position:-43px 0}.bx-wrapper .bx-controls-direction a{position:absolute;top:50%;margin-top:-16px;outline:0;width:32px;height:32px;text-indent:-9999px;z-index:9999}.bx-wrapper .bx-controls-direction a.disabled{display:none}.bx-wrapper .bx-controls-auto{text-align:center}.bx-wrapper .bx-controls-auto .bx-start{display:block;text-indent:-9999px;width:10px;height:11px;outline:0;background:url(images/controls.png) -86px -11px no-repeat;margin:0 3px}.bx-wrapper .bx-controls-auto .bx-start.active,.bx-wrapper .bx-controls-auto .bx-start:focus,.bx-wrapper .bx-controls-auto .bx-start:hover{background-position:-86px 0}.bx-wrapper .bx-controls-auto .bx-stop{display:block;text-indent:-9999px;width:9px;height:11px;outline:0;background:url(images/controls.png) -86px -44px no-repeat;margin:0 3px}.bx-wrapper .bx-controls-auto .bx-stop.active,.bx-wrapper .bx-controls-auto .bx-stop:focus,.bx-wrapper .bx-controls-auto .bx-stop:hover{background-position:-86px -33px}.bx-wrapper .bx-controls.bx-has-controls-auto.bx-has-pager .bx-pager{text-align:left;width:80%}.bx-wrapper .bx-controls.bx-has-controls-auto.bx-has-pager .bx-controls-auto{right:0;width:35px}.bx-wrapper .bx-caption{position:absolute;bottom:0;left:0;background:#666;background:rgba(80,80,80,.75);width:100%}.bx-wrapper .bx-caption span{color:#fff;font-family:Arial;display:block;font-size:.85em;padding:10px}
--------------------------------------------------------------------------------
/lectures/Unit12/SimpleJQuery/jquery.bxslider/vendor/jquery.fitvids.js:
--------------------------------------------------------------------------------
1 | /*global jQuery */
2 | /*jshint multistr:true browser:true */
3 | /*!
4 | * FitVids 1.0
5 | *
6 | * Copyright 2011, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com
7 | * Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/
8 | * Released under the WTFPL license - http://sam.zoy.org/wtfpl/
9 | *
10 | * Date: Thu Sept 01 18:00:00 2011 -0500
11 | */
12 |
13 | (function( $ ){
14 |
15 | "use strict";
16 |
17 | $.fn.fitVids = function( options ) {
18 | var settings = {
19 | customSelector: null
20 | };
21 |
22 | var div = document.createElement('div'),
23 | ref = document.getElementsByTagName('base')[0] || document.getElementsByTagName('script')[0];
24 |
25 | div.className = 'fit-vids-style';
26 | div.innerHTML = '';
43 |
44 | ref.parentNode.insertBefore(div,ref);
45 |
46 | if ( options ) {
47 | $.extend( settings, options );
48 | }
49 |
50 | return this.each(function(){
51 | var selectors = [
52 | "iframe[src*='player.vimeo.com']",
53 | "iframe[src*='www.youtube.com']",
54 | "iframe[src*='www.kickstarter.com']",
55 | "object",
56 | "embed"
57 | ];
58 |
59 | if (settings.customSelector) {
60 | selectors.push(settings.customSelector);
61 | }
62 |
63 | var $allVideos = $(this).find(selectors.join(','));
64 |
65 | $allVideos.each(function(){
66 | var $this = $(this);
67 | if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; }
68 | var height = ( this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10))) ) ? parseInt($this.attr('height'), 10) : $this.height(),
69 | width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(),
70 | aspectRatio = height / width;
71 | if(!$this.attr('id')){
72 | var videoID = 'fitvid' + Math.floor(Math.random()*999999);
73 | $this.attr('id', videoID);
74 | }
75 | $this.wrap('
').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+"%");
76 | $this.removeAttr('height').removeAttr('width');
77 | });
78 | });
79 | };
80 | })( jQuery );
81 |
--------------------------------------------------------------------------------
/lectures/Unit13/examples/TodoJS/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | TodoJS
5 |
6 |
7 | TodoJS
8 |
12 |
15 |
16 |
37 |
38 |
--------------------------------------------------------------------------------
/lectures/Unit14/README.md:
--------------------------------------------------------------------------------
1 | [Express](http://expressjs.com/en/starter/installing.html)
2 | [epilogue](https://github.com/dchester/epilogue)
3 | [Node, Postgres, and Sequelize](http://mherman.org/blog/2015/10/22/node-postgres-sequelize/#.WOmiGhKGMWo)
4 | [sequelize/express-example](https://github.com/sequelize/express-example)
5 | [Usage with Express.JS](http://docs.sequelizejs.com/en/1.7.0/articles/express/)
--------------------------------------------------------------------------------
/lectures/Unit14/examples/BeautyTab/_locales/en/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "l10nTabName": {
3 | "message":"Localization"
4 | ,"description":"name of the localization tab"
5 | }
6 | ,"l10nHeader": {
7 | "message":"It does localization too! (this whole tab is, actually)"
8 | ,"description":"Header text for the localization section"
9 | }
10 | ,"l10nIntro": {
11 | "message":"'L10n' refers to 'Localization' - 'L' an 'n' are obvious, and 10 comes from the number of letters between those two. It is the process/whatever of displaying something in the language of choice. It uses 'I18n', 'Internationalization', which refers to the tools / framework supporting L10n. I.e., something is internationalized if it has I18n support, and can be localized. Something is localized for you if it is in your language / dialect."
12 | ,"description":"introduce the basic idea."
13 | }
14 | ,"l10nProd": {
15 | "message":"You are planning to allow localization, right? You have no idea who will be using your extension! You have no idea who will be translating it! At least support the basics, it's not hard, and having the framework in place will let you transition much more easily later on."
16 | ,"description":"drive the point home. It's good for you."
17 | }
18 | ,"l10nFirstParagraph": {
19 | "message":"When the options page loads, elements decorated with data-l10n will automatically be localized!"
20 | ,"description":"inform that elements will be localized on load"
21 | }
22 | ,"l10nSecondParagraph": {
23 | "message":"If you need more complex localization, you can also define data-l10n-args . This should contain $containerType$ filled with $dataType$ , which will be passed into Chrome's i18n API as $functionArgs$ . In fact, this paragraph does just that, and wraps the args in mono-space font. Easy!"
24 | ,"description":"introduce the data-l10n-args attribute. End on a lame note."
25 | ,"placeholders": {
26 | "containerType": {
27 | "content":"$1"
28 | ,"example":"'array', 'list', or something similar"
29 | ,"description":"type of the args container"
30 | }
31 | ,"dataType": {
32 | "content":"$2"
33 | ,"example":"string"
34 | ,"description":"type of data in each array index"
35 | }
36 | ,"functionArgs": {
37 | "content":"$3"
38 | ,"example":"arguments"
39 | ,"description":"whatever you call what you pass into a function/method. args, params, etc."
40 | }
41 | }
42 | }
43 | ,"l10nThirdParagraph": {
44 | "message":"Message contents are passed right into innerHTML without processing - include any tags (or even scripts) that you feel like. If you have an input field, the placeholder will be set instead, and buttons will have the value attribute set."
45 | ,"description":"inform that we handle placeholders, buttons, and direct HTML input"
46 | }
47 | ,"l10nButtonsBefore": {
48 | "message":"Different types of buttons are handled as well. <button> elements have their html set:"
49 | }
50 | ,"l10nButton": {
51 | "message":"in a button "
52 | }
53 | ,"l10nButtonsBetween": {
54 | "message":"while <input type='submit'> and <input type='button'> get their 'value' set (note: no HTML):"
55 | }
56 | ,"l10nSubmit": {
57 | "message":"a submit value"
58 | }
59 | ,"l10nButtonsAfter": {
60 | "message":"Awesome, no?"
61 | }
62 | ,"l10nExtras": {
63 | "message":"You can even set data-l10n on things like the <title> tag, which lets you have translatable page titles, or fieldset <legend> tags, or anywhere else - the default Boil.localize() behavior will check every tag in the document, not just the body."
64 | ,"description":"inform about places which may not be obvious, like , etc"
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/lectures/Unit14/examples/BeautyTab/icons/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit14/examples/BeautyTab/icons/icon128.png
--------------------------------------------------------------------------------
/lectures/Unit14/examples/BeautyTab/icons/icon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit14/examples/BeautyTab/icons/icon16.png
--------------------------------------------------------------------------------
/lectures/Unit14/examples/BeautyTab/icons/icon19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit14/examples/BeautyTab/icons/icon19.png
--------------------------------------------------------------------------------
/lectures/Unit14/examples/BeautyTab/icons/icon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit14/examples/BeautyTab/icons/icon48.png
--------------------------------------------------------------------------------
/lectures/Unit14/examples/BeautyTab/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "CHANGE THIS : Extension boilerplate",
3 | "version": "0.0.1",
4 | "manifest_version": 2,
5 | "description": "This extension was created with the awesome extensionizr.com",
6 | "homepage_url": "http://extensionizr.com",
7 | "icons": {
8 | "16": "icons/icon16.png",
9 | "48": "icons/icon48.png",
10 | "128": "icons/icon128.png"
11 | },
12 | "default_locale": "en",
13 | "background": {
14 | "page": "src/bg/background.html",
15 | "persistent": false
16 | },
17 | "options_page": "src/options/index.html",
18 | "chrome_url_overrides": {
19 | "newtab": "src/override/override.html"
20 | }
21 | }
--------------------------------------------------------------------------------
/lectures/Unit14/examples/BeautyTab/src/bg/background.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/lectures/Unit14/examples/BeautyTab/src/bg/background.js:
--------------------------------------------------------------------------------
1 | // if you checked "fancy-settings" in extensionizr.com, uncomment this lines
2 |
3 | // var settings = new Store("settings", {
4 | // "sample_setting": "This is how you use Store.js to remember values"
5 | // });
6 |
7 |
8 | //example of using a message handler from the inject scripts
9 | chrome.extension.onMessage.addListener(
10 | function(request, sender, sendResponse) {
11 | chrome.pageAction.show(sender.tab.id);
12 | sendResponse();
13 | });
--------------------------------------------------------------------------------
/lectures/Unit14/examples/BeautyTab/src/options/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 圖片來源
9 | Gank
10 |
11 |
--------------------------------------------------------------------------------
/lectures/Unit14/examples/BeautyTab/src/override/main.js:
--------------------------------------------------------------------------------
1 | var showImages = function(data, index) {
2 | var result = document.querySelector('#result');
3 | var image = document.createElement('img');
4 | image.src = data.results[index].url;
5 | image.className = 'img-thumbnail';
6 | result.appendChild(image);
7 | };
8 |
9 | var initLoad = function() {
10 | var xhr = new XMLHttpRequest();
11 | xhr.open('GET', 'http://gank.io/api/data/%E7%A6%8F%E5%88%A9/100/1');
12 | xhr.onreadystatechange = function() {
13 | if(xhr.readyState === 4) {
14 | var data = JSON.parse(xhr.responseText);
15 | var index = Math.floor(Math.random() * data.results.length);
16 | showImages(data, index);
17 | }
18 | };
19 | xhr.send();
20 | }
21 |
22 | initLoad();
--------------------------------------------------------------------------------
/lectures/Unit14/examples/BeautyTab/src/override/override.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BeautyTab 表特分頁
6 |
7 |
8 |
9 |
10 |
BeautyTab 表特分頁
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/lectures/Unit15/README.md:
--------------------------------------------------------------------------------
1 | [ChartJS](https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.4/Chart.bundle.min.js)
--------------------------------------------------------------------------------
/lectures/Unit16/README.md:
--------------------------------------------------------------------------------
1 | # NodeJS iRich
--------------------------------------------------------------------------------
/lectures/Unit16/examples/node-irich/127.0.0.1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit16/examples/node-irich/127.0.0.1
--------------------------------------------------------------------------------
/lectures/Unit16/examples/node-irich/app.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var path = require('path');
3 | var favicon = require('serve-favicon');
4 | var logger = require('morgan');
5 | var cookieParser = require('cookie-parser');
6 | var bodyParser = require('body-parser');
7 |
8 | var index = require('./routes/index');
9 | var accounts = require('./routes/accounts');
10 |
11 | var app = express();
12 |
13 | // view engine setup
14 | app.set('views', path.join(__dirname, 'views'));
15 | app.set('view engine', 'ejs');
16 |
17 | // uncomment after placing your favicon in /public
18 | //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
19 | app.use(logger('dev'));
20 | app.use(bodyParser.json());
21 | app.use(bodyParser.urlencoded({ extended: false }));
22 | app.use(cookieParser());
23 | app.use(express.static(path.join(__dirname, 'public')));
24 |
25 | app.use(index);
26 | app.use('/accounts', accounts);
27 |
28 | // catch 404 and forward to error handler
29 | app.use(function(req, res, next) {
30 | var err = new Error('Not Found');
31 | err.status = 404;
32 | next(err);
33 | });
34 |
35 | // error handler
36 | app.use(function(err, req, res, next) {
37 | // set locals, only providing error in development
38 | res.locals.message = err.message;
39 | res.locals.error = req.app.get('env') === 'development' ? err : {};
40 |
41 | // render the error page
42 | res.status(err.status || 500);
43 | res.render('error');
44 | });
45 |
46 | module.exports = app;
47 |
--------------------------------------------------------------------------------
/lectures/Unit16/examples/node-irich/bin/www:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Module dependencies.
5 | */
6 |
7 | var app = require('../app');
8 | var debug = require('debug')('node-irich:server');
9 | var http = require('http');
10 | var models = require('../models');
11 |
12 | /**
13 | * Get port from environment and store in Express.
14 | */
15 |
16 | var port = normalizePort(process.env.PORT || '3000');
17 | app.set('port', port);
18 |
19 | /**
20 | * Create HTTP server.
21 | */
22 |
23 | var server = http.createServer(app);
24 |
25 | /**
26 | * Listen on provided port, on all network interfaces.
27 | */
28 |
29 | models.sequelize.sync().then(function() {
30 | /**
31 | * Listen on provided port, on all network interfaces.
32 | */
33 | server.listen(port, function() {
34 | debug('Express server listening on port ' + server.address().port);
35 | });
36 | server.on('error', onError);
37 | server.on('listening', onListening);
38 | });
39 |
40 | /**
41 | * Normalize a port into a number, string, or false.
42 | */
43 |
44 | function normalizePort(val) {
45 | var port = parseInt(val, 10);
46 |
47 | if (isNaN(port)) {
48 | // named pipe
49 | return val;
50 | }
51 |
52 | if (port >= 0) {
53 | // port number
54 | return port;
55 | }
56 |
57 | return false;
58 | }
59 |
60 | /**
61 | * Event listener for HTTP server "error" event.
62 | */
63 |
64 | function onError(error) {
65 | if (error.syscall !== 'listen') {
66 | throw error;
67 | }
68 |
69 | var bind = typeof port === 'string'
70 | ? 'Pipe ' + port
71 | : 'Port ' + port;
72 |
73 | // handle specific listen errors with friendly messages
74 | switch (error.code) {
75 | case 'EACCES':
76 | console.error(bind + ' requires elevated privileges');
77 | process.exit(1);
78 | break;
79 | case 'EADDRINUSE':
80 | console.error(bind + ' is already in use');
81 | process.exit(1);
82 | break;
83 | default:
84 | throw error;
85 | }
86 | }
87 |
88 | /**
89 | * Event listener for HTTP server "listening" event.
90 | */
91 |
92 | function onListening() {
93 | var addr = server.address();
94 | var bind = typeof addr === 'string'
95 | ? 'pipe ' + addr
96 | : 'port ' + addr.port;
97 | debug('Listening on ' + bind);
98 | }
99 |
--------------------------------------------------------------------------------
/lectures/Unit16/examples/node-irich/config/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "development": {
3 | "username": "root",
4 | "password": null,
5 | "database": "database_development",
6 | "host": "127.0.0.1",
7 | "dialect": "sqlite"
8 | },
9 | "test": {
10 | "username": "root",
11 | "password": null,
12 | "database": "database_test",
13 | "host": "127.0.0.1",
14 | "dialect": "sqlite"
15 | },
16 | "production": {
17 | "username": "root",
18 | "password": null,
19 | "database": "database_production",
20 | "host": "127.0.0.1",
21 | "dialect": "sqlite"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lectures/Unit16/examples/node-irich/models/account.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = function(sequelize, DataTypes) {
4 | var Account = sequelize.define('Account', {
5 | title: DataTypes.STRING,
6 | type: DataTypes.STRING,
7 | cost: DataTypes.STRING
8 | });
9 |
10 | return Account;
11 | };
12 |
--------------------------------------------------------------------------------
/lectures/Unit16/examples/node-irich/models/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs');
4 | var path = require('path');
5 | var Sequelize = require('sequelize');
6 | var basename = path.basename(module.filename);
7 | var env = process.env.NODE_ENV || 'development';
8 | var config = require(__dirname + '/../config/config.json')[env];
9 | var db = {};
10 |
11 | if (config.use_env_variable) {
12 | var sequelize = new Sequelize(process.env[config.use_env_variable]);
13 | } else {
14 | var sequelize = new Sequelize(config.database, config.username, config.password, config);
15 | }
16 |
17 | fs
18 | .readdirSync(__dirname)
19 | .filter(function(file) {
20 | return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
21 | })
22 | .forEach(function(file) {
23 | var model = sequelize['import'](path.join(__dirname, file));
24 | db[model.name] = model;
25 | });
26 |
27 | Object.keys(db).forEach(function(modelName) {
28 | if (db[modelName].associate) {
29 | db[modelName].associate(db);
30 | }
31 | });
32 |
33 | db.sequelize = sequelize;
34 | db.Sequelize = Sequelize;
35 |
36 | module.exports = db;
37 |
--------------------------------------------------------------------------------
/lectures/Unit16/examples/node-irich/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-irich",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "start": "node ./bin/www"
7 | },
8 | "dependencies": {
9 | "body-parser": "~1.17.1",
10 | "cookie-parser": "~1.4.3",
11 | "debug": "~2.6.3",
12 | "ejs": "~2.5.6",
13 | "express": "~4.15.2",
14 | "morgan": "~1.8.1",
15 | "sequelize": "^3.30.4",
16 | "sequelize-cli": "^2.7.0",
17 | "serve-favicon": "~2.4.2",
18 | "sqlite3": "^3.1.8"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lectures/Unit16/examples/node-irich/public/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
3 | }
4 |
5 | a {
6 | color: #00B7FF;
7 | }
8 |
9 | .main-container {
10 | margin-top: 70px;
11 | }
--------------------------------------------------------------------------------
/lectures/Unit16/examples/node-irich/routes/accounts.js:
--------------------------------------------------------------------------------
1 | var models = require('../models');
2 | var express = require('express');
3 | var router = express.Router();
4 |
5 |
6 | router.get('/create', function(req, res) {
7 | res.render('create_account');
8 | });
9 |
10 | router.post('/create', function(req, res) {
11 | models.Account.create({
12 | title: req.body.title,
13 | type: req.body.type,
14 | cost: req.body.cost
15 | }).then(function() {
16 | res.redirect('/');
17 | });
18 | });
19 |
20 | router.get('/', function(req, res) {
21 | models.Account.findAll().then(function(accounts) {
22 | res.json(accounts);
23 | });
24 | });
25 |
26 |
27 | router.get('/:account_id', function(req, res) {
28 | models.Account.findOne({
29 | where: { id: req.params.account_id }
30 | }).then(function(account) {
31 | res.render('account', { account: account });
32 | });
33 | });
34 |
35 | router.get('/:account_id/update', function(req, res) {
36 | console.log(req.params.account_id);
37 | models.Account.findOne({
38 | where: { id: req.params.account_id }
39 | }).then(function(account) {
40 | res.render('update_account', { account: account });
41 | });
42 | });
43 |
44 | router.post('/:account_id/update', function(req, res) {
45 | models.Account.findOne({
46 | where: { id: req.params.account_id }
47 | }).then(function(account) {
48 | account.update({
49 | title: req.body.title,
50 | type: req.body.type,
51 | cost: req.body.cost
52 | });
53 | }).then(function() {
54 | res.redirect('/');
55 | });
56 | });
57 |
58 | router.post('/:account_id/delete', function(req, res) {
59 | models.Account.destroy({
60 | where: {
61 | id: req.params.account_id
62 | }
63 | }).then(function() {
64 | res.redirect('/');
65 | });
66 | });
67 |
68 | module.exports = router;
--------------------------------------------------------------------------------
/lectures/Unit16/examples/node-irich/routes/index.js:
--------------------------------------------------------------------------------
1 | var models = require('../models');
2 | var express = require('express');
3 | var router = express.Router();
4 |
5 | router.get('/', function(req, res) {
6 | models.Account.findAll().then(function(accounts) {
7 | res.render('index', {
8 | title: 'iRich 愛記帳',
9 | accounts: accounts
10 | });
11 | });
12 | });
13 |
14 | module.exports = router;
--------------------------------------------------------------------------------
/lectures/Unit16/examples/node-irich/views/account.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iRich 愛記帳
5 |
6 |
7 |
8 |
9 |
10 |
26 |
27 |
28 |
29 |
30 | Home
31 | <%= account.title %>
32 |
33 |
消費明細
34 |
<%= account.title %>
35 |
<%= account.type %>
36 |
<%= account.cost %>
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/lectures/Unit16/examples/node-irich/views/create_account.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iRich 愛記帳
5 |
6 |
7 |
8 |
9 |
10 |
26 |
27 |
28 |
29 |
新增消費
30 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/lectures/Unit16/examples/node-irich/views/error.ejs:
--------------------------------------------------------------------------------
1 | <%= message %>
2 | <%= error.status %>
3 | <%= error.stack %>
4 |
--------------------------------------------------------------------------------
/lectures/Unit16/examples/node-irich/views/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iRich 愛記帳
5 |
6 |
7 |
8 |
9 |
10 |
26 |
27 |
28 |
29 |
30 |
31 |
記錄生活中的所有花費
32 |
隨手記錄日常花費,早日達成財務自由
33 |
Learn more »
34 |
35 |
36 |
37 |
38 |
39 |
40 | 標題
41 | 分類
42 | 花費
43 | 操作
44 |
45 | <% for(var i = 0; i < accounts.length; i++) { %>
46 |
47 |
48 | <%= accounts[i].title %>
49 | <%= accounts[i].type %>
50 | <%= accounts[i].cost %>
51 | 更新
52 |
53 |
56 |
57 |
58 | <% } %>
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/lectures/Unit16/examples/node-irich/views/update_account.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iRich 愛記帳
5 |
6 |
7 |
8 |
9 |
10 |
26 |
27 |
28 |
29 |
更新消費
30 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/lectures/Unit16/node-irich/127.0.0.1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit16/node-irich/127.0.0.1
--------------------------------------------------------------------------------
/lectures/Unit16/node-irich/app.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var path = require('path');
3 | var favicon = require('serve-favicon');
4 | var logger = require('morgan');
5 | var cookieParser = require('cookie-parser');
6 | var bodyParser = require('body-parser');
7 |
8 | var index = require('./routes/index');
9 | var accounts = require('./routes/accounts');
10 |
11 | var app = express();
12 |
13 | // view engine setup
14 | app.set('views', path.join(__dirname, 'views'));
15 | app.set('view engine', 'ejs');
16 |
17 | // uncomment after placing your favicon in /public
18 | //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
19 | app.use(logger('dev'));
20 | app.use(bodyParser.json());
21 | app.use(bodyParser.urlencoded({ extended: false }));
22 | app.use(cookieParser());
23 | app.use(express.static(path.join(__dirname, 'public')));
24 |
25 | app.use(index);
26 | app.use('/accounts', accounts);
27 |
28 | // catch 404 and forward to error handler
29 | app.use(function(req, res, next) {
30 | var err = new Error('Not Found');
31 | err.status = 404;
32 | next(err);
33 | });
34 |
35 | // error handler
36 | app.use(function(err, req, res, next) {
37 | // set locals, only providing error in development
38 | res.locals.message = err.message;
39 | res.locals.error = req.app.get('env') === 'development' ? err : {};
40 |
41 | // render the error page
42 | res.status(err.status || 500);
43 | res.render('error');
44 | });
45 |
46 | module.exports = app;
47 |
--------------------------------------------------------------------------------
/lectures/Unit16/node-irich/bin/www:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Module dependencies.
5 | */
6 |
7 | var app = require('../app');
8 | var debug = require('debug')('node-irich:server');
9 | var http = require('http');
10 | var models = require('../models');
11 |
12 | /**
13 | * Get port from environment and store in Express.
14 | */
15 |
16 | var port = normalizePort(process.env.PORT || '3000');
17 | app.set('port', port);
18 |
19 | /**
20 | * Create HTTP server.
21 | */
22 |
23 | var server = http.createServer(app);
24 |
25 | /**
26 | * Listen on provided port, on all network interfaces.
27 | */
28 |
29 | models.sequelize.sync().then(function() {
30 | /**
31 | * Listen on provided port, on all network interfaces.
32 | */
33 | server.listen(port, function() {
34 | debug('Express server listening on port ' + server.address().port);
35 | });
36 | server.on('error', onError);
37 | server.on('listening', onListening);
38 | });
39 |
40 | /**
41 | * Normalize a port into a number, string, or false.
42 | */
43 |
44 | function normalizePort(val) {
45 | var port = parseInt(val, 10);
46 |
47 | if (isNaN(port)) {
48 | // named pipe
49 | return val;
50 | }
51 |
52 | if (port >= 0) {
53 | // port number
54 | return port;
55 | }
56 |
57 | return false;
58 | }
59 |
60 | /**
61 | * Event listener for HTTP server "error" event.
62 | */
63 |
64 | function onError(error) {
65 | if (error.syscall !== 'listen') {
66 | throw error;
67 | }
68 |
69 | var bind = typeof port === 'string'
70 | ? 'Pipe ' + port
71 | : 'Port ' + port;
72 |
73 | // handle specific listen errors with friendly messages
74 | switch (error.code) {
75 | case 'EACCES':
76 | console.error(bind + ' requires elevated privileges');
77 | process.exit(1);
78 | break;
79 | case 'EADDRINUSE':
80 | console.error(bind + ' is already in use');
81 | process.exit(1);
82 | break;
83 | default:
84 | throw error;
85 | }
86 | }
87 |
88 | /**
89 | * Event listener for HTTP server "listening" event.
90 | */
91 |
92 | function onListening() {
93 | var addr = server.address();
94 | var bind = typeof addr === 'string'
95 | ? 'pipe ' + addr
96 | : 'port ' + addr.port;
97 | debug('Listening on ' + bind);
98 | }
99 |
--------------------------------------------------------------------------------
/lectures/Unit16/node-irich/config/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "development": {
3 | "username": "root",
4 | "password": null,
5 | "database": "database_development",
6 | "host": "127.0.0.1",
7 | "dialect": "sqlite"
8 | },
9 | "test": {
10 | "username": "root",
11 | "password": null,
12 | "database": "database_test",
13 | "host": "127.0.0.1",
14 | "dialect": "sqlite"
15 | },
16 | "production": {
17 | "username": "root",
18 | "password": null,
19 | "database": "database_production",
20 | "host": "127.0.0.1",
21 | "dialect": "sqlite"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lectures/Unit16/node-irich/models/account.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = function(sequelize, DataTypes) {
4 | var Account = sequelize.define('Account', {
5 | title: DataTypes.STRING,
6 | type: DataTypes.STRING,
7 | cost: DataTypes.STRING
8 | });
9 |
10 | return Account;
11 | };
12 |
--------------------------------------------------------------------------------
/lectures/Unit16/node-irich/models/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs');
4 | var path = require('path');
5 | var Sequelize = require('sequelize');
6 | var basename = path.basename(module.filename);
7 | var env = process.env.NODE_ENV || 'development';
8 | var config = require(__dirname + '/../config/config.json')[env];
9 | var db = {};
10 |
11 | if (config.use_env_variable) {
12 | var sequelize = new Sequelize(process.env[config.use_env_variable]);
13 | } else {
14 | var sequelize = new Sequelize(config.database, config.username, config.password, config);
15 | }
16 |
17 | fs
18 | .readdirSync(__dirname)
19 | .filter(function(file) {
20 | return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
21 | })
22 | .forEach(function(file) {
23 | var model = sequelize['import'](path.join(__dirname, file));
24 | db[model.name] = model;
25 | });
26 |
27 | Object.keys(db).forEach(function(modelName) {
28 | if (db[modelName].associate) {
29 | db[modelName].associate(db);
30 | }
31 | });
32 |
33 | db.sequelize = sequelize;
34 | db.Sequelize = Sequelize;
35 |
36 | module.exports = db;
37 |
--------------------------------------------------------------------------------
/lectures/Unit16/node-irich/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-irich",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "start": "node ./bin/www"
7 | },
8 | "dependencies": {
9 | "body-parser": "~1.17.1",
10 | "cookie-parser": "~1.4.3",
11 | "debug": "~2.6.3",
12 | "ejs": "~2.5.6",
13 | "express": "~4.15.2",
14 | "morgan": "~1.8.1",
15 | "sequelize": "^3.30.4",
16 | "sequelize-cli": "^2.7.0",
17 | "serve-favicon": "~2.4.2",
18 | "sqlite3": "^3.1.8"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lectures/Unit16/node-irich/public/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
3 | }
4 |
5 | a {
6 | color: #00B7FF;
7 | }
8 |
9 | .main-container {
10 | margin-top: 70px;
11 | }
--------------------------------------------------------------------------------
/lectures/Unit16/node-irich/routes/accounts.js:
--------------------------------------------------------------------------------
1 | var models = require('../models');
2 | var express = require('express');
3 | var router = express.Router();
4 |
5 |
6 | router.get('/create', function(req, res) {
7 | res.render('create_account');
8 | });
9 |
10 | router.post('/create', function(req, res) {
11 | models.Account.create({
12 | title: req.body.title,
13 | type: req.body.type,
14 | cost: req.body.cost
15 | }).then(function() {
16 | res.redirect('/');
17 | });
18 | });
19 |
20 | router.get('/', function(req, res) {
21 | models.Account.findAll().then(function(accounts) {
22 | res.json(accounts);
23 | });
24 | });
25 |
26 |
27 | router.get('/:account_id', function(req, res) {
28 | models.Account.findOne({
29 | where: { id: req.params.account_id }
30 | }).then(function(account) {
31 | res.render('account', { account: account });
32 | });
33 | });
34 |
35 | router.get('/:account_id/update', function(req, res) {
36 | console.log(req.params.account_id);
37 | models.Account.findOne({
38 | where: { id: req.params.account_id }
39 | }).then(function(account) {
40 | res.render('update_account', { account: account });
41 | });
42 | });
43 |
44 | router.post('/:account_id/update', function(req, res) {
45 | models.Account.findOne({
46 | where: { id: req.params.account_id }
47 | }).then(function(account) {
48 | account.update({
49 | title: req.body.title,
50 | type: req.body.type,
51 | cost: req.body.cost
52 | });
53 | }).then(function() {
54 | res.redirect('/');
55 | });
56 | });
57 |
58 | router.post('/:account_id/delete', function(req, res) {
59 | models.Account.destroy({
60 | where: {
61 | id: req.params.account_id
62 | }
63 | }).then(function() {
64 | res.redirect('/');
65 | });
66 | });
67 |
68 | module.exports = router;
--------------------------------------------------------------------------------
/lectures/Unit16/node-irich/routes/index.js:
--------------------------------------------------------------------------------
1 | var models = require('../models');
2 | var express = require('express');
3 | var router = express.Router();
4 |
5 | router.get('/', function(req, res) {
6 | models.Account.findAll().then(function(accounts) {
7 | res.render('index', {
8 | title: 'iRich 愛記帳',
9 | accounts: accounts
10 | });
11 | });
12 | });
13 |
14 | module.exports = router;
--------------------------------------------------------------------------------
/lectures/Unit16/node-irich/views/account.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iRich 愛記帳
5 |
6 |
7 |
8 |
9 |
10 |
26 |
27 |
28 |
29 |
30 | Home
31 | <%= account.title %>
32 |
33 |
消費明細
34 |
<%= account.title %>
35 |
<%= account.type %>
36 |
<%= account.cost %>
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/lectures/Unit16/node-irich/views/create_account.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iRich 愛記帳
5 |
6 |
7 |
8 |
9 |
10 |
26 |
27 |
28 |
29 |
新增消費
30 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/lectures/Unit16/node-irich/views/error.ejs:
--------------------------------------------------------------------------------
1 | <%= message %>
2 | <%= error.status %>
3 | <%= error.stack %>
4 |
--------------------------------------------------------------------------------
/lectures/Unit16/node-irich/views/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iRich 愛記帳
5 |
6 |
7 |
8 |
9 |
10 |
26 |
27 |
28 |
29 |
30 |
31 |
記錄生活中的所有花費
32 |
隨手記錄日常花費,早日達成財務自由
33 |
Learn more »
34 |
35 |
36 |
37 |
38 |
39 |
40 | 標題
41 | 分類
42 | 花費
43 | 操作
44 |
45 | <% for(var i = 0; i < accounts.length; i++) { %>
46 |
47 |
48 | <%= accounts[i].title %>
49 | <%= accounts[i].type %>
50 | <%= accounts[i].cost %>
51 | 更新
52 |
53 |
56 |
57 |
58 | <% } %>
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/lectures/Unit16/node-irich/views/update_account.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iRich 愛記帳
5 |
6 |
7 |
8 |
9 |
10 |
26 |
27 |
28 |
29 |
更新消費
30 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/lectures/Unit17/README.md:
--------------------------------------------------------------------------------
1 | [How To Develop A Chat Bot With Node.js](https://www.smashingmagazine.com/2016/10/how-to-develop-a-chat-bot-with-node-js/)
2 | [Creating a Simple Facebook Messenger AI Bot with API.ai in Node.js](http://www.girliemac.com/blog/2017/01/06/facebook-apiai-bot-nodejs/)
3 | [fbsamples/messenger-platform-samples](https://github.com/fbsamples/messenger-platform-samples)
4 | [Messenger 平台](https://developers.facebook.com/docs/messenger-platform/)
5 | [OpenZip](http://download.post.gov.tw/post/download/Xml_10510.xml)
--------------------------------------------------------------------------------
/lectures/Unit17/examples/socket-chat/app.js:
--------------------------------------------------------------------------------
1 | var app = require('express')();
2 | var http = require('http').Server(app);
3 | var io = require('socket.io')(http);
4 |
5 | app.get('/', function(req, res){
6 | res.sendFile(__dirname + '/index.html');
7 | });
8 |
9 | io.on('connection', function(socket){
10 | console.log('a user connected');
11 | });
12 |
13 |
14 | io.on('connection', function(socket){
15 | socket.on('chat message', function(msg){
16 | io.emit('chat message', msg);
17 | });
18 | });
19 |
20 | http.listen(3000, function(){
21 | console.log('listening on *:3000');
22 | });
--------------------------------------------------------------------------------
/lectures/Unit17/examples/socket-chat/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Socket.IO chat
5 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
24 |
37 |
--------------------------------------------------------------------------------
/lectures/Unit17/examples/socket-chat/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "socket-chat",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "app.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "kdchang",
10 | "license": "MIT",
11 | "dependencies": {
12 | "express": "^4.15.2",
13 | "socket.io": "^1.7.3"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/lectures/Unit18/README.md:
--------------------------------------------------------------------------------
1 | # 單元18 實戰範例:部屬應用程式到 Heroku 雲端伺服器
2 |
3 | Install the Heroku CLI
4 |
5 | Download and install the Heroku CLI.
6 |
7 | If you haven't already, log in to your Heroku account and follow the prompts to create a new SSH public key.
8 |
9 | $ heroku login
10 | Create a new Git repository
11 |
12 | Initialize a git repository in a new or existing directory
13 |
14 | $ cd my-project/
15 | $ git init
16 | $ heroku git:remote -a irich
17 | Deploy your application
18 |
19 | Commit your code to the repository and deploy it to Heroku using Git.
20 |
21 | $ git add .
22 | $ git commit -am "make it better"
23 | $ git push heroku master
24 | Existing Git repository
25 |
26 | For existing repositories, simply add the heroku remote
27 |
28 | $ heroku git:remote -a irich
29 |
30 |
31 | [sequelizejs heroku](http://docs.sequelizejs.com/en/1.7.0/articles/heroku/)
--------------------------------------------------------------------------------
/lectures/Unit18/examples/BeautyBot/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const bodyParser = require('body-parser');
4 | const config = require('config');
5 | const express = require('express');
6 | const request = require('request');
7 |
8 | var app = express();
9 |
10 | app.use(bodyParser.json());
11 |
12 | const VERIFY_TOKEN = config.get('devConfig.verifyToken');
13 | const PAGE_ACCESS_TOKEN = config.get('devConfig.pageAccessToken');
14 |
15 | app.get('/webhook', function(req, res) {
16 | if (req.query['hub.mode'] === 'subscribe' &&
17 | req.query['hub.verify_token'] === VERIFY_TOKEN) {
18 | console.log("Validating webhook");
19 | res.status(200).send(req.query['hub.challenge']);
20 | } else {
21 | console.error("Failed validation. Make sure the validation tokens match.");
22 | res.sendStatus(403);
23 | }
24 | });
25 |
26 | app.post('/webhook', function (req, res) {
27 | var data = req.body;
28 |
29 | // Make sure this is a page subscription
30 | if (data.object === 'page') {
31 | // Iterate over each entry - there may be multiple if batched
32 | data.entry.forEach(function(entry) {
33 | var pageID = entry.id;
34 | var timeOfEvent = entry.time;
35 | // Iterate over each messaging event
36 | entry.messaging.forEach(function(event) {
37 | if (event.message) {
38 | receivedMessage(event);
39 | } else {
40 | console.log("Webhook received unknown event: ", event);
41 | }
42 | });
43 | });
44 |
45 | // Assume all went well.
46 | //
47 | // You must send back a 200, within 20 seconds, to let us know
48 | // you've successfully received the callback. Otherwise, the request
49 | // will time out and we will keep trying to resend.
50 | res.sendStatus(200);
51 | }
52 | });
53 |
54 | function receivedMessage(event) {
55 | var senderID = event.sender.id;
56 | var recipientID = event.recipient.id;
57 | var timeOfMessage = event.timestamp;
58 | var message = event.message;
59 |
60 | console.log("Received message for user %d and page %d at %d with message:",
61 | senderID, recipientID, timeOfMessage);
62 | console.log(JSON.stringify(message));
63 |
64 | var messageId = message.mid;
65 |
66 | var messageText = message.text;
67 | var messageAttachments = message.attachments;
68 |
69 | if (messageText) {
70 | // If we receive a text message, check to see if it matches a keyword
71 | // and send back the example. Otherwise, just echo the text we received.
72 | switch (messageText) {
73 | case 'hi':
74 | sendTextMessage(senderID, '您好,請說給我美圖,我就會送給您一張美美的圖喔!');
75 | break;
76 | case '您好':
77 | sendTextMessage(senderID, '您好,請說給我美圖,我就會送給您一張美美的圖喔!');
78 | break;
79 | case '給我美圖':
80 | sendImageMessage(senderID);
81 | sendTextMessage(senderID, '美圖來了!請稍後!');
82 | break;
83 | default:
84 | sendTextMessage(senderID, '你說啥?');
85 | }
86 | } else if (messageAttachments) {
87 | sendTextMessage(senderID, "Message with attachment received");
88 | }
89 | }
90 |
91 | function sendTextMessage(recipientId, messageText) {
92 | var messageData = {
93 | recipient: {
94 | id: recipientId
95 | },
96 | message: {
97 | text: messageText
98 | }
99 | };
100 |
101 | callSendAPI(messageData);
102 | }
103 |
104 | function sendImageMessage(recipientId) {
105 | request({
106 | 'method': 'GET',
107 | 'url': 'http://gank.io/api/data/%E7%A6%8F%E5%88%A9/100/1'
108 | }, function(error, response, body) {
109 | var data = JSON.parse(body);
110 | var index = Math.floor(Math.random() * data.results.length)
111 | var url = data.results[index].url;
112 | console.log(url);
113 | //sendActionMessage(senderID, 'typing_on');
114 | var messageData = {
115 | recipient: {
116 | id: recipientId
117 | },
118 | message:{
119 | attachment: {
120 | type: 'image',
121 | payload: {
122 | url: url
123 | }
124 | }
125 | }
126 | };
127 |
128 | callSendAPI(messageData);
129 | });
130 | }
131 |
132 | function callSendAPI(messageData) {
133 | request({
134 | uri: 'https://graph.facebook.com/v2.6/me/messages',
135 | qs: { access_token: PAGE_ACCESS_TOKEN },
136 | method: 'POST',
137 | json: messageData
138 |
139 | }, function (error, response, body) {
140 | if (!error && response.statusCode == 200) {
141 | var recipientId = body.recipient_id;
142 | var messageId = body.message_id;
143 | } else {
144 | console.error("Unable to send message.");
145 | console.error(response);
146 | console.error(error);
147 | }
148 | });
149 | }
150 |
151 | app.listen(3000, function () {
152 | console.log('Example app listening on port 3000!')
153 | });
--------------------------------------------------------------------------------
/lectures/Unit18/examples/BeautyBot/config/default.json:
--------------------------------------------------------------------------------
1 | {
2 | "devConfig": {
3 | "pageAccessToken": "",
4 | "verifyToken": ""
5 | }
6 | }
--------------------------------------------------------------------------------
/lectures/Unit18/examples/BeautyBot/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "zipcode-chatbot",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "app.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "kdchang",
10 | "license": "MIT",
11 | "dependencies": {
12 | "body-parser": "^1.17.1",
13 | "config": "^1.25.1",
14 | "express": "^4.15.2",
15 | "request": "^2.81.0",
16 | "xml2js": "^0.4.17"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lectures/Unit20/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # JavaScript 程式設計新手村
5 |
6 | ## 單元20 前端開發面試常見問題研討
7 |
8 | @kdchang
9 |
10 | ---
11 |
12 | # Outline
13 |
14 | 1. 面試前準備
15 | 2. 前端技術面試概論
16 | 3. 前端常見問題研討
17 |
18 | ---
19 |
20 | # 面試前準備
21 |
22 | 1. 持續經營技術部落格
23 | 2. 參與開放原始碼專案和社群
24 | 3. 淨化自己的網路資訊
25 | 4. 累積可以放在簡歷上的作品
26 | 5. 使用 JavaScript 練習 [HackerRank](https://www.hackerrank.com/)、[LeetCode](https://leetcode.com/)、[Codility](https://codility.com) 題目
27 | 6. 盡可能累積電腦科學和軟體工程相關知識
28 |
29 | ---
30 |
31 | # 前端技術面試概論
32 |
33 | 在目前業界前端工程的光譜很廣,有專注在網頁互動設計或是軟體工程的範疇,所以在準備過程要了解職缺屬性和個人職涯定位
34 |
35 | ---
36 |
37 | ## 這是某 F 公司前端徵才文
38 |
39 | ```
40 | 1. 3+ years of JavaScript experience,
41 | including concepts like asynchronous programming,
42 | closures, types, and ES6
43 |
44 | 2. Experience with React is a bonus
45 |
46 | 3. 3+ years of HTML/CSS experience,
47 | including concepts like layout, specificity,
48 | cross browser compatibility,
49 | and accessibility
50 |
51 | 4. 3+ years experience with browser APIs and optimizing
52 | front end performance BS/MS in Computer Science or
53 | a related technical field preferred
54 | ```
55 |
56 | ---
57 |
58 | ## 這是某 Y 公司前端徵才文
59 |
60 | ```
61 | 1. A degree in Computer Science or a closely related field
62 |
63 | 2. Fresh college graduate and experienced engineers are
64 | welcome
65 |
66 | 3. Solid experience and passion for building highly
67 | interactive and efficient web applications using Javascript,
68 | CSS, HTML, AJAX, JSON, and XML
69 |
70 | 4. Experience in server side technologies like PHP, NodeJS
71 |
72 | 5. Experience with JavaScript frameworks like JQuery, EmberJS,
73 | ReactJS (preferably), Angular, etc
74 |
75 | 6. Experience with CSS frameworks like Bootstrap, Pure, etc.
76 |
77 | 7. Experience with testing frameworks like Jasmine, QUnit,
78 | Mocha and test runners like Testem, Protractor, Karma.
79 | ```
80 |
81 | ---
82 |
83 | ## 這是某 P 公司前端徵才文
84 |
85 | ```
86 | 1. 熟悉JavaScript、Ajax開發。
87 | 2. 有JavaScript相關框架使用經驗、像是用過jQuery。
88 | 3. 熟悉HTML5。
89 | 4. 熟悉CSS3。
90 | 5. 有跨瀏覽器相容的實作經驗。
91 | 6. 有Responsive Design的實作經驗。(有更好)
92 | ```
93 |
94 | ---
95 |
96 | ## 一般技術面試流程
97 |
98 | 事實上,面試結果的很多環節是在事前和事後的準備決定
99 |
100 | 1. 簡歷審核(內推/校園招募/社會招募/獵人頭)
101 | 2. Phone Interview([Codebunk](https://codebunk.com/)、[Coderpad](https://coderpad.io/))或事前作業
102 | 3. Onsite Interview(Behavior/Technical)
103 | 4. HR Interview
104 |
105 | ---
106 |
107 | # 前端常見問題研討
108 |
109 | [前端工程師面試問題集](https://gist.github.com/hanksudo/5873678)
110 |
111 | 延伸閱讀:
112 | 1. [Cracking the front-end interview](https://medium.freecodecamp.com/cracking-the-front-end-interview-9a34cd46237#.38yyn7del)
113 | 2. [Front-end Job Interview Questions](https://github.com/h5bp/Front-end-Developer-Interview-Questions)
114 |
115 | ---
116 |
117 | ## 自我介紹
118 | 描述自己過去的工作經驗、專案經驗、學經歷和為什麼想加入該團隊,能提供什麼貢獻?(有些外商公司會需要英文自我介紹)
119 |
120 | ---
121 |
122 | ## HTML 基礎掌握
123 | 1. doctype 是什麼?如何使用?
124 | 2. HTML5 有哪些新的語意標籤?
125 | 3. scripts 引入位置有什麼差異?
126 | 4. 解釋 form 表單屬性使用的 http 方法中 POST / GET 的差別?
127 | 5. 有用過 HTML5 離線儲存嗎?
128 |
129 | ---
130 |
131 | ## CSS 基礎掌握
132 | 1. 如何使用純 CSS 排出兩欄式版面?
133 | 2. 知道什麼是 CSS 選擇器 / Pseudo-classes 嗎?
134 | 3. 知道 box model 的概念嗎?
135 | 4. 什麼是 [CSS Sprites](https://css-tricks.com/css-sprites/)?
136 | 5. 知道什麼是 RWD 設計嗎?
137 |
138 | ---
139 |
140 | ## JavaScript
141 |
142 | 1. JavaScript 的型別轉換?
143 | 2. 談談變數生存空間 Scope?
144 | 3. 如何使用 JavaScript 建構函數建立物件?
145 | 4. 什麼是 prototype-based 繼承?
146 | 5. apply / call 用法?
147 | 6. 什麼是事件氣泡傳遞?
148 | 7. 什麼是 Ajax?有用過 Promise 嗎?
149 | 8. DOM 的基礎操作和事件處理?
150 |
151 | 延伸閱讀:[5 Typical JavaScript Interview Exercises](https://www.sitepoint.com/5-typical-javascript-interview-exercises/)
152 |
153 | ---
154 |
155 | # 進階前端技術掌握
156 |
157 | 1. 有用過哪些前端框架或是函式庫?優點和缺點?
158 | 2. 前端效能優化有哪些作法?
159 | 3. 瀏覽器在載入頁面的過程發生什麼事?
160 | 4. 平常如何和設計師/後端工程師溝通?
161 | 5. 最近有看過什麼前端新的技術嗎?
162 |
163 | ---
164 |
165 | # 詢問面試官問題
166 |
167 | 通常面試最後會面試官會問你有什麼想要問他們的,建議事先準備幾個比較容易加分的問題詢問:
168 | 1. 事先瞭解公司的業務和新聞,展現對於公司的了解和投入
169 | 2. 針對技術問題進一步交流
170 | 3. 分享自己新學習的技術詢問對方看法
171 | 4. 虛心和面試官請教工作或是學習經驗
172 | 5. 針對欲加入團隊文化和工作流程進一步了解
173 |
174 | ---
175 |
176 | # HR 面談
177 |
178 | 1. 透過詢問過去學校或工作經驗了解人格特質
179 | 2. 分享薪資結構和公司文化
180 | 3. 詢問預期待遇
181 |
182 | ---
183 |
184 | # 總結
185 |
186 | 在這個單元中我們學會了:
187 |
188 | 1. 面試前準備
189 | 2. 前端技術面試概論
190 | 3. 前端常見問題研討
--------------------------------------------------------------------------------
/lectures/Unit21/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Wifi 熱點
5 |
9 |
10 |
11 |
12 |
48 |
51 |
52 |
--------------------------------------------------------------------------------
/lectures/Unit22/examples/app.js:
--------------------------------------------------------------------------------
1 | const request = require('request');
2 | const cheerio = require('cheerio');
3 | const fs = require('fs');
4 |
5 | request({
6 | url: 'https://www.ptt.cc/bbs/Soft_Job/index.html',
7 | method: 'GET',
8 | }, function(err, httpResponse, body) {
9 | if (err) {
10 | console.log(err);
11 | return;
12 | }
13 | const $ = cheerio.load(body);
14 | const results = [];
15 | let titles = $('a');
16 |
17 | for(let i = 0; i < titles.length; i++) {
18 | results.push({ title: $(titles[i]).text(), link: $(titles[i]).attr('href') });
19 | }
20 |
21 | fs.writeFileSync('result.json', JSON.stringify(results));
22 | console.log(results);
23 | })
--------------------------------------------------------------------------------
/lectures/Unit22/examples/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "examples",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "app.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "kdchang",
10 | "license": "MIT",
11 | "dependencies": {
12 | "cheerio": "^0.22.0",
13 | "request": "^2.81.0"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/lectures/Unit22/examples/result.json:
--------------------------------------------------------------------------------
1 | [{"title":"批踢踢實業坊","link":"/"},{"title":"看板 Soft_Job","link":"/bbs/Soft_Job/index.html"},{"title":"關於我們","link":"/about.html"},{"title":"聯絡資訊","link":"/contact.html"},{"title":"看板","link":"/bbs/Soft_Job/index.html"},{"title":"精華區","link":"/man/Soft_Job/index.html"},{"title":"最舊","link":"/bbs/Soft_Job/index1.html"},{"title":"‹ 上頁","link":"/bbs/Soft_Job/index1241.html"},{"title":"下頁 ›"},{"title":"最新","link":"/bbs/Soft_Job/index.html"},{"title":"Re: [請益] 純軟外派職缺","link":"/bbs/Soft_Job/M.1492745595.A.5A1.html"},{"title":"Re: [請益] 關於TutorABC的研發部門","link":"/bbs/Soft_Job/M.1492746928.A.B04.html"},{"title":"[請益] 一卡通面試請益","link":"/bbs/Soft_Job/M.1492749853.A.4A3.html"},{"title":"Fw: [北美] 美國軟體工程師生活分享","link":"/bbs/Soft_Job/M.1492751613.A.026.html"},{"title":"Re: [請益] 對面試感到恐懼","link":"/bbs/Soft_Job/M.1492761540.A.021.html"},{"title":"Re: [請益] 對面試感到恐懼","link":"/bbs/Soft_Job/M.1492763015.A.461.html"},{"title":"Re: [請益] 對面試感到恐懼","link":"/bbs/Soft_Job/M.1492766330.A.3F8.html"},{"title":"Re: [請益] 對面試感到恐懼","link":"/bbs/Soft_Job/M.1492778716.A.656.html"},{"title":"Fw: [聘書] offer抉擇","link":"/bbs/Soft_Job/M.1492782020.A.189.html"},{"title":"[討論] 關於負載平衡","link":"/bbs/Soft_Job/M.1492784147.A.19A.html"},{"title":"[請益] offer請益","link":"/bbs/Soft_Job/M.1492789791.A.524.html"},{"title":"[請益] offer選擇 現職/台塑/台銀","link":"/bbs/Soft_Job/M.1492823790.A.1EC.html"},{"title":"[公告] 2017年4月10日 面試心得文需附上時間點","link":"/bbs/Soft_Job/M.1451578149.A.2F4.html"},{"title":"[公告] 徵才不符板規或徵才自刪公司","link":"/bbs/Soft_Job/M.1453196050.A.D41.html"},{"title":"[情報] 訓練課程與付費APP與網站分享","link":"/bbs/Soft_Job/M.1459783651.A.DBE.html"},{"title":"[情報] 社群活動與免費APP與網站分享","link":"/bbs/Soft_Job/M.1459784168.A.0C8.html"}]
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | npm-debug.log
3 | .DS_Store
4 | /*.env
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/127.0.0.1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit23/ajax-node-irich/127.0.0.1
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/Profile:
--------------------------------------------------------------------------------
1 | web: npm start
2 |
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/app.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var path = require('path');
3 | var favicon = require('serve-favicon');
4 | var logger = require('morgan');
5 | var cookieParser = require('cookie-parser');
6 | var bodyParser = require('body-parser');
7 |
8 | var index = require('./routes/index');
9 | var accounts = require('./routes/accounts');
10 | var apiRoutes = require('./routes/apiRoutes');
11 |
12 | var app = express();
13 |
14 | // view engine setup
15 | app.set('views', path.join(__dirname, 'views'));
16 | app.set('view engine', 'ejs');
17 |
18 | // uncomment after placing your favicon in /public
19 | //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
20 | app.use(logger('dev'));
21 | app.use(bodyParser.json());
22 | app.use(bodyParser.urlencoded({ extended: false }));
23 | app.use(cookieParser());
24 | app.use(express.static(path.join(__dirname, 'public')));
25 |
26 | app.use('/', index);
27 | app.use('/accounts', accounts);
28 | app.use('/api', apiRoutes);
29 |
30 | // catch 404 and forward to error handler
31 | app.use(function(req, res, next) {
32 | var err = new Error('Not Found');
33 | err.status = 404;
34 | next(err);
35 | });
36 |
37 | // error handler
38 | app.use(function(err, req, res, next) {
39 | // set locals, only providing error in development
40 | res.locals.message = err.message;
41 | res.locals.error = req.app.get('env') === 'development' ? err : {};
42 |
43 | // render the error page
44 | res.status(err.status || 500);
45 | res.render('error');
46 | });
47 |
48 | module.exports = app;
49 |
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/bin/www:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Module dependencies.
5 | */
6 |
7 | var app = require('../app');
8 | var debug = require('debug')('node-irich:server');
9 | var http = require('http');
10 | var models = require('../models');
11 |
12 | /**
13 | * Get port from environment and store in Express.
14 | */
15 |
16 | var port = normalizePort(process.env.PORT || '3000');
17 | app.set('port', port);
18 |
19 | /**
20 | * Create HTTP server.
21 | */
22 |
23 | var server = http.createServer(app);
24 |
25 | /**
26 | * Listen on provided port, on all network interfaces.
27 | */
28 | models.sequelize.sync().then(function () {
29 | server.listen(port);
30 | server.on('error', onError);
31 | server.on('listening', onListening);
32 | });
33 |
34 | /**
35 | * Normalize a port into a number, string, or false.
36 | */
37 |
38 | function normalizePort(val) {
39 | var port = parseInt(val, 10);
40 |
41 | if (isNaN(port)) {
42 | // named pipe
43 | return val;
44 | }
45 |
46 | if (port >= 0) {
47 | // port number
48 | return port;
49 | }
50 |
51 | return false;
52 | }
53 |
54 | /**
55 | * Event listener for HTTP server "error" event.
56 | */
57 |
58 | function onError(error) {
59 | if (error.syscall !== 'listen') {
60 | throw error;
61 | }
62 |
63 | var bind = typeof port === 'string'
64 | ? 'Pipe ' + port
65 | : 'Port ' + port;
66 |
67 | // handle specific listen errors with friendly messages
68 | switch (error.code) {
69 | case 'EACCES':
70 | console.error(bind + ' requires elevated privileges');
71 | process.exit(1);
72 | break;
73 | case 'EADDRINUSE':
74 | console.error(bind + ' is already in use');
75 | process.exit(1);
76 | break;
77 | default:
78 | throw error;
79 | }
80 | }
81 |
82 | /**
83 | * Event listener for HTTP server "listening" event.
84 | */
85 |
86 | function onListening() {
87 | var addr = server.address();
88 | var bind = typeof addr === 'string'
89 | ? 'pipe ' + addr
90 | : 'port ' + addr.port;
91 | debug('Listening on ' + bind);
92 | }
93 |
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/config/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "development": {
3 | "username": "root",
4 | "password": null,
5 | "database": "database_development",
6 | "host": "127.0.0.1",
7 | "dialect": "sqlite"
8 | },
9 | "test": {
10 | "username": "root",
11 | "password": null,
12 | "database": "database_test",
13 | "host": "127.0.0.1",
14 | "dialect": "sqlite"
15 | },
16 | "production": {
17 | "username": "root",
18 | "password": null,
19 | "database": "database_production",
20 | "host": "127.0.0.1",
21 | "dialect": "sqlite"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/migrations/20170418152012-create-task.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | module.exports = {
3 | up: function(queryInterface, Sequelize) {
4 | return queryInterface.createTable('Tasks', {
5 | id: {
6 | allowNull: false,
7 | autoIncrement: true,
8 | primaryKey: true,
9 | type: Sequelize.INTEGER
10 | },
11 | title: {
12 | type: Sequelize.STRING
13 | },
14 | createdAt: {
15 | allowNull: false,
16 | type: Sequelize.DATE
17 | },
18 | updatedAt: {
19 | allowNull: false,
20 | type: Sequelize.DATE
21 | }
22 | });
23 | },
24 | down: function(queryInterface, Sequelize) {
25 | return queryInterface.dropTable('Tasks');
26 | }
27 | };
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/models/account.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = function(sequelize, DataTypes) {
4 | var Account = sequelize.define('Account', {
5 | title: DataTypes.STRING,
6 | type: DataTypes.STRING,
7 | cost: DataTypes.STRING
8 | });
9 |
10 | return Account;
11 | };
12 |
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/models/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs');
4 | var path = require('path');
5 | var Sequelize = require('sequelize');
6 | var basename = path.basename(module.filename);
7 | var env = process.env.NODE_ENV || 'development';
8 | var config = require(__dirname + '/../config/config.json')[env];
9 | var db = {};
10 |
11 | if (config.use_env_variable) {
12 | var sequelize = new Sequelize(process.env[config.use_env_variable]);
13 | } else {
14 | var sequelize = new Sequelize(config.database, config.username, config.password, config);
15 | }
16 |
17 | fs
18 | .readdirSync(__dirname)
19 | .filter(function(file) {
20 | return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
21 | })
22 | .forEach(function(file) {
23 | var model = sequelize['import'](path.join(__dirname, file));
24 | db[model.name] = model;
25 | });
26 |
27 | Object.keys(db).forEach(function(modelName) {
28 | if (db[modelName].associate) {
29 | db[modelName].associate(db);
30 | }
31 | });
32 |
33 | db.sequelize = sequelize;
34 | db.Sequelize = Sequelize;
35 |
36 | module.exports = db;
37 |
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-irich",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "start": "node ./bin/www"
7 | },
8 | "dependencies": {
9 | "body-parser": "~1.17.1",
10 | "chart.js": "^2.5.0",
11 | "cookie-parser": "~1.4.3",
12 | "debug": "~2.6.3",
13 | "ejs": "~2.5.6",
14 | "express": "~4.15.2",
15 | "morgan": "~1.8.1",
16 | "mysql2": "^1.6.4",
17 | "sequelize": "^3.30.4",
18 | "sequelize-cli": "^2.7.0",
19 | "serve-favicon": "~2.4.2",
20 | "sqlite3": "^3.1.8"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/public/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
3 | }
4 |
5 | a {
6 | color: #00B7FF;
7 | }
8 |
9 | .main-container {
10 | margin-top: 70px;
11 | }
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/routes/accounts.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 | var models = require('../models');
4 |
5 | /* GET users listing. */
6 | router.get('/create', function(req, res, next) {
7 | res.render('create_account');
8 | });
9 |
10 | router.post('/create', function(req, res, next) {
11 | models.Account.create({
12 | title: req.body.title,
13 | type: req.body.type,
14 | cost: req.body.cost
15 | }).then(function() {
16 | res.redirect('/');
17 | });
18 | });
19 |
20 | router.get('/:account_id', function(req, res, next) {
21 | models.Account.findOne({
22 | where: {
23 | id: req.params.account_id
24 | }
25 | }).then(function(account) {
26 | res.render('account', { account: account });
27 | });
28 | });
29 |
30 | router.get('/:account_id/update', function(req, res, next) {
31 | models.Account.findOne({
32 | where: { id: req.params.account_id }
33 | }).then(function(account) {
34 | res.render('update_account', { account: account });
35 | });
36 | });
37 |
38 | router.post('/:account_id/update', function(req, res, next) {
39 | models.Account.findOne({
40 | where: { id: req.params.account_id }
41 | }).then(function(account) {
42 | account.update({
43 | title: req.body.title,
44 | type: req.body.type,
45 | cost: req.body.cost
46 | });
47 | }).then(function() {
48 | res.redirect('/');
49 | });
50 | });
51 |
52 | router.post('/:account_id/delete', function(req, res, next) {
53 | models.Account.destroy({
54 | where: {
55 | id: req.params.account_id
56 | }
57 | }).then(function() {
58 | res.redirect('/');
59 | });
60 | });
61 |
62 | module.exports = router;
63 |
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/routes/apiRoutes.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 | var models = require('../models');
4 |
5 | /* GET users listing. */
6 | router.get('/accounts', function(req, res, next) {
7 | models.Account.findAll().then(function(accounts) {
8 | res.json(accounts);
9 | });
10 | });
11 |
12 | module.exports = router;
13 |
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/routes/index.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 | var models = require('../models');
4 |
5 | /* GET home page. */
6 | router.get('/', function(req, res, next) {
7 | models.Account.findAll().then(function(accounts) {
8 | console.log(accounts);
9 | res.render('index', {
10 | title: 'iRich 愛記帳',
11 | accounts: accounts
12 | });
13 | });
14 | });
15 |
16 | module.exports = router;
17 |
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/views/account.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iRich 愛記帳
5 |
6 |
7 |
8 |
9 |
10 |
11 |
27 |
28 |
29 |
30 |
31 |
32 | Home
33 | <%= account.title %>
34 |
35 |
36 |
37 |
消費標題:<%= account.title %>
38 | 消費類別:<%= account.type %>
39 | 消費花費:<%= account.cost %>
40 |
41 |
42 |
43 |
44 |
45 | © 2016 Company, Inc.
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/views/create_account.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iRich 愛記帳
5 |
6 |
7 |
8 |
9 |
10 |
26 |
27 |
28 |
29 |
新增消費
30 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/views/error.ejs:
--------------------------------------------------------------------------------
1 | <%= message %>
2 | <%= error.status %>
3 | <%= error.stack %>
4 |
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/views/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iRich 愛記帳
5 |
6 |
7 |
8 |
9 |
10 |
11 |
27 |
28 |
29 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | 消費名稱
44 | 消費類型
45 | 支出
46 | 更新操作
47 | 刪除操作
48 |
49 | <% for(var i = 0; i < accounts.length; i++) { %>
50 |
51 | <%= accounts[i].title %>
52 | <%= accounts[i].type %>
53 | <%= accounts[i].cost %>
54 | 更新
55 |
56 |
57 |
60 |
61 |
62 | <% } %>
63 |
64 |
65 |
66 |
67 |
68 | © 2016 Company, Inc.
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/lectures/Unit23/ajax-node-irich/views/update_account.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iRich 愛記帳
5 |
6 |
7 |
8 |
9 |
10 |
26 |
27 |
28 |
29 |
新增消費
30 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | npm-debug.log
3 | .DS_Store
4 | /*.env
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/127.0.0.1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kdchang/javascript101-lite/d6358c0c51e85953345ef5318421dace2331026a/lectures/Unit23/examples/ajax-node-irich/127.0.0.1
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/Profile:
--------------------------------------------------------------------------------
1 | web: npm start
2 |
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/app.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var path = require('path');
3 | var favicon = require('serve-favicon');
4 | var logger = require('morgan');
5 | var cookieParser = require('cookie-parser');
6 | var bodyParser = require('body-parser');
7 |
8 | var index = require('./routes/index');
9 | var accounts = require('./routes/accounts');
10 | var apiRoutes = require('./routes/apiRoutes');
11 |
12 | var app = express();
13 |
14 | // view engine setup
15 | app.set('views', path.join(__dirname, 'views'));
16 | app.set('view engine', 'ejs');
17 |
18 | // uncomment after placing your favicon in /public
19 | //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
20 | app.use(logger('dev'));
21 | app.use(bodyParser.json());
22 | app.use(bodyParser.urlencoded({ extended: false }));
23 | app.use(cookieParser());
24 | app.use(express.static(path.join(__dirname, 'public')));
25 |
26 | app.use('/', index);
27 | app.use('/accounts', accounts);
28 | app.use('/api', apiRoutes);
29 |
30 | // catch 404 and forward to error handler
31 | app.use(function(req, res, next) {
32 | var err = new Error('Not Found');
33 | err.status = 404;
34 | next(err);
35 | });
36 |
37 | // error handler
38 | app.use(function(err, req, res, next) {
39 | // set locals, only providing error in development
40 | res.locals.message = err.message;
41 | res.locals.error = req.app.get('env') === 'development' ? err : {};
42 |
43 | // render the error page
44 | res.status(err.status || 500);
45 | res.render('error');
46 | });
47 |
48 | module.exports = app;
49 |
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/bin/www:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Module dependencies.
5 | */
6 |
7 | var app = require('../app');
8 | var debug = require('debug')('node-irich:server');
9 | var http = require('http');
10 | var models = require('../models');
11 |
12 | /**
13 | * Get port from environment and store in Express.
14 | */
15 |
16 | var port = normalizePort(process.env.PORT || '3000');
17 | app.set('port', port);
18 |
19 | /**
20 | * Create HTTP server.
21 | */
22 |
23 | var server = http.createServer(app);
24 |
25 | /**
26 | * Listen on provided port, on all network interfaces.
27 | */
28 | models.sequelize.sync().then(function () {
29 | server.listen(port);
30 | server.on('error', onError);
31 | server.on('listening', onListening);
32 | });
33 |
34 | /**
35 | * Normalize a port into a number, string, or false.
36 | */
37 |
38 | function normalizePort(val) {
39 | var port = parseInt(val, 10);
40 |
41 | if (isNaN(port)) {
42 | // named pipe
43 | return val;
44 | }
45 |
46 | if (port >= 0) {
47 | // port number
48 | return port;
49 | }
50 |
51 | return false;
52 | }
53 |
54 | /**
55 | * Event listener for HTTP server "error" event.
56 | */
57 |
58 | function onError(error) {
59 | if (error.syscall !== 'listen') {
60 | throw error;
61 | }
62 |
63 | var bind = typeof port === 'string'
64 | ? 'Pipe ' + port
65 | : 'Port ' + port;
66 |
67 | // handle specific listen errors with friendly messages
68 | switch (error.code) {
69 | case 'EACCES':
70 | console.error(bind + ' requires elevated privileges');
71 | process.exit(1);
72 | break;
73 | case 'EADDRINUSE':
74 | console.error(bind + ' is already in use');
75 | process.exit(1);
76 | break;
77 | default:
78 | throw error;
79 | }
80 | }
81 |
82 | /**
83 | * Event listener for HTTP server "listening" event.
84 | */
85 |
86 | function onListening() {
87 | var addr = server.address();
88 | var bind = typeof addr === 'string'
89 | ? 'pipe ' + addr
90 | : 'port ' + addr.port;
91 | debug('Listening on ' + bind);
92 | }
93 |
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/config/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "development": {
3 | "username": "root",
4 | "password": null,
5 | "database": "database_development",
6 | "host": "127.0.0.1",
7 | "dialect": "sqlite"
8 | },
9 | "test": {
10 | "username": "root",
11 | "password": null,
12 | "database": "database_test",
13 | "host": "127.0.0.1",
14 | "dialect": "sqlite"
15 | },
16 | "production": {
17 | "username": "root",
18 | "password": null,
19 | "database": "database_production",
20 | "host": "127.0.0.1",
21 | "dialect": "sqlite"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/migrations/20170418152012-create-task.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | module.exports = {
3 | up: function(queryInterface, Sequelize) {
4 | return queryInterface.createTable('Tasks', {
5 | id: {
6 | allowNull: false,
7 | autoIncrement: true,
8 | primaryKey: true,
9 | type: Sequelize.INTEGER
10 | },
11 | title: {
12 | type: Sequelize.STRING
13 | },
14 | createdAt: {
15 | allowNull: false,
16 | type: Sequelize.DATE
17 | },
18 | updatedAt: {
19 | allowNull: false,
20 | type: Sequelize.DATE
21 | }
22 | });
23 | },
24 | down: function(queryInterface, Sequelize) {
25 | return queryInterface.dropTable('Tasks');
26 | }
27 | };
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/models/account.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = function(sequelize, DataTypes) {
4 | var Account = sequelize.define('Account', {
5 | title: DataTypes.STRING,
6 | type: DataTypes.STRING,
7 | cost: DataTypes.STRING
8 | });
9 |
10 | return Account;
11 | };
12 |
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/models/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs');
4 | var path = require('path');
5 | var Sequelize = require('sequelize');
6 | var basename = path.basename(module.filename);
7 | var env = process.env.NODE_ENV || 'development';
8 | var config = require(__dirname + '/../config/config.json')[env];
9 | var db = {};
10 |
11 | if (config.use_env_variable) {
12 | var sequelize = new Sequelize(process.env[config.use_env_variable]);
13 | } else {
14 | var sequelize = new Sequelize(config.database, config.username, config.password, config);
15 | }
16 |
17 | fs
18 | .readdirSync(__dirname)
19 | .filter(function(file) {
20 | return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
21 | })
22 | .forEach(function(file) {
23 | var model = sequelize['import'](path.join(__dirname, file));
24 | db[model.name] = model;
25 | });
26 |
27 | Object.keys(db).forEach(function(modelName) {
28 | if (db[modelName].associate) {
29 | db[modelName].associate(db);
30 | }
31 | });
32 |
33 | db.sequelize = sequelize;
34 | db.Sequelize = Sequelize;
35 |
36 | module.exports = db;
37 |
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-irich",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "start": "node ./bin/www"
7 | },
8 | "dependencies": {
9 | "body-parser": "~1.17.1",
10 | "chart.js": "^2.5.0",
11 | "cookie-parser": "~1.4.3",
12 | "debug": "~2.6.3",
13 | "ejs": "~2.5.6",
14 | "express": "~4.15.2",
15 | "morgan": "~1.8.1",
16 | "sequelize": "^3.30.4",
17 | "sequelize-cli": "^2.7.0",
18 | "serve-favicon": "~2.4.2",
19 | "sqlite3": "^3.1.8"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/public/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
3 | }
4 |
5 | a {
6 | color: #00B7FF;
7 | }
8 |
9 | .main-container {
10 | margin-top: 70px;
11 | }
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/routes/accounts.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 | var models = require('../models');
4 |
5 | /* GET users listing. */
6 | router.get('/create', function(req, res, next) {
7 | res.render('create_account');
8 | });
9 |
10 | router.post('/create', function(req, res, next) {
11 | models.Account.create({
12 | title: req.body.title,
13 | type: req.body.type,
14 | cost: req.body.cost
15 | }).then(function() {
16 | res.redirect('/');
17 | });
18 | });
19 |
20 | router.get('/:account_id', function(req, res, next) {
21 | models.Account.findOne({
22 | where: {
23 | id: req.params.account_id
24 | }
25 | }).then(function(account) {
26 | res.render('account', { account: account });
27 | });
28 | });
29 |
30 | router.get('/:account_id/update', function(req, res, next) {
31 | models.Account.findOne({
32 | where: { id: req.params.account_id }
33 | }).then(function(account) {
34 | res.render('update_account', { account: account });
35 | });
36 | });
37 |
38 | router.post('/:account_id/update', function(req, res, next) {
39 | models.Account.findOne({
40 | where: { id: req.params.account_id }
41 | }).then(function(account) {
42 | account.update({
43 | title: req.body.title,
44 | type: req.body.type,
45 | cost: req.body.cost
46 | });
47 | }).then(function() {
48 | res.redirect('/');
49 | });
50 | });
51 |
52 | router.post('/:account_id/delete', function(req, res, next) {
53 | models.Account.destroy({
54 | where: {
55 | id: req.params.account_id
56 | }
57 | }).then(function() {
58 | res.redirect('/');
59 | });
60 | });
61 |
62 | module.exports = router;
63 |
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/routes/apiRoutes.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 | var models = require('../models');
4 |
5 | /* GET users listing. */
6 | router.get('/accounts', function(req, res, next) {
7 | models.Account.findAll().then(function(accounts) {
8 | res.json(accounts);
9 | });
10 | });
11 |
12 | module.exports = router;
13 |
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/routes/index.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 | var models = require('../models');
4 |
5 | /* GET home page. */
6 | router.get('/', function(req, res, next) {
7 | models.Account.findAll().then(function(accounts) {
8 | console.log(accounts);
9 | res.render('index', {
10 | title: 'iRich 愛記帳',
11 | accounts: accounts
12 | });
13 | });
14 | });
15 |
16 | module.exports = router;
17 |
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/views/account.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iRich 愛記帳
5 |
6 |
7 |
8 |
9 |
10 |
11 |
27 |
28 |
29 |
30 |
31 |
32 | Home
33 | <%= account.title %>
34 |
35 |
36 |
37 |
消費標題:<%= account.title %>
38 | 消費類別:<%= account.type %>
39 | 消費花費:<%= account.cost %>
40 |
41 |
42 |
43 |
44 |
45 | © 2016 Company, Inc.
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/views/create_account.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iRich 愛記帳
5 |
6 |
7 |
8 |
9 |
10 |
26 |
27 |
28 |
29 |
新增消費
30 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/views/error.ejs:
--------------------------------------------------------------------------------
1 | <%= message %>
2 | <%= error.status %>
3 | <%= error.stack %>
4 |
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/views/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iRich 愛記帳
5 |
6 |
7 |
8 |
9 |
10 |
11 |
27 |
28 |
29 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | 消費名稱
44 | 消費類型
45 | 支出
46 | 更新操作
47 | 刪除操作
48 |
49 | <% for(var i = 0; i < accounts.length; i++) { %>
50 |
51 | <%= accounts[i].title %>
52 | <%= accounts[i].type %>
53 | <%= accounts[i].cost %>
54 | 更新
55 |
56 |
57 |
60 |
61 |
62 | <% } %>
63 |
64 |
65 |
66 |
67 |
68 | © 2016 Company, Inc.
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/lectures/Unit23/examples/ajax-node-irich/views/update_account.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iRich 愛記帳
5 |
6 |
7 |
8 |
9 |
10 |
26 |
27 |
28 |
29 |
新增消費
30 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/lectures/Unit24/examples/BeautyPlus/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/lectures/Unit24/examples/BeautyPlus/LICENSE.md:
--------------------------------------------------------------------------------
1 | CC0 1.0 Universal
2 | ==================
3 |
4 | Statement of Purpose
5 | ---------------------
6 |
7 | The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
8 |
9 | Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
10 |
11 | For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
12 |
13 | 1. Copyright and Related Rights.
14 | --------------------------------
15 | A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
16 |
17 | i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
18 | ii. moral rights retained by the original author(s) and/or performer(s);
19 | iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
20 | iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
21 | v. rights protecting the extraction, dissemination, use and reuse of data in a Work;
22 | vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
23 | vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
24 |
25 | 2. Waiver.
26 | -----------
27 | To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
28 |
29 | 3. Public License Fallback.
30 | ----------------------------
31 | Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
32 |
33 | 4. Limitations and Disclaimers.
34 | --------------------------------
35 |
36 | a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
37 | b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
38 | c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
39 | d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
40 |
--------------------------------------------------------------------------------
/lectures/Unit24/examples/BeautyPlus/README.md:
--------------------------------------------------------------------------------
1 | # electron-quick-start
2 |
3 | **Clone and run for a quick way to see Electron in action.**
4 |
5 | This is a minimal Electron application based on the [Quick Start Guide](http://electron.atom.io/docs/tutorial/quick-start) within the Electron documentation.
6 |
7 | **Use this app along with the [Electron API Demos](http://electron.atom.io/#get-started) app for API code examples to help you get started.**
8 |
9 | A basic Electron application needs just these files:
10 |
11 | - `package.json` - Points to the app's main file and lists its details and dependencies.
12 | - `main.js` - Starts the app and creates a browser window to render HTML. This is the app's **main process**.
13 | - `index.html` - A web page to render. This is the app's **renderer process**.
14 |
15 | You can learn more about each of these components within the [Quick Start Guide](http://electron.atom.io/docs/tutorial/quick-start).
16 |
17 | ## To Use
18 |
19 | To clone and run this repository you'll need [Git](https://git-scm.com) and [Node.js](https://nodejs.org/en/download/) (which comes with [npm](http://npmjs.com)) installed on your computer. From your command line:
20 |
21 | ```bash
22 | # Clone this repository
23 | git clone https://github.com/electron/electron-quick-start
24 | # Go into the repository
25 | cd electron-quick-start
26 | # Install dependencies
27 | npm install
28 | # Run the app
29 | npm start
30 | ```
31 |
32 | ## Resources for Learning Electron
33 |
34 | - [electron.atom.io/docs](http://electron.atom.io/docs) - all of Electron's documentation
35 | - [electron.atom.io/community/#boilerplates](http://electron.atom.io/community/#boilerplates) - sample starter apps created by the community
36 | - [electron/electron-quick-start](https://github.com/electron/electron-quick-start) - a very basic starter Electron app
37 | - [electron/simple-samples](https://github.com/electron/simple-samples) - small applications with ideas for taking them further
38 | - [electron/electron-api-demos](https://github.com/electron/electron-api-demos) - an Electron app that teaches you how to use Electron
39 | - [hokein/electron-sample-apps](https://github.com/hokein/electron-sample-apps) - small demo apps for the various Electron APIs
40 |
41 | ## License
42 |
43 | [CC0 1.0 (Public Domain)](LICENSE.md)
44 |
--------------------------------------------------------------------------------
/lectures/Unit24/examples/BeautyPlus/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Beauty+
6 |
7 |
8 |
9 |
10 |
Beauty+
11 |
12 |
好手氣
13 |
14 |
15 |
16 |
20 |
21 |
--------------------------------------------------------------------------------
/lectures/Unit24/examples/BeautyPlus/main.js:
--------------------------------------------------------------------------------
1 | const electron = require('electron')
2 | // Module to control application life.
3 | const app = electron.app
4 | // Module to create native browser window.
5 | const BrowserWindow = electron.BrowserWindow
6 |
7 | const path = require('path')
8 | const url = require('url')
9 |
10 | // Keep a global reference of the window object, if you don't, the window will
11 | // be closed automatically when the JavaScript object is garbage collected.
12 | let mainWindow
13 |
14 | function createWindow () {
15 | // Create the browser window.
16 | mainWindow = new BrowserWindow({width: 800, height: 600})
17 |
18 | // and load the index.html of the app.
19 | mainWindow.loadURL(url.format({
20 | pathname: path.join(__dirname, 'index.html'),
21 | protocol: 'file:',
22 | slashes: true
23 | }))
24 |
25 | // Open the DevTools.
26 | mainWindow.webContents.openDevTools()
27 |
28 |
29 | // Emitted when the window is closed.
30 | mainWindow.on('closed', function () {
31 | // Dereference the window object, usually you would store windows
32 | // in an array if your app supports multi windows, this is the time
33 | // when you should delete the corresponding element.
34 | mainWindow = null
35 | })
36 | }
37 |
38 | // This method will be called when Electron has finished
39 | // initialization and is ready to create browser windows.
40 | // Some APIs can only be used after this event occurs.
41 | app.on('ready', createWindow)
42 |
43 | // Quit when all windows are closed.
44 | app.on('window-all-closed', function () {
45 | // On OS X it is common for applications and their menu bar
46 | // to stay active until the user quits explicitly with Cmd + Q
47 | if (process.platform !== 'darwin') {
48 | app.quit()
49 | }
50 | })
51 |
52 | app.on('activate', function () {
53 | // On OS X it's common to re-create a window in the app when the
54 | // dock icon is clicked and there are no other windows open.
55 | if (mainWindow === null) {
56 | createWindow()
57 | }
58 | })
59 |
60 | // In this file you can include the rest of your app's specific main process
61 | // code. You can also put them in separate files and require them here.
62 |
--------------------------------------------------------------------------------
/lectures/Unit24/examples/BeautyPlus/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "electron-quick-start",
3 | "version": "1.0.0",
4 | "description": "A minimal Electron application",
5 | "main": "main.js",
6 | "scripts": {
7 | "start": "electron ."
8 | },
9 | "repository": "https://github.com/electron/electron-quick-start",
10 | "keywords": [
11 | "Electron",
12 | "quick",
13 | "start",
14 | "tutorial",
15 | "demo"
16 | ],
17 | "author": "GitHub",
18 | "license": "CC0-1.0",
19 | "devDependencies": {
20 | "electron": "~1.6.2"
21 | },
22 | "dependencies": {
23 | "request": "^2.81.0"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lectures/Unit24/examples/BeautyPlus/renderer.js:
--------------------------------------------------------------------------------
1 | // This file is required by the index.html file and will
2 | // be executed in the renderer process for that window.
3 | // All of the Node.js APIs are available in this process.
4 |
5 | var request = require('request');
6 |
7 | var luckybtn = document.getElementById('luckybtn');
8 |
9 | luckybtn.addEventListener('click', function() {
10 | request({
11 | uri: 'http://gank.io/api/data/%E7%A6%8F%E5%88%A9/500/1',
12 | method: 'GET'
13 | }, function(error, response, body) {
14 | //console.log(body);
15 | var data = JSON.parse(body);
16 | var index = Math.floor(Math.random() * data.results.length) // (0 - 1) * 467 -> 0....466
17 |
18 | var result = document.getElementById('result');
19 | var strHTML = ' ';
20 | result.innerHTML = strHTML;
21 | });
22 | });
--------------------------------------------------------------------------------
/lectures/Unit25/examples/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "public/bower_components/",
3 | "timeout": 120000,
4 | "registry": {
5 | "search": [
6 | "https://bower.herokuapp.com"
7 | ]
8 | }
9 | }
--------------------------------------------------------------------------------
/lectures/Unit25/examples/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log
16 |
--------------------------------------------------------------------------------
/lectures/Unit25/examples/ReactTodo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ReactTodo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
65 |
66 |
67 |
--------------------------------------------------------------------------------