├── .gitignore
├── Application
├── 1-Mask-Words
│ └── README.md
├── 2-A-Simple-Logger
│ └── README.md
├── 3-Query-Language-Over-CSV
│ └── README.md
└── README.md
├── README.md
├── week1
├── 1-hello-node
│ └── README.md
├── 2-simple-blog
│ └── README.md
├── 3-jade-blog
│ └── README.md
├── README.md
└── hangout
│ ├── .bowerrc
│ ├── .gitignore
│ ├── bower.json
│ ├── package.json
│ ├── posts.json
│ ├── public
│ ├── css
│ │ └── style.css
│ └── img
│ │ ├── bg.jpg
│ │ ├── content-bg.png
│ │ ├── logo.png
│ │ ├── post1.png
│ │ └── post2.jpg
│ ├── server.js
│ └── views
│ ├── index.jade
│ ├── layout.jade
│ └── post.jade
├── week2
├── 1-bulls-n-cows
│ └── README.md
├── 2-console-crud
│ └── README.md
├── README.md
└── hangout
│ ├── crud.js
│ ├── data
│ └── users.json
│ └── package.json
├── week3
├── 1-A-Panda
│ ├── README.md
│ └── panda.js
├── 2-Point
│ ├── README.md
│ └── points.js
├── 3-Prototypes
│ ├── README.md
│ └── prototypes.js
├── 4-Queue
│ ├── README.md
│ └── queue.js
├── 5-Event-Bus
│ ├── README.md
│ └── bus.js
├── 6-HTML-Generator
│ └── README.md
├── README.md
└── materials
│ ├── call_apply.js
│ ├── closure.js
│ └── person.js
├── week4
├── 1-Keeping-up-the-Score
│ ├── README.md
│ ├── mockup.png
│ ├── page.html
│ └── page.js
├── 2-DOM-Todo
│ ├── README.md
│ ├── example.html
│ ├── example.js
│ └── mockup.png
├── README.md
├── hangout
│ ├── README.md
│ ├── dom-wrapper.js
│ ├── index.html
│ └── interface.js
└── materials
│ ├── dom.js
│ ├── page.html
│ └── page.js
├── week5
├── 2-todo-crud
│ └── README.md
├── README.md
└── hangout
│ ├── .bowerrc
│ ├── bower.json
│ ├── css
│ └── style.css
│ ├── index.html
│ └── js
│ ├── app.js
│ └── init.js
├── week6
├── 1-bootstrap-shop
│ └── README.md
├── 2-hobby-site
│ ├── .bowerrc
│ ├── README.md
│ ├── server.js
│ └── views
│ │ ├── index.jade
│ │ └── layout.jade
├── README.md
├── guides
│ └── sass.md
├── hangout1
│ ├── .bowerrc
│ ├── bower.json
│ ├── data
│ │ └── rest.json
│ ├── package.json
│ ├── public
│ │ ├── css
│ │ │ └── style.css
│ │ └── js
│ │ │ ├── app.js
│ │ │ ├── init.js
│ │ │ ├── taskModel.js
│ │ │ └── tasksView.js
│ ├── server.js
│ └── views
│ │ └── index.jade
├── hangout1_full
│ ├── .bowerrc
│ ├── bower.json
│ ├── data
│ │ └── rest.json
│ ├── package.json
│ ├── public
│ │ ├── css
│ │ │ └── style.css
│ │ └── js
│ │ │ ├── app.js
│ │ │ ├── init.js
│ │ │ ├── taskModel.js
│ │ │ └── tasksView.js
│ ├── server.js
│ └── views
│ │ └── index.jade
└── hangout2
│ ├── .bowerrc
│ ├── bower.json
│ ├── package.json
│ ├── public
│ ├── css
│ │ ├── inc
│ │ │ ├── _base.scss
│ │ │ ├── _layout.scss
│ │ │ ├── helpers
│ │ │ │ ├── _bootstrap_mod.scss
│ │ │ │ └── _vars.scss
│ │ │ └── sections
│ │ │ │ ├── _events.scss
│ │ │ │ └── _home.scss
│ │ ├── style.css
│ │ └── style.scss
│ └── img
│ │ ├── artists
│ │ ├── james-brown.jpg
│ │ ├── jamiroquai.jpg
│ │ └── tom-jones.jpeg
│ │ ├── events
│ │ ├── event1.jpg
│ │ ├── event2.jpg
│ │ └── event3.jpg
│ │ └── header-bg.jpg
│ ├── server.js
│ └── views
│ ├── artists.jade
│ ├── events.jade
│ ├── index.jade
│ └── layout.jade
├── week7
└── 1-students-crud
│ └── README.md
└── week8
├── 2-rest-resource
├── .bowerrc
├── README.md
├── data
│ └── restMap.json
├── public
│ └── js
│ │ └── init.js
└── server.js
├── README.md
├── hangout
├── .bowerrc
├── .gitignore
├── bower.json
├── data
│ └── restMap.json
├── package.json
├── public
│ ├── js
│ │ ├── init.js
│ │ └── resource.js
│ └── views
│ │ ├── mags.jade
│ │ ├── subs.jade
│ │ └── users.jade
├── server.js
└── views
│ └── index.jade
└── rest-example
├── .bowerrc
├── bower.json
├── data
└── restMap.json
├── package.json
├── public
└── js
│ ├── init.js
│ └── resource.js
├── server.js
└── views
└── index.jade
/.gitignore:
--------------------------------------------------------------------------------
1 | README.html
2 | lib
3 | node_modules
4 | public/lib
5 | style.css.map
6 | npm-debug.log
7 | .sass-cache
8 |
--------------------------------------------------------------------------------
/Application/1-Mask-Words/README.md:
--------------------------------------------------------------------------------
1 | # Problem 1 - Mask Out Words
2 |
3 | In a programming language of your choice, implement the following function/method:
4 |
5 | ```
6 | maskOutWords(words, text)
7 | ```
8 |
9 | If you read type declarations well, here it is:
10 |
11 | ```haskell
12 | maskOutWords :: [String] -> String -> String
13 | ```
14 |
15 | Where:
16 |
17 | * `words` is a list of words (strings)
18 | * `text` is a string, that may contain newlines - `\n`
19 |
20 |
21 | The function should return a new text, where each matching word from `words` is replaced by the same number of characters `*`.
22 |
23 | Consider the following things:
24 |
25 | * **All matching should be case insensitive!**
26 | * Take care of words that end with `,` or `.` - they should be matached, without the punctiation.
27 |
28 | For example, if we have the following arguments:
29 |
30 | * `words = ["PHP"]`
31 | * `text = "We love coding in PHP!\nThis makes us really productive"`
32 |
33 | The result is going to be:
34 |
35 | ```
36 | "We love coding in ***!\nThis makes us really productive"
37 | ```
38 |
39 | Another example will be:
40 |
41 | * `words = ["yesterday", "Dog", "food", "walk"]`
42 | * `text = "Yesterday, I took my dog for a walk.\n It was crazy! My dog wanted only food."`
43 |
44 | The result is going to be:
45 |
46 | ```
47 | ********, I took my *** for a ****.\n It was crazy! My *** wanted only ****."
48 | ```
49 |
--------------------------------------------------------------------------------
/Application/2-A-Simple-Logger/README.md:
--------------------------------------------------------------------------------
1 | # Problem 2 - A simple logger
2 |
3 | In a language of your choice, implement the following things:
4 |
5 | ## The interface
6 |
7 | Make an interface, called `MyLogger` with only 1 method - `log(level, message)`
8 |
9 | The two arguments should be:
10 |
11 | * `level` - an integer, from 1 to 3.
12 | * 1 means that your are logging with `INFO` level.
13 | * 2 means that you are logging with `WARNING` level.
14 | * 3 means that you are logging with `PLSCHECKFFS` level.
15 | * `message` is a string, that you are logging.
16 |
17 | There is a rule of how to make the log message, regardless where you are saving it:
18 |
19 | ```
20 | {LOG_LEVEL_STRING}::{TIMESTAMP}::{MESSAGE}
21 | ```
22 |
23 | For example, if we log with `level = 1`, and `message = "Hello World"`, this will produce the following line:
24 |
25 | ```
26 | INFO::2015-02-02T01:43:19+00:00::Hello World
27 | ```
28 |
29 | [The timestamp should be in ISO 8901 format.](http://en.wikipedia.org/wiki/ISO_8601)
30 |
31 | Make 3 different classes, that implement the interface `MyLogger`:
32 |
33 | ## `ConsoleLogger`
34 |
35 | The `ConsoleLogger` should log the messages directly to the console.
36 |
37 | ## `FileLogger`
38 |
39 | The `FileLogger` should log the messages to a given file.
40 |
41 | ## `HTTPLogger`
42 |
43 | The `HTTPLogger` shoud log the messages via a POST request to a given HTTP url.
44 |
45 | ## Examples
46 |
47 | For each logger, make sure to include examples - scripts or tests that show how the logging works.
48 |
--------------------------------------------------------------------------------
/Application/3-Query-Language-Over-CSV/README.md:
--------------------------------------------------------------------------------
1 | # Problem 3 - A query language over a CSV file
2 |
3 | A CSV files (comma separated values) can be represented as a table.
4 |
5 | For example this CSV file:
6 |
7 | ```csv
8 | id, name, course
9 | 1, Rado, Haskell
10 | 2, Ivo, Python
11 | ```
12 |
13 | Can be represented by this table:
14 |
15 | | id | name | course |
16 | |----|------|---------|
17 | | 1 | Rado | Haskell |
18 |
19 |
20 | We are going to use CSV files as tables and make a simple query language for fetching data.
21 |
22 | **In a language of your choice, make a program that:**
23 |
24 | * Reads a CSV file.
25 | * Gives the user an interactive input for queries.
26 | * Answers the queries with data from the CSV file.
27 |
28 | The queries, that should be supported are:
29 |
30 | * `SELECT [columns] LIMIT X` - where you can SELECT without giving the LIMIT. Then this will fetch all rows.
31 | * `SUM [column]` - returns the sum of all integers in the given column.
32 | * `SHOW` - returns a list of all column names in your data.
33 | * `FIND X` - returns all rows, that has `X` in some of their cells (Match X with at least one of the columns). **If `X` is a string, search for every string, that contains `X` as a substring.**
34 |
35 | Here are examples of all queries.
36 |
37 | Consider that we have loaded the following CSV:
38 |
39 | ```csv
40 | id,name,hometown
41 | 1,Kiara,Lunel
42 | 2,Mona,Henley-on-Thames
43 | 3,Kiayada,Villers-aux-Tours
44 | 4,Karly,Hillsboro
45 | 5,Igor,Oranienburg
46 | ```
47 |
48 | Now, lets make queries:
49 |
50 |
51 | ```
52 | query>SELECT id
53 | |id|
54 | |--|
55 | |1 |
56 | |2 |
57 | |3 |
58 | |4 |
59 | |5 |
60 | ```
61 |
62 | ```
63 | query> SELECT id, name
64 | |id| name |
65 | |--|--------|
66 | |1 |Kiara |
67 | |2 |Mona |
68 | |3 |Kiayada |
69 | |4 |Karly |
70 | |5 |Igor |
71 | ```
72 |
73 | ```
74 | query> SELECT id, name LIMIT 1
75 | |id| name |
76 | |--|--------|
77 | |1 |Kiara |
78 | ```
79 |
80 | ```
81 | query> SUM id
82 | 15
83 | ```
84 |
85 | ```
86 | query> SHOW
87 | id, name, hometown
88 | ```
89 |
90 | ```
91 | query> FIND "-"
92 | |id| name | hometown |
93 | |--|--------| ------------------|
94 | |2 |Mona | Henley-on-Thames |
95 | |3 |Kiayada | Villers-aux-Tours |
96 | ```
97 |
98 | ## Features
99 |
100 | * If the query is non-valid - say it. Don't crash the program.
101 | * As you see in the examples, the results should be displayed in visual, tabular way. This is up to you. You don't have to follow the styles of the example.
102 |
--------------------------------------------------------------------------------
/Application/README.md:
--------------------------------------------------------------------------------
1 | # Application problems for Frontend JavaScript
2 |
3 | ## Problem 1 - Mask out words
4 |
5 | [Read the description here.](1-Mask-Words)
6 |
7 | ## Problem 2 - A simple Logger
8 |
9 | [Read the description here.](2-A-Simple-Logger)
10 |
11 | ## Problem 3 - Query language over CSV
12 |
13 | [Read the description here.](3-Query-Language-Over-CSV)
14 |
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Frontend-JavaScript-2
2 |
3 | The second edition of the Frontend JavaScript course in HackBulgaria.
4 |
5 | ```
6 | _ _____ _ _
7 | | | / ____| (_) | |
8 | | | __ _ __ __ __ _ | (___ ___ _ __ _ _ __ | |_
9 | _ | | / _` |\ \ / // _` | \___ \ / __|| '__|| || '_ \ | __|
10 | | |__| || (_| | \ V /| (_| | ____) || (__ | | | || |_) || |_
11 | \____/ \__,_| \_/ \__,_||_____/ \___||_| |_|| .__/ \__|
12 | | |
13 | |_|
14 | ```
15 |
16 | ## Douglas Crockford
17 |
18 | Watch those videos:
19 |
20 | * [JavaScript - The Early Years](https://www.youtube.com/watch?v=JxAXlJEmNMg)
21 | * [And Then There Was JavaScript](https://www.youtube.com/watch?v=RO1Wnu-xKoY)
22 | * [Function the Ultimate](https://www.youtube.com/watch?v=ya4UHuXNygM)
23 | ## Materials for prepartion
24 | * [Metamorphosis of AJAX](https://www.youtube.com/watch?v=Fv9qT9joc0M)
25 | * [The End of All Things](https://www.youtube.com/watch?v=47Ceot8yqeI)
26 |
27 |
28 | We strongly recommend that you check the following materials:
29 |
30 | * Throughout the course we will use the following book - http://eloquentjavascript.net/
31 | * For the start of the course, **you can read from chapter 1 to chapter 4** - to get a good feeling of the language.
32 | * If you are into it, you can complete the JavaScript track in CodeCademy - http://www.codecademy.com/en/tracks/javascript
33 |
34 |
35 | ## Course Program
36 |
37 | **The program is subject to change and will change until it gets to its final form ;)**
38 |
39 | * JavaScript the good the bad and the weird parts - learning JavaScript as a language.
40 | * The Art and Science of Front-end development
41 | * Building an Interface with jQuery
42 | - DOM manipulation
43 | - event handling
44 | - plugins
45 |
46 | * Bootstrapping the UX
47 | * Sculpting with SASS
48 | * Thinking Async - Closures, Callbacks, Promises
49 | * CRUD Pattern with jQuery and Firebase
50 | * Data manipulation with lodash
51 | * SPAs with Angular Part 1
52 | * SPAs with Angular Part 2
53 | * HTML5 APIs - Canvas & WebSockets. Making games!
54 | * (Bonus) 3D Apps with Three.js
55 | * (Bonus) Diagrams, Charts with d3.js and Raphael.js
56 |
57 |
--------------------------------------------------------------------------------
/week1/1-hello-node/README.md:
--------------------------------------------------------------------------------
1 | # Week 1 Task 1: Hello Node
2 | To start off let's create our directory structure and set up a new hello world project.
3 |
4 | ## Starting File Structure
5 | ```sh
6 | # in unix you can create it in 1 line:
7 | $ mkdir -p ~/Projects/frontendjs/week1/hello-node
8 |
9 | # enter the project folder
10 | $ cd ~/Projects/frontendjs/week1/hello-node
11 |
12 | # also creating a file is easy
13 | $ touch server.js
14 | ```
15 |
16 | The file structure should look something like this:
17 | ```
18 | .
19 | └── Projects
20 | └── frontendjs
21 | └── week1
22 | └── hello-node
23 | └── server.js
24 | ```
25 |
26 | ## Inits and Dependencies
27 |
28 | Let's init our configuration file and fetch the modules we need.
29 |
30 | We will use [npm](https://www.npmjs.com/) (Node Package Manager) for that:
31 |
32 | ```sh
33 | # init the project. When prompted leave the defaults
34 | $ npm init
35 | ```
36 | This will produce *package.json* which holds info about the project and it's dependencies.
37 |
38 | Speaking of which our dependency for this project would be [express](http://www.expressjs.com).
39 |
40 | ```
41 | # installs the express module to the ./node_modules folder
42 | # --save adds it to the dependencies in package.json
43 | $ npm install --save express
44 | ```
45 |
46 | ## Hello Express
47 |
48 | Open server.js and add the following code:
49 |
50 | ```javascript
51 | "use strict"
52 |
53 | // require the dependencies
54 | var express = require('express');
55 |
56 | // declare the app
57 | var app = express();
58 |
59 | // TODO: configure the app
60 |
61 | // add the routes
62 | app.get('/', function (req, res) {
63 | res.send('Hello World!');
64 | })
65 |
66 | // launch the server
67 | var server = app.listen(3000, function () {
68 |
69 | var host = server.address().address;
70 | var port = server.address().port;
71 |
72 | console.log('Example app listening at http://%s:%s', host, port);
73 |
74 | })
75 |
76 | ```
77 |
78 | Next run the example with *node* and check the result at http://localhost:3000/
79 |
80 | ```sh
81 | $ node server.js
82 | ```
83 |
84 | Nice we have running our first node server. Oh wait wasn't this a front-end course.
85 |
86 | ## Go Public
87 |
88 | With our example above we set up a server that prints out "Hello World" everytime someone opens the base url. In order to be able to serve different *static* files such as htmls, styles, images we eighter need to add another route for each or we can just use the middleware express graciously provided.
89 |
90 | Just add the following code in the "configure the app section":
91 | ```javascript
92 | // configure the app
93 | app.use(express.static('public'));
94 | ```
95 |
96 | Next let's create the public folder, in it an index.html file.
97 | ```sh
98 | # Look ma, all in 1 line
99 | $ mkdir public; touch public/index.html
100 | ```
101 |
102 | Also add the hello world message there:
103 | ```html
104 |
105 |
Hello World!
106 | ```
107 |
108 | And remove or comment the old route in *server.js* so that it doesn't conflict with *index.html*
109 | ```javascript
110 | // add the routes
111 | /*app.get('/', function (req, res) {
112 | res.send('Hello World!');
113 | })*/
114 | ```
115 |
116 | Save, restart and check the browser again.
117 |
118 | Well basically the same message. Shall we spice things up a bit.
119 |
120 | ## Bower up
121 |
122 | If you remember we used [npm](www.npmjs.com) to manage our dependencies for the server.
123 |
124 | Now that we have created a public folder for our front-end needs we need a front-end package manager.
125 |
126 | [Bower](bower.io) is our app. Pretty much works the same way as npm.
127 |
128 | Speaking of npm we will need it to install bower globally so that we can use it in all our projects.
129 | ```sh
130 | # -g stands for gangsta
131 | npm install -g bower
132 | ```
133 |
134 | Next we need to configure a directory for our front-end libs. Create(touch) the file .bowerrc and add the following content to it:
135 | ```json
136 | {
137 | "directory": "public/lib"
138 | }
139 | ```
140 |
141 | Next we be initing
142 | ```sh
143 | # same as npm, produces bower.json
144 | $ bower init
145 | ```
146 |
147 | Alright let's add an awesome lib to mark our first steps in bower.
148 | ```sh
149 | # adds the lib to public/lib and saves the dependency to bower.json
150 | $ bower install --save fontawesome
151 | ```
152 |
153 | Our directory structure should look something like this:
154 | ```
155 | .
156 | ├── server.js
157 | ├── package.json
158 | └── node_modules
159 | │ └── express
160 | ├── .bowerrc
161 | ├── bower.json
162 | └── public
163 | ├── index.html
164 | └── lib
165 | └── fontawesome
166 | ```
167 |
168 | Awesome, [Font Awesome](http://fontawesome.io/)
169 |
170 | Add to top things off add a nice icon to compliment our message:
171 |
172 | ```html
173 |
174 |
175 |
Hello World!
176 | ```
177 |
--------------------------------------------------------------------------------
/week1/2-simple-blog/README.md:
--------------------------------------------------------------------------------
1 | # Week 1 Task 2: Simple Blog
2 | Now let's create something more complex than a hello world page.
--------------------------------------------------------------------------------
/week1/3-jade-blog/README.md:
--------------------------------------------------------------------------------
1 | # Week 1 Task 3: Jade Blog
2 |
3 | ## Init Stuff
4 | You know the drill, files, dependencies, server. If not check out the hello node task.
5 |
6 | You should end up with something like this:
7 | ```
8 | .
9 | ├── server.js
10 | ├── package.json
11 | ├── node_modules
12 | │ └── express
13 | ├── .bowerrc
14 | ├── bower.json
15 | └── public
16 | ├── index.html
17 | └── lib
18 | └── fontawesome
19 | ```
20 |
21 | ## Jade What
22 |
23 | There are a lot of template engines out there. Most of them are plain old html with additional patterns or masks that indicate where variables should be inserted, conditional statements, loops etc...
24 |
25 | One of the biggest things that differentiate jade is that it goes one step further and get's rid of the unneeded characters and leaves only the most important.
26 |
27 | so this:
28 | ```html
29 |
30 | ```
31 | translates to this:
32 | ```jade
33 | div.className#idName(attr="1")
34 | ```
35 |
36 | div's, since we all use them a lot in jade we can ommit them. So this also works:
37 | ```jade
38 | .className#idName(attr="1")
39 | ```
40 |
41 | You may notice that this jade statemet looks very much like a css selector.
42 |
43 | To top things off you don't need closing tags. The structure is defined, well with a structure.
44 |
45 | Here is a more complex example:
46 | ```jade
47 | .className#idName(attr="1",style="border: 1px;")
48 | span.class1.class2#id1 Some Text Here
49 | p.
50 | Text positioned bellow a tag with a "." at the end
51 | and with additional identation will be inserted as is
52 | no matter on how many lines. Of course this works great for
53 | script(type="text/javascript").
54 | var javaScript = "Code Here";
55 | function forReal(){
56 | alert("I am not kidding!");
57 | }
58 | ```
59 |
60 | Compiled will produce the following html:
61 | ```html
62 |
63 | Some Text Here
64 |
65 | Text positioned bellow a tag with a "." at the end
66 | and with additional identation will be inserted as is
67 | no matter on how many lines. Of course this works great for
68 |
69 |
75 |
76 | ```
77 |
78 | Ok now that we know what jade code looks like and how to translate it to and back from html (if not check the jade lang site. It has a good documentation and examples)
79 |
80 | ## Install Jade
81 |
82 | Since we already inited our project and have installed and set up express we can just
83 | ```sh
84 | npm install --save jade
85 | ```
86 |
87 | To make express play nice with jade just after
88 | ```javascript
89 | // configure the app
90 | app.use(express.static('public'));
91 | ```
92 |
93 | add
94 | ```javascript
95 | app.set('view engine', 'jade');
96 | ```
--------------------------------------------------------------------------------
/week1/README.md:
--------------------------------------------------------------------------------
1 | # Week 1 Start
2 |
3 | ## Prerequisites
4 |
5 | ### Environment
6 | - Node Installed
7 | - For Linux Users - Search Google for: "Digital Ocean install node via nvm"
8 | - Git Installed
9 | - IDE - minimum Sublime
10 |
11 | ### Knowledge
12 | - HTML, CSS (required)
13 | - Basic programming knowledge (recommended)
14 | - Data types, Operations, Arrays, Dictionaries, OOP
15 |
16 | ## Before you start
17 |
18 | - Create a folder for the course, preferably in a Projects folder in your home folder
19 | ```sh
20 | # in linux
21 | $ mkdir -p ~/Projects/frontendjs/week1
22 | $ cd ~/Projects/frontendjs
23 | ```
24 |
25 | - init a git repo that you will add all your tasks each week
26 | ```sh
27 | # init the repo
28 | $ git init
29 | # create an empty file to be added to the repo
30 | $ touch README.md
31 | # add all
32 | $ git add .
33 | # your first commit
34 | $ git commit -m "initial commit"
35 | ```
36 |
37 | - create a repo in github and follow the instructions there to link them
38 |
39 | Next up - Hello Node
--------------------------------------------------------------------------------
/week1/hangout/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "public/lib"
3 | }
--------------------------------------------------------------------------------
/week1/hangout/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | public/lib
3 | npm-debug.log
--------------------------------------------------------------------------------
/week1/hangout/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "week1hangout",
3 | "version": "0.0.9",
4 | "authors": [
5 | "Alex Milanov "
6 | ],
7 | "description": "week 1 final project plus some stuff",
8 | "main": "server.js",
9 | "keywords": [
10 | "jade",
11 | "blog",
12 | "express"
13 | ],
14 | "license": "MIT",
15 | "ignore": [
16 | "**/.*",
17 | "node_modules",
18 | "bower_components",
19 | "test",
20 | "tests"
21 | ],
22 | "dependencies": {
23 | "bootstrap": "~3.3.4"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/week1/hangout/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "week1hangout",
3 | "version": "0.0.9",
4 | "description": "week 1 final project plus some stuff",
5 | "main": "server.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "node server.js"
9 | },
10 | "keywords": [
11 | "jade",
12 | "express",
13 | "blog"
14 | ],
15 | "author": "Alex Milanov",
16 | "license": "ISC",
17 | "dependencies": {
18 | "express": "^4.12.3",
19 | "jade": "^1.9.2"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/week1/hangout/posts.json:
--------------------------------------------------------------------------------
1 | {
2 | "post1" : {
3 | "img": "img/post1.png",
4 | "title": "Optimizing Investing, Blood, Hormones, and Life (Podcast Double-Header: #63 and #65)",
5 | "text": "[DISCLAIMER: I’m not a doctor, nor do I play one on the Internet. Speak with a medical professional before doing anything medical-related, m’kay?]There is something here for everyone.This post details two jam-packed discussions — one with world-renowned macro investors and investment strategists (Mark Hart and Raoul Pal), and another with a top performance doc you’ve referenced hundreds of times (Peter Attia, MD).In both, we address dozens of topics."
6 | },
7 | "post2" : {
8 | "img": "img/post2.jpg",
9 | "title": "The Good, The Bad, and The Ugly of CrossFit",
10 | "text": "This post delves into the good, the bad, and the ugly of all things CrossFit. It answers many important questions"
11 | }
12 | }
--------------------------------------------------------------------------------
/week1/hangout/public/css/style.css:
--------------------------------------------------------------------------------
1 |
2 | body {
3 | background: url("/img/bg.jpg") no-repeat scroll center top #1A1A1A;
4 | color: #333;
5 | font-family: Helvetica,Arial,sans-serif;
6 | font-size: 14px;
7 | }
8 |
9 | a {
10 | text-decoration: none;
11 | color: #144E9C
12 | }
13 |
14 | .container {
15 | margin: 20px auto;
16 | padding: 0px;
17 | width: 900px;
18 | }
19 |
20 | /* header */
21 |
22 | header {
23 | height: 70px;
24 | }
25 |
26 | header a {
27 | margin:0px;
28 | margin-left: 20px;
29 | height: 60px;
30 | line-height: 60px;
31 | display: block;
32 | padding: 5px;
33 | }
34 |
35 |
36 | /* section */
37 |
38 |
39 | /* section - content */
40 |
41 | section {
42 | background: url("/img/content-bg.png") repeat-y scroll 0px 0px #FFF;
43 | box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.35);
44 | padding: 20px;
45 | min-height: 100%;
46 | height: 100%;
47 | }
48 |
49 | section hr {
50 | color: rgba(0, 0, 0, 0.13);
51 | }
52 |
53 | section .content {
54 | float: left;
55 | width: 510px;
56 | }
57 |
58 |
59 | /* post */
60 | article a.title {
61 | color: #64AF1B;
62 | font-size: 28px;
63 | line-height: 30px;
64 | font-weight: bold;
65 | letter-spacing: -1px;
66 | }
67 |
68 |
69 | /* section - sidebar */
70 |
71 | .sidebar {
72 | float: right;
73 | width: 300px;
74 | }
75 |
76 | .sidebar .widget-title {
77 | font-weight: bold;
78 | margin: 0px 0px 0.5em;
79 | font-size: 16px;
80 | }
81 |
82 |
83 | .sidebar ul.widget-list {
84 | list-style: none;
85 | background: white;
86 | margin: 0px;
87 | padding: 5px 7px;
88 | border: 2px solid #8CBF1F;
89 | }
90 |
91 | .sidebar ul.li {
92 | font-size: 16px;
93 | }
94 |
95 |
--------------------------------------------------------------------------------
/week1/hangout/public/img/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Frontend-JavaScript-2/280c9d0fc8a1cb30c86101f3928afa3c05090df1/week1/hangout/public/img/bg.jpg
--------------------------------------------------------------------------------
/week1/hangout/public/img/content-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Frontend-JavaScript-2/280c9d0fc8a1cb30c86101f3928afa3c05090df1/week1/hangout/public/img/content-bg.png
--------------------------------------------------------------------------------
/week1/hangout/public/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Frontend-JavaScript-2/280c9d0fc8a1cb30c86101f3928afa3c05090df1/week1/hangout/public/img/logo.png
--------------------------------------------------------------------------------
/week1/hangout/public/img/post1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Frontend-JavaScript-2/280c9d0fc8a1cb30c86101f3928afa3c05090df1/week1/hangout/public/img/post1.png
--------------------------------------------------------------------------------
/week1/hangout/public/img/post2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Frontend-JavaScript-2/280c9d0fc8a1cb30c86101f3928afa3c05090df1/week1/hangout/public/img/post2.jpg
--------------------------------------------------------------------------------
/week1/hangout/server.js:
--------------------------------------------------------------------------------
1 | "use strict"
2 |
3 | // dependancies
4 | var express = require('express')
5 | var fs = require("fs");
6 | var posts = require("./posts.json");
7 |
8 | // create app
9 | var app = express()
10 |
11 |
12 | // configuration and middleware
13 | app.use(express.static('public'));
14 | app.set('view engine', 'jade');
15 |
16 |
17 | // routes
18 | app.get('/', function (req, res) {
19 | res.render('index', {posts: posts});
20 | })
21 |
22 | // listen for files: /post -> /views/post.jade
23 | app.get("/:fileName", function(req, res, next){
24 | if(req.params && req.params.fileName){
25 | var fileName = req.params.fileName.replace(".html","");
26 |
27 | // if jade file exists
28 | if(fs.existsSync(__dirname+"/views/"+fileName+".jade")){
29 | res.render(fileName);
30 | // if post is in posts
31 | } else if (posts[fileName]) {
32 | res.render("post", {post: posts[fileName]});
33 | // else continue
34 | } else {
35 | next();
36 | }
37 |
38 | } else {
39 | next();
40 | }
41 | })
42 |
43 |
44 |
45 | // set up server
46 | var server = app.listen(3000, function () {
47 |
48 | var host = server.address().address
49 | var port = server.address().port
50 |
51 | console.log('Example app listening at http://%s:%s', host, port)
52 |
53 | })
--------------------------------------------------------------------------------
/week1/hangout/views/index.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block content
4 | each post, id in posts
5 | hr
6 | article
7 | a.title(href="/"+id+".html")= post.title
8 | p.text= post.text
9 |
--------------------------------------------------------------------------------
/week1/hangout/views/layout.jade:
--------------------------------------------------------------------------------
1 | html
2 | head
3 | title Jade Blog
4 | link(rel="stylesheet",type="text/css",href="css/style.css")
5 | body
6 | .container
7 | header
8 | a(href="/")
9 | img(src="img/logo.png")
10 | section
11 | .sidebar
12 | p.widget-title Category List
13 | ul.widget-list
14 | li: a(href="/") Category1
15 | li: a(href="/") Category2
16 | .content
17 | block content
--------------------------------------------------------------------------------
/week1/hangout/views/post.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block content
4 | article
5 | a.title= post.title
6 | img(src=post.img)
7 | p.text= post.text
--------------------------------------------------------------------------------
/week2/1-bulls-n-cows/README.md:
--------------------------------------------------------------------------------
1 | # Week 2 : Task 1 : Bulls & Cows
2 |
3 | Let's recreate the game where you have to guess a four-digit number whereby all digits are unique.
4 |
5 | ## Dependencies
6 | - npm
7 | - prompt
8 | - chalk
9 |
10 | ## Premise
11 | - generate a 4 digit number with unique digits
12 | - 4375 is ok
13 | - 5566 not ok
14 | - prompt user for input
15 | - if guess is successful end game
16 | - if not prompt until successful
17 |
18 | ## Example
19 | ```sh
20 | node bulls-n-cows.js
21 | > 4582
22 | 1 bulls 2 cows
23 | > 4735
24 | 2 bulls 2 cows
25 | > 4375
26 | you guessed it!
27 | ```
--------------------------------------------------------------------------------
/week2/2-console-crud/README.md:
--------------------------------------------------------------------------------
1 | # Week 2 : Task 2 : Console CRUD
2 |
3 | ## Premise
4 | Create an app that allows you to create, read, update, delete users in a collection.
5 | - displays a menu with different CRUD actions
6 | - prompts for an action
7 | - each action either displays a result (List users) or prompts for additional information (Add User)
8 | - the data is stored in a global variable users of type collection (dictionary in array)
9 | ```js
10 | var users = [{
11 | id: 1, name: "Pesho", email: "pesho@gmail.com"
12 | },{
13 | id: 2, name: "Gosho", email: "gosho@gmail.com"
14 | }];
15 | ```
16 |
17 | ## Steps
18 | 1. Create interface and prompt
19 | 2. Implement list users and add user
20 | 3. Implement get user, edit user and delete user
21 | 4. Implement search users
22 | 5. Implement save, load to json file
23 | 6. Create function that draws the users table
24 |
25 | ## Dependencies
26 | - npm
27 | - prompt
28 | - chalk
29 |
30 | ## Intitial Interface
31 | ```sh
32 | node console-crud.js
33 |
34 | Pick action:
35 | 1. List users
36 | 2. Add user
37 | > action: _
38 |
39 | # List users
40 | > action: 1
41 | Listing Users:
42 | 1 Ivan ivan@gmail.com
43 | 2 Pesho pesho@gmail.com
44 |
45 | # Add user
46 | > action: 2
47 | Enter user data:
48 | > id: 3
49 | > name: Todor
50 | > email: todor@gmail.com
51 |
52 | ```
53 |
54 | ## Final Interface
55 | ```sh
56 | node console-crud.js
57 |
58 | |=================|
59 | | Pick action |
60 | |=================|
61 | | 1. List users |
62 | | 2. Add user |
63 | | 3. Get user |
64 | | 4. Edit user |
65 | | 5. Delete user |
66 | | 6. Search users |
67 | | 7. Load users |
68 | | 8. Save users |
69 | |=================|
70 | > action: _
71 |
72 | # Search users
73 | > action: 6
74 | Search users:
75 | > keyword: sho
76 | Results: 2
77 | |===============================|
78 | | ID | Name | Email |
79 | |===============================|
80 | | 1 | Pesho | pesho@gmail |
81 | | 2 | Gosho | gosho@gmail |
82 | |===============================|
83 |
84 | #
85 | ```
86 |
--------------------------------------------------------------------------------
/week2/README.md:
--------------------------------------------------------------------------------
1 | # Week 2 Data Types & Operations
2 |
3 | ## Basic Syntax
4 |
5 | ### Variables
6 |
7 | As you know, variables are defined with the `var` keyword.
8 |
9 | ```javascript
10 | var a = 5;
11 | var b = 6;
12 |
13 | console.log(a + b);
14 | ```
15 |
16 | Variables have types but the types are hidden from us since JavaScript is a dynamic language.
17 |
18 | We can have functions, numbers, strings, lists, objects and so on.
19 |
20 | ```javascript
21 | // numbers
22 | var n = 5;
23 |
24 | // strings
25 | var str = "JavaScript is Awesome!";
26 |
27 | // arrays / lists
28 | var list = [1,2,3];
29 |
30 | // functions
31 | var f = function(x) {
32 | return x * x;
33 | };
34 |
35 | // objects - they serve as dictionaries
36 | var courses = {
37 | "FrontendJavaScript" : "https://github.com/HackBulgaria/Frontend-JavaScript-1/",
38 | "Core Java" : "https://github.com/HackBulgaria/Core-Java-1"
39 | };
40 | ```
41 |
42 | ### Function Scope for variables
43 |
44 | In languages like C / C++, Java, C#, etc. - we have block scope visibility for variables.
45 |
46 | That means, if we create a new variable inside a for-loop, it won't be visible outside it:
47 |
48 | ```c
49 | for(int i = 0; i < 10; i++) {
50 | // something with i
51 | }
52 |
53 | // i is not visible here
54 | printf("%d", i);
55 | ```
56 |
57 | __In JavaScript, a variable is visible to the enclosing function!__
58 |
59 | For example:
60 |
61 | ```javascript
62 | var arr = [1,2,3];
63 | for(var i = 0; i < arr.length; i++) {
64 | console.log(arr[i]);
65 | }
66 |
67 | // i is visible
68 | // this will print 3
69 | console.log(i);
70 | ```
71 |
72 | We have something called __variable hoisting__. All `var` statements are moved to the top of the enclosing function, but the value is assigned later, in the original place of the `var` statement
73 |
74 | The code above is translated to:
75 |
76 | ```javascript
77 | var arr = [1,2,3];
78 | var i; // undefined
79 |
80 | for(i = 0; i < arr.length; i++) {
81 | console.log(arr[i]);
82 | }
83 |
84 | // i is visible
85 | // this will print 3
86 | console.log(i);
87 | ```
88 |
89 | ### Iterating arrays
90 |
91 | In JavaScript, we have a standard for-loop:
92 |
93 | ```javascript
94 | var
95 | arr = [1,2,3],
96 | i = 0,
97 | n = arr.length;
98 |
99 | for(i; i < n; i++) {
100 | // do something with arr[i]
101 | }
102 | ```
103 |
104 | But also, we have something far more powerful - a [`forEach` method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) of the array object:
105 |
106 | ```javascript
107 | var arr = [1,2,3];
108 |
109 | arr.forEach(function(value, index, arr) {
110 | // do something with value
111 | console.log(value);
112 | });
113 | ```
114 |
115 | `forEach` takes a function (__we call this callback__) and calls the given function for every item in the array.
116 |
117 | The function is called with 3 arguments:
118 |
119 | * `value` - which is the current item in the array
120 | * `index` - which is the index of the current value in the array
121 | * `array` - the array itself.
122 |
123 | `forEach` is a method. Since everything in JavaScript is a function, we have methods for most of our types.
124 |
125 | ### Iterating objects
126 |
127 | Objects in JavaScript can serve as dictionaries (hash tables) where the key can be string.
128 | __In JavaScript, objects cannot have keys with different types than a string.__
129 |
130 | A fully functioning hash table is coming in the next version of JavaScript.
131 |
132 | To iterate an object, we can use a `for .. in` loop:
133 |
134 | ```javascript
135 | var courses = {
136 | "FrontendJavaScript" : "https://github.com/HackBulgaria/Frontend-JavaScript-1/",
137 | "Core Java" : "https://github.com/HackBulgaria/Core-Java-1"
138 | };
139 |
140 | for(var course in courses) {
141 | console.log("A link for " + course + " can be found here - " + courses[course]);
142 | };
143 | ```
144 |
145 | Later, we will find out that `for .. in` loop goes one step further and returns object properties that we do not want.
146 |
147 | Another way to iterate is to use the `Object.keys()` method, which returns all keys from a given object.
148 |
149 | For example:
150 |
151 | ```javascript
152 | var courses = {
153 | "FrontendJavaScript" : "https://github.com/HackBulgaria/Frontend-JavaScript-1/",
154 | "Core Java" : "https://github.com/HackBulgaria/Core-Java-1"
155 | };
156 |
157 | console.log(Object.keys(courses)); // [ 'FrontendJavaScript', 'Core Java' ]
158 | ```
159 |
160 | Knowing that arrays have `forEach` method, we can do the following:
161 |
162 | ```javascript
163 | var courses = {
164 | "FrontendJavaScript" : "https://github.com/HackBulgaria/Frontend-JavaScript-1/",
165 | "Core Java" : "https://github.com/HackBulgaria/Core-Java-1"
166 | };
167 |
168 | // we can skip the index and array arguments
169 | Object.keys(courses).forEach(function(value) {
170 | console.log("A link for " + value + " can be found here - " + courses[value])
171 | });
172 | ```
173 |
174 | ## Sorting Arrays
175 |
176 | It is a good idea to read the documentation about sort - https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
177 |
178 |
179 | The default sort sorts the items lexicographically.
180 |
181 |
182 | Check this out:
183 |
184 | ```javascript
185 | var scores = [1, 2, 10, 21];
186 | scores.sort(); // [1, 10, 2, 21]
187 | ```
188 |
189 | If you want to sort numbers, you have to give a comparator function:
190 |
191 | ```javascript
192 | var numbers = [4, 2, 5, 1, 3];
193 | numbers.sort(function(a, b) {
194 | return a - b;
195 | });
196 | console.log(numbers);
197 | ```
198 |
199 | ### TODO String Operations, String/Array Conversions
--------------------------------------------------------------------------------
/week2/hangout/crud.js:
--------------------------------------------------------------------------------
1 | "use strict"
2 | // dependencies
3 | var prompt = require('prompt');
4 | var jsonfile = require('jsonfile');
5 | var chalk = require('chalk');
6 |
7 | // file to store users
8 | var usersFile = 'data/users.json';
9 |
10 | // searchable fields
11 | var searchableFields = ["name", "email"];
12 |
13 | // value colors
14 | var valueColors = {
15 | "number" : "blue",
16 | "string" : "yellow"
17 | }
18 |
19 | // collection with users
20 | var users = [
21 | {
22 | id: 123,
23 | name: "Alex",
24 | email: "alex@i4web.biz"
25 | },
26 | {
27 | id: 456,
28 | name: "Gosho",
29 | email: "gosho@test.com"
30 | }
31 | ];
32 |
33 | // collection with commands
34 | var commands = [
35 | {"menu": "list"},
36 | {"menu": "add"},
37 | {"menu": "get"},
38 | {"menu": "update"},
39 | {"menu": "remove"},
40 | {"menu": "load"},
41 | {"menu": "save"},
42 | {"menu": "quit"}
43 | ];
44 |
45 | // util functions
46 | // reset screen
47 | function resetScreen() {
48 | return process.stdout.write('\x1Bc');
49 | }
50 |
51 | function createMold(length){
52 | var mold = "|";
53 | for(var i=1; i<=length; i++){
54 | mold += " ";
55 | }
56 | mold += "|";
57 | return mold;
58 | }
59 |
60 | function buildSeparator(lengths){
61 | var output = "";
62 | lengths.forEach(function(length){
63 | for(var i=1; i<=length+2; i++){
64 | output += "-";
65 | }
66 | })
67 | console.log(output);
68 | }
69 |
70 | function buildColumn(value, length, color){
71 | var mold = createMold(length);
72 | var fmtValue = (color) ? chalk[color](value) : value;
73 | return mold.substr(0,2) + fmtValue + mold.substr(value.length+2);
74 | }
75 |
76 | function buildHeader(item, lengths){
77 | var output = "";
78 | Object.keys(item).forEach(function(key, index){
79 | output += buildColumn(key, lengths[index], "red")
80 | });
81 | console.log(output);
82 | }
83 |
84 | function buildRow(item, lengths){
85 | var output = "";
86 | Object.keys(item).forEach(function(key, index){
87 |
88 | var value = String(item[key]);
89 | var color = valueColors[typeof(item[key])] || false;
90 |
91 | output += buildColumn(value, lengths[index], color)
92 | });
93 | console.log(output);
94 | }
95 |
96 |
97 | function calculateLengths(items){
98 | var maxLengths = [];
99 | items.forEach(function(item, index) {
100 | Object.keys(item).forEach(function(key, keyIndex){
101 | var value = String(item[key]);
102 | if(!maxLengths[keyIndex] || value.length+2 > maxLengths[keyIndex]){
103 | maxLengths[keyIndex] = value.length+2;
104 | }
105 | })
106 | })
107 | return maxLengths;
108 | }
109 |
110 | // build table
111 | function buildTable(items){
112 | var lengths = calculateLengths(items);
113 | buildSeparator(lengths)
114 | buildHeader(items[0], lengths);
115 | buildSeparator(lengths)
116 | items.forEach(function(item, index) {
117 | buildRow(item, lengths);
118 | })
119 | buildSeparator(lengths)
120 | }
121 |
122 | // get functions
123 | // show list
124 | function showList(){
125 | buildTable(users);
126 | }
127 |
128 | function selectIndexById(arr, id){
129 | // var to store matched index
130 | var matchIndex = false;
131 |
132 | // select element by id
133 | arr.forEach(function(item, index) {
134 | if(item.id == id){
135 | matchIndex = index;
136 | }
137 | });
138 |
139 | return matchIndex;
140 | }
141 |
142 | // get by id
143 | function promptGetById(){
144 | prompt.get(['id'], function (err, result) {
145 |
146 | var id = result.id;
147 |
148 | // var to store matched index
149 | var matchIndex = selectIndexById(users, id);
150 |
151 | // display it
152 | if(matchIndex !== false){
153 | buildTable([users[matchIndex]]);
154 | } else {
155 | console.log("Could not find user");
156 | }
157 |
158 | // prompt for next command
159 | promptMenuCommand();
160 |
161 | });
162 | }
163 |
164 | // search
165 | function promptSearch(){
166 | prompt.get(['keyword'], function(err, result){
167 |
168 | var keyword = result.keyword;
169 |
170 | var matchedItems = [];
171 |
172 | users.forEach(function(item, index) {
173 | var hasMatch = false;
174 | searchableFields.forEach(function(field){
175 | if(item[field].match(keyword)){
176 | hasMatch = true;
177 | }
178 | })
179 | if(hasMatch){
180 | matchedItems.push(item);
181 | }
182 | });
183 |
184 | if(matchedItems.length > 0)
185 | buildTable(matchedItems);
186 | else
187 | console.log("Could not find matches!");
188 |
189 | promptMenuCommand();
190 |
191 | })
192 | }
193 |
194 | // update by id
195 | function promptUpdateById(){
196 | prompt.get(['id','field','value'], function (err, result) {
197 |
198 | if(!result.id || !result.field || result.value === undefined){
199 | console.log("id, field, value are required");
200 | promptUpdateById();
201 | return false;
202 | }
203 |
204 | var id = result.id;
205 | var field = result.field;
206 | var value = result.value;
207 |
208 | // var to store matched index
209 | var matchIndex = selectIndexById(users, id);
210 |
211 | // update entry
212 | if(matchIndex !== false){
213 | var oldValue = users[matchIndex][field];
214 |
215 | users[matchIndex][field] = value;
216 |
217 | console.log("Successfully changed the value of "+field
218 | +" from "+oldValue+" to "+value+" for id "+id);
219 |
220 | console.log(users[matchIndex]);
221 |
222 | } else {
223 | console.log("Could not find user");
224 | }
225 |
226 | // prompt for next command
227 | promptMenuCommand();
228 |
229 | });
230 | }
231 |
232 | // remove
233 | function promptRemoveById(){
234 | prompt.get(['id'], function (err, result) {
235 |
236 | var id = result.id;
237 |
238 | // var to store matched index
239 | var matchIndex = selectIndexById(users, id);
240 |
241 | // remove it
242 | if(matchIndex !== false){
243 | users.splice(matchIndex, 1);
244 | console.log("Successfully removed user for id "+id);
245 |
246 | // show updated list
247 | showList();
248 |
249 | } else {
250 | console.log("Could not find user");
251 | }
252 |
253 | // prompt for next command
254 | promptMenuCommand();
255 |
256 | });
257 | }
258 |
259 | // add item
260 | function promptAddItem(){
261 |
262 | //
263 | console.log("Enter item to add:");
264 |
265 | prompt.get(['id','name','email'], function (err, result) {
266 |
267 | users.push(result);
268 | console.log("Successfully added user!");
269 |
270 | // show updated list
271 | showList();
272 |
273 | // prompt for next command
274 | promptMenuCommand();
275 |
276 | });
277 | }
278 |
279 | function loadFromFile(){
280 | users = jsonfile.readFileSync(usersFile);
281 |
282 | }
283 |
284 | function saveToFile(){
285 | jsonfile.writeFileSync(usersFile, users);
286 | }
287 |
288 |
289 | // quit
290 | function quit(){
291 | console.log("See you soon!");
292 | }
293 |
294 | // show menu
295 | function showMenu(){
296 | buildTable(commands);
297 | }
298 |
299 | // prompt menu command
300 | function promptMenuCommand(){
301 |
302 | console.log("")
303 | showMenu();
304 |
305 | prompt.get(['command'], function (err, result) {
306 |
307 | resetScreen();
308 |
309 | if(result === undefined){
310 | return quit();
311 | }
312 |
313 | var command = result.command;
314 |
315 | switch(command){
316 | case "list":
317 | showList();
318 | promptMenuCommand();
319 | break;
320 | case "add":
321 | promptAddItem();
322 | break;
323 | case "get":
324 | promptGetById();
325 | break;
326 | case "search":
327 | promptSearch();
328 | break;
329 | case "update":
330 | promptUpdateById();
331 | break;
332 | case "remove":
333 | promptRemoveById();
334 | break;
335 | case "load":
336 | loadFromFile();
337 | promptMenuCommand();
338 | break;
339 | case "save":
340 | saveToFile();
341 | promptMenuCommand();
342 | break;
343 | case "quit":
344 | quit();
345 | break;
346 | default:
347 | console.log("Unrecognized command!");
348 | promptMenuCommand();
349 | break;
350 | }
351 |
352 | });
353 |
354 | }
355 |
356 |
357 | // code
358 | prompt.start();
359 |
360 | promptMenuCommand();
361 |
--------------------------------------------------------------------------------
/week2/hangout/data/users.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": 123,
4 | "name": "Alex",
5 | "email": "alex@i4web.biz"
6 | },
7 | {
8 | "id": "567",
9 | "name": "Tosho",
10 | "email": "tosho@test.com"
11 | },
12 | {
13 | "id": "456",
14 | "name": "Gosho",
15 | "email": "iam@back.com"
16 | }
17 | ]
18 |
--------------------------------------------------------------------------------
/week2/hangout/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hangout2crud",
3 | "version": "0.0.0",
4 | "description": "crud operations in console",
5 | "main": "crud.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [
10 | "crud",
11 | "console",
12 | "prompt"
13 | ],
14 | "author": "",
15 | "license": "ISC",
16 | "dependencies": {
17 | "prompt": "~0.2.14",
18 | "jsonfile": "~2.0.0",
19 | "chalk": "~1.0.0"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/week3/1-A-Panda/README.md:
--------------------------------------------------------------------------------
1 | # We will model a Panda
2 |
3 | In a file called `panda.js`, create a `Panda` object, which takes two arguments:
4 |
5 | * The `name` of the panda
6 | * The `sex` of the panda - can be `"male"` or `"female"`
7 | * Each `Panda` should have a `weight` property, which always starts at `20`
8 |
9 | Our `Panda` should have the following methods, attached to the `Panda`'s prototype:
10 |
11 | * `toString()` - returns a string representation of our panda. See the examples below for how it should look like
12 | * `isMale()` and `isFemale()` - returns true/false based on the `sex` of the Panda
13 | * `eat(bamboo)` where `bamboo` is an integer - how much kilograms does tha panda eat. When a panda eats `x` kg of `bamboo`, it gains `x/2` weight. If the weight of the panda goes above 80, the name of the panda should be prepended with `"Lazy Panda"`. See examples below.
14 | * `mate(anotherPanda)` - we will have a reproduction mechanism for our pandas. More on mating below.
15 |
16 | ## Basic examples for our Panda
17 |
18 | ```javascript
19 | var ivo = new Panda("Ivo", "male");
20 |
21 | ivo.weight == 20; // true
22 | ivo.isMale() == true; // true
23 | ivo.isFemale() == false; // true
24 | ivo.toString() == "Ivo is a male panda which weights 20 kg" // true
25 |
26 | ivo.eat(80);
27 | ivo.weight == 60; // true
28 |
29 | ivo.eat(80);
30 | ivo.weight == 100; // true
31 |
32 | ivo.name == "Lazy Panda Ivo" // true
33 | ```
34 |
35 | ## Examples for Panda Mating
36 |
37 | When we call the `mate(anotherPanda)` method, we should get a new panda with the following criteria:
38 |
39 | * The sex of the new panda should be a 50% chance between male and female.
40 | * **If the panda is male**, the name of the baby panda should be: `"{Name-of-Father} {Name-of-Mother}"`
41 | * Otherwise, it should be the other way around - `"{Name-of-Mother} {Name-of-Father}"`
42 | * If we try to mate male with male or female with female panda, the method should throw an error `CannotMatePandas`. Research how you can throw an error from JavaScript code :)
43 |
44 | Example:
45 |
46 |
47 | ```javascript
48 | var ivan = new Panda("Ivan", "male");
49 | var ivanka = new Panda("Ivanka", "female");
50 |
51 | var baby = ivan.mate(ivanka);
52 |
53 | // we can have one of the two options:
54 |
55 | baby.name == "Ivan Ivanka" && baby.sex == "male"
56 | baby.name == "Ivanka Ivan" && baby.sex == "female"
57 | ```
58 |
--------------------------------------------------------------------------------
/week3/1-A-Panda/panda.js:
--------------------------------------------------------------------------------
1 | function getRandomInt(min, max) {
2 | return Math.floor(Math.random() * (max - min)) + min;
3 | }
4 |
5 | function Panda(name, sex) {
6 | this.name = name;
7 |
8 | if(["male", "female"].indexOf(sex) === -1) {
9 | sex = "female";
10 | }
11 |
12 | this.sex = sex;
13 | this.weight = 20;
14 | this.isLazy = false;
15 | }
16 |
17 | Panda.prototype.isMale = function() {
18 | return this.sex === "male";
19 | }
20 |
21 | Panda.prototype.isFemale = function() {
22 | return this.sex === "female";
23 | }
24 |
25 | Panda.prototype.toString = function() {
26 | return [this.name, "is a", this.sex, "panda which weighs", this.weight, "kg"].join(" ");
27 | }
28 |
29 |
30 | Panda.prototype.eat = function(bamboo) {
31 | this.weight += bamboo / 2;
32 |
33 | if(this.weight >= 80 && !this.isLazy) {
34 | this.name = "Lazy Panda " + this.name;
35 | this.isLazy = true;
36 | }
37 | }
38 |
39 | Panda.prototype.mate = function(anotherPanda) {
40 | var fatherName = "";
41 | var motherName = "";
42 |
43 | if(this.isMale() && anotherPanda.isFemale()) {
44 | fatherName = this.name;
45 | motherName = anotherPanda.name
46 | } else if(this.isFemale() && anotherPanda.isMale()) {
47 | fatherName = anotherPanda.name;
48 | motherName = this.name;
49 | } else {
50 | throw {
51 | "name": "PandasCannotMate",
52 | "message": "They love each other but sadly cannot mate ;("
53 | };
54 | }
55 |
56 | var babySex = ["female", "male"][getRandomInt(0, 2)];
57 |
58 | var babyName = {
59 | "female": motherName + " " + fatherName,
60 | "male": fatherName + " " + motherName
61 | }[babySex];
62 |
63 | return new Panda(babyName, babySex);
64 | }
65 |
66 |
--------------------------------------------------------------------------------
/week3/2-Point/README.md:
--------------------------------------------------------------------------------
1 | # Point3D
2 |
3 | We are going to model a simple 3D point, holding `x`, `y` and `z`.
4 |
5 |
6 | With a little twist, we will make one mutable and one immutable version of that object.
7 |
8 | ## Mutable point
9 |
10 | We want to have the following things:
11 |
12 | * All the three components - `x`, `y` and `z` should be private with only getters - `getX()`, `getY()`, `getZ()`.
13 | * Our point should have a method, called `move(dx, dy, dz)`, which mutates our point in the following way: `x = x + dx`, `y = y + dy`, `z = z + dz`.
14 | * We want the `toString()` method to return a string looking like `({x}, {y}, {z})`
15 |
16 | For example:
17 |
18 | ```javascript
19 | var p1 = MutablePoint3d(0, 0, 0);
20 |
21 | p1.move(0, 0, -1);
22 |
23 | p1.getX() == 0; // true
24 | p1.getY() == 0; // true
25 | p1.getZ() == -1; // true
26 |
27 | p1.toString() == "(0, 0, -1)" // true
28 | ```
29 |
30 | ## Immutable Point
31 |
32 | The twist. We want to create a `ImmutablePoint3d` object, which behaves the same as `MutablePoint3d`.
33 |
34 | The only difference is that the `move(dx, dy, dz)` method should return a new `ImmutablePoint3d`, instead of mutating the instance.
35 |
36 | For example:
37 |
38 | ```javascript
39 | var p2 = new ImmutablePoint3d(0, 0, 0);
40 |
41 | var result = p2.move(0, 0, -1);
42 |
43 | p2.getX() == 0; // true
44 | p2.getY() == 0; // true
45 | p2.getZ() == 0; // true
46 |
47 |
48 | result.getZ() == -1; // true
49 |
50 | p2.toString() == "(0, 0, 0)" // true
51 | result.toString() == "(0, 0, -1)" // true
52 | ```
53 |
--------------------------------------------------------------------------------
/week3/2-Point/points.js:
--------------------------------------------------------------------------------
1 | function MutablePoint3d(x, y, z) {
2 | this.getX = function() {
3 | return x;
4 | }
5 |
6 | this.getY = function() {
7 | return y;
8 | }
9 |
10 | this.getZ = function() {
11 | return z;
12 | }
13 |
14 | this.move = function(dx, dy, dz) {
15 | x += dx;
16 | y += dy;
17 | z += dz;
18 | }
19 | }
20 |
21 | MutablePoint3d.prototype.toString = function() {
22 | return "(" + [this.getX(), this.getY(), this.getZ()].join(", ") + ")";
23 | }
24 |
25 |
26 | function ImmutablePoint3d(x, y, z) {
27 | this.getX = function() {
28 | return x;
29 | }
30 |
31 | this.getY = function() {
32 | return y;
33 | }
34 |
35 | this.getZ = function() {
36 | return z;
37 | }
38 | }
39 |
40 | ImmutablePoint3d.prototype.move = function(dx, dy, dz) {
41 | return new ImmutablePoint3d(this.getX() + dx, this.getY() + dy, this.getZ() + dz);
42 | }
43 |
44 | ImmutablePoint3d.prototype.toString = function() {
45 | return "(" + [this.getX(), this.getY(), this.getZ()].join(", ") + ")";
46 | }
47 |
48 | var p2 = new ImmutablePoint3d(0, 0, 0);
49 | var result = p2.move(0, 0, -1);
50 |
51 | console.log(p2.toString());
52 | console.log(result.toString());
53 |
54 |
--------------------------------------------------------------------------------
/week3/3-Prototypes/README.md:
--------------------------------------------------------------------------------
1 | # Augmeting existing object's prototypes
2 |
3 | We are going to play with the prototypes of the existing `String` and `Array` prototypes.
4 |
5 | In a file called `prototypes.js`, add the following methods to:
6 |
7 | ## String
8 |
9 | Extend the `String` prototype by adding the following methods:
10 |
11 | ## capitalize()
12 |
13 | Make the first letter of the string uppercase.
14 |
15 | ```javascript
16 | "javaScript".capitalize() == "JavaScript"
17 | ```
18 |
19 | ## isBlank()
20 |
21 | Returns `true` if the string is an empty string or containing only empty strings.
22 |
23 | ```javascript
24 | " ".isBlank() == true
25 | " ".isBlank() == true
26 | " asda ".isBlank() == false
27 | ```
28 |
29 | ## words()
30 |
31 | Splits a string into array of words.
32 |
33 | ```javascript
34 | var words = "This is a very clever sentence!".words()
35 | console.log(words)
36 | // ["This", "is", "a", "very", "clever", "sentence!"]
37 | ```
38 |
39 | ## format()
40 |
41 | The missing format function in JavaScript. Formats a string with the specified arguments.
42 |
43 | The placeholders should be `"{}"` or named `"{name}"` curly braces.
44 |
45 | Here are some examples:
46 |
47 | ```javascript
48 | var name = "What?";
49 | var result = "Hi, my name is {}. Nice to meet you {}".format(name, "Good sir!");
50 | console.log(result);
51 | // "Hi, my name is What?. Nice to meet you Good sir!"
52 |
53 | ```
54 |
55 | Here is an example with named curly braces:
56 |
57 | ```javascript
58 | var replaces = { "name": "Ivan", "language": "Bulgarian" };
59 | var result = "Hello there {name}! Do you speak {language}?".format(replaces);
60 | console.log(result);
61 | // "Hello there Ivan! Do you speak Bulgarian?"
62 | ```
63 |
64 | ## Array
65 |
66 | ### head, tail and last
67 |
68 | * `head` returns the first element of the array.
69 | * `tail` returns the array without the first element.
70 | * `last` returns the last element of the array.
71 |
72 | ```javascript
73 | var a = [1, 2, 3];
74 |
75 | a.head() == 1;
76 | a.tail() == [2, 3]
77 | a.last() == [3]
78 |
79 | # We do not change the array
80 | a == [1, 2, 3];
81 | ```
82 |
83 | ## range
84 |
85 | Range is a method of two arguments - `start` and `end` and returns a new array of all integers between `[start, end]`
86 |
87 | ```javascript
88 | var result = [].range(1, 10);
89 | result == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
90 | ```
91 | ## sum
92 |
93 | Self explanatory. Returns the sum of all numbers in the array.
94 |
95 | ```javascript
96 | [1, 2, 3].sum() == 6;
97 | ```
98 |
99 | ## product
100 |
101 | Like sum, but returns the product of all numbers in the array
102 |
103 | ```javascript
104 | [1, 2, 3].product() == 6;
105 | ```
106 | ## compact
107 |
108 | Returns a new version of the array where all **falsy** values have been removed.
109 |
110 | Here is a list of faulty values in JavaScript:
111 |
112 | * `false`
113 | * `0` (zero)
114 | * `""` (empty string)
115 | * `null`
116 | * `undefined`
117 | * `NaN` (a special Number value meaning Not-a-Number!)
118 |
119 | Example:
120 |
121 | ```javascript
122 | [false, true, 0, "", null, 5, undefined, NaN, "JavaScript"].compact() == [true, 5, "JavaScript"]
123 | ```
124 |
125 | ## take and drop
126 |
127 | * `take` takes one argument - an integer value `n`, and returns the first `n` elements from the array
128 | * `drop` takes one argument - an integer value `n` and returns a new array, where the first `n` elements are removed
129 |
130 | If something overflows, either return the entire array or an empty one.
131 |
132 | Examples:
133 |
134 | ```javascript
135 | var a = [].range(1, 10);
136 | a.take(3) == [1, 2, 3];
137 | a.drop(5) == [6, 7, 8, 9, 10];
138 | a.take(100) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
139 | a.drop(100) == [];
140 | ```
141 |
142 | ## dedup
143 |
144 | Returns a new array where all duplicate elements are removed, leaving only one copy of each.
145 |
146 | **Compare elements with `===`**
147 |
148 | ```javascript
149 | [1, 1, 1, 1, 1].dedup() == [1];
150 | ```
151 |
152 | ## sample
153 |
154 | Returns a random sample from the array.
155 |
156 | Example:
157 |
158 | ```javascript
159 | [1, 2, 3].sample() // can be 1
160 | [1, 2, 3].sample() // can be 3
161 | [1, 2, 3].sample() // can be 2
162 | ```
163 |
164 |
--------------------------------------------------------------------------------
/week3/3-Prototypes/prototypes.js:
--------------------------------------------------------------------------------
1 | // variadic arguments
2 | String.prototype.format = function(dict) {
3 | var result = this;
4 |
5 | if(typeof(dict) === "object") {
6 | Object.keys(dict).forEach(function(key) {
7 | result = result.replace("{" + key + "}", dict[key]);
8 | });
9 | return result;
10 | }
11 |
12 | var args = [];
13 | var n = arguments.length;
14 | var i = 0;
15 |
16 | for(i; i < n; i+=1) {
17 | args.push(arguments[i]);
18 | }
19 |
20 | var result = this;
21 |
22 | args.forEach(function(arg) {
23 | result = result.replace("{}", arg);
24 | });
25 |
26 | return result;
27 | }
28 |
29 | console.log("{} {} {}".format("one", "two", "three"));
30 | console.log("Hello {name}, I am {friend}".format({
31 | "name": "Ivo",
32 | "friend": "Rado"
33 | }));
34 |
35 |
--------------------------------------------------------------------------------
/week3/4-Queue/README.md:
--------------------------------------------------------------------------------
1 | # A classic queue
2 |
3 | In a file called `queue.js` implement the following:
4 |
5 | Using a literal object - `{}` - create an object, that behaves like a queue.
6 |
7 | For example, if we store our queue like this:
8 |
9 | ```javascript
10 | var queue = {
11 | // implementation
12 | }
13 | ```
14 |
15 | It should have the following methods:
16 |
17 | * `queue.push(item)` - pushes the item to the queue
18 | * `queue.pop()` - returns the item on top of the queue
19 | * `queue.isEmpty()` - returns true if the queue is empty
20 |
21 | Here is an example:
22 |
23 | ```javascript
24 | function bfs(graph, start, end) {
25 | prev = {};
26 | visited = [start];
27 | queue.push(start);
28 |
29 | while(!queue.isEmpty()) {
30 | var node = queue.pop();
31 |
32 | if(node.is(end)) {
33 | // do something
34 | return
35 | }
36 |
37 | graph.getNeighbours(node).forEach(function(n) {
38 | if(visited.indexOf(n) !== -1) {
39 | visited.push(n);
40 | prev[n] = node;
41 |
42 | queue.push(n);
43 | }
44 | });
45 |
46 | }
47 | }
48 | ```
49 |
--------------------------------------------------------------------------------
/week3/4-Queue/queue.js:
--------------------------------------------------------------------------------
1 | var queue = (function() {
2 | var data = [];
3 |
4 | function pop() {
5 | var head = data.shift();
6 | return head;
7 | }
8 |
9 | function push(item) {
10 | data.push(item);
11 | return item;
12 | }
13 |
14 | function isEmpty() {
15 | return data.length == 0;
16 | }
17 |
18 | return {
19 | "pop": pop,
20 | "push": push,
21 | "isEmpty": isEmpty
22 | }
23 | })();
24 |
25 |
--------------------------------------------------------------------------------
/week3/5-Event-Bus/README.md:
--------------------------------------------------------------------------------
1 | ## An Event bus
2 |
3 | Create a single object, that behaves like an event bus! We can attach custom events with callbacks to them and also trigger those events.
4 |
5 | The object should have the following __public__ methods:
6 |
7 | * `.on(eventName, callback)` - adds the given `callback` for the given `eventName`
8 | * `.remove(eventName)` - removes all callbacks for the given `eventName`
9 | * `.trigger(eventName)` - fires the given `eventName` which calls all callbacks for that event
10 |
11 | __Everything else, regarding the implementation of the event bus should be private!__
12 |
13 | Here is an example usage:
14 |
15 | ```javascript
16 | var bus = { // implementation }
17 |
18 | bus.on("PANIC_EVENT", function() {
19 | console.log("PANIC_EVENT HAPPENED!")
20 | });
21 |
22 | bus.on("PANIC_EVENT", function() {
23 | console.log("PANIC_EVENT HAPPENED AGAIN!");
24 | });
25 | ```
26 |
27 | Now, if we call:
28 |
29 | ```javascript
30 | bus.trigger("PANIC_EVENT");
31 | ```
32 |
33 | This will log:
34 |
35 | ```
36 | "PANIC_EVENT HAPPENED!"
37 | "PANIC_EVENT HAPPENED AGAIN!"
38 | ```
39 |
--------------------------------------------------------------------------------
/week3/5-Event-Bus/bus.js:
--------------------------------------------------------------------------------
1 | // IIFE - Immediately Invoked Function Expression
2 | // design pattern in JavaScript
3 | var bus = (function() {
4 | var eventTable = {};
5 |
6 | function trigger(event) {
7 | var events = eventTable[event] || [];
8 |
9 | events.forEach(function(callback) {
10 | callback();
11 | });
12 | }
13 |
14 | function remove(event) {
15 | delete eventTable[event];
16 | }
17 |
18 | function on(event, callback) {
19 | if(typeof(eventTable[event]) === "undefined") {
20 | eventTable[event] = [];
21 | }
22 |
23 | eventTable[event].push(callback);
24 | }
25 |
26 | return {
27 | "trigger": trigger,
28 | "on": on,
29 | "remove": remove
30 | }
31 | })();
32 |
33 |
--------------------------------------------------------------------------------
/week3/6-HTML-Generator/README.md:
--------------------------------------------------------------------------------
1 | # A set of classes that generate HTML
2 |
3 | We are going to implement a set of different classes that takes data and renders as HTML.
4 |
5 | We are going to combine that into a `Page` class, which will render the entire HTML.
6 |
7 | * Each class is going to have a common interface of the `render()` method, which returns a string, representing the rendered HTML.
8 | * Some of the classes are going to be containers, having an `addChild()` method - to add different components as their children.
9 | * **Each level of nesting should be indented with 2 spaces!**
10 |
11 | ## The Paragraph class
12 |
13 | Here is an example usage:
14 |
15 | ```javascript
16 | var p = new Paragraph("Some text here");
17 | p.render() == "
Some text here
";
18 | ```
19 |
20 | ## The Div class
21 |
22 | `Div` will be a container and for the case, our only container.
23 |
24 | **The `addChild` method should return `this` in order to have chaining. Check the page example for more info.**
25 |
26 | Here is an example usage:
27 |
28 | ```javascript
29 | var div = new Div();
30 | div.addChild(new Paragraph("I am inside that div"));
31 | div.addChild(new Paragraph("I am inside that div too"));
32 |
33 | div.render() ==
34 | "
35 |
I am inside that div
36 |
I am inside that div too
37 |
"
38 | ```
39 |
40 | If we render a div with no children:
41 |
42 | ```javascript
43 | var div = new Div();
44 | div.render() == "";
45 | ```
46 |
47 | We can also nest divs:
48 |
49 | ```javascript
50 | var div1 = new Div();
51 | var div2 = new Div();
52 |
53 | div1.addChild(div1);
54 |
55 | div1.render() ==
56 | "
57 |
58 |
59 |
60 | "
61 | ```
62 |
63 | ## The Table class
64 |
65 | Our table class can accept a dictionary, with the following format:
66 |
67 | ```javascript
68 | {
69 | "column_name1": [column values, ...],
70 | "column_name2": [colun values, ...]
71 | }
72 | ```
73 |
74 | Also, our table class can accept a list, with the following format:
75 |
76 | **Consider the first element the row with the name of the columns.**
77 |
78 | ```javascript
79 | [ ["Column1", "Column2"],
80 | ["data1, "data2"], ...
81 | ]
82 | ```
83 |
84 | Here are examples:
85 |
86 | ```javascript
87 | var tableData = {
88 | "name": ["Ivo", "Rado", "Maria"],
89 | "age": [22, 24, 22]
90 | }
91 |
92 |
93 | var table = new Table(tableData);
94 |
95 | table.render() ==
96 | "
97 |
98 |
99 |
100 |
name
101 |
age
102 |
103 |
104 |
105 |
106 |
Ivo
107 |
22
108 |
109 |
110 |
Rado
111 |
24
112 |
113 |
114 |
Maria
115 |
22
116 |
117 |
118 |
119 | "
120 | ```
121 |
122 | The same goes with list data:
123 |
124 | ```javascript
125 | var tableData = [ ["name", "age"], ["Ivo", 22], ["Rado", 24], ["Maria", 22] ];
126 |
127 | var table = new Table(tableData);
128 | table.render() ==
129 | "
130 |
131 |
132 |
133 |
name
134 |
age
135 |
136 |
137 |
138 |
139 |
Ivo
140 |
22
141 |
142 |
143 |
Rado
144 |
24
145 |
146 |
147 |
Maria
148 |
22
149 |
150 |
151 |
152 | "
153 | ```
154 |
155 | ## Rendering everything in a page
156 |
157 | We should have a `Page` class which takes a root element and reners everything from it.
158 |
159 | Here is an example:
160 |
161 | ```javascript
162 | var p = new Paragraph("Rolling in the deep");
163 | var div = new Div();
164 |
165 | div
166 | .addChild(new Div())
167 | .addChild(new Div())
168 | .addChild(p);
169 |
170 | var page = new Page(div);
171 |
172 | page.render() ==
173 | "
174 |
175 |
176 |
177 |
Rolling in the deep
178 |
179 | "
180 |
181 | ```
182 |
--------------------------------------------------------------------------------
/week3/README.md:
--------------------------------------------------------------------------------
1 | # Basic JavaScript OOP & Working with the DOM
2 |
3 | Here are two very good guides for starting with JavaScript OOP from the Mozilla Dev Network:
4 |
5 | * [Introduction to Object Oriented JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript)
6 | * [Details of the Object Model in JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model)
7 | * [What is that object prototype in JavaScript?](http://stackoverflow.com/questions/572897/how-does-javascript-prototype-work)
8 | * [The chapter from Eloquent JavaScript](http://eloquentjavascript.net/06_object.html)
9 | * There are good slides from John Resig for "advanced JavaScript" - http://ejohn.org/apps/learn - you can check it!
10 | * [Example for creating object with JavaScript literal](materials/person.js)
11 | * [Examples for Function.prototype.call and Function.prototype.apply](materials/call_apply.js)
12 | * [Examples for closures](materials/closure.js)
13 |
--------------------------------------------------------------------------------
/week3/materials/call_apply.js:
--------------------------------------------------------------------------------
1 | function Person(name) {
2 | this.name = name;
3 | }
4 |
5 | Person.prototype.toString = function() {
6 | return "Hello, I am " + this.name;
7 | }
8 | // 1. Да открадна this
9 | // 2. Да открадна prototype
10 | function Student(name, fn) {
11 | Person.call(this, name);
12 | this.fn = fn;
13 | }
14 |
15 | Student.prototype = Object.create(Person.prototype);
16 | Student.prototype.toString = function() {
17 | return Person.prototype.toString.call(this) + " " + this.fn;
18 | }
19 |
20 | var p = new Person("Rado");
21 | var s = new Student("Ivo", "800000");
22 |
23 | console.log(p.toString());
24 | console.log(s.toString());
25 |
26 |
--------------------------------------------------------------------------------
/week3/materials/closure.js:
--------------------------------------------------------------------------------
1 | function makeCounter() {
2 | return (function() {
3 | var count = 0;
4 | return function() {
5 | count += 1;
6 | return count;
7 | }
8 | }());
9 | }
10 |
11 | var c1 = makeCounter();
12 | console.log(c1());
13 | console.log(c1());
14 |
15 | console.log("Swiching counters");
16 |
17 | var c2 = makeCounter();
18 | console.log(c2());
19 | console.log(c2());
20 |
21 | // private for object literals
22 | // with closure
23 | var person =
24 | (function() {
25 | var name = "Ivo";
26 |
27 | return {
28 | "getName": function() {
29 | return name;
30 | }
31 | }
32 | }());
33 |
34 | console.log(person.getName());
35 |
--------------------------------------------------------------------------------
/week3/materials/person.js:
--------------------------------------------------------------------------------
1 | var person = {
2 | "name": "Ivo",
3 | "age": 24
4 | };
5 |
6 |
7 | // "closure" -> "обвивка"
8 |
9 | function createPerson(name, age) {
10 | return {
11 | "getName": function() {
12 | return name;
13 | },
14 | "getAge": function() {
15 | return age;
16 | }
17 | }
18 |
19 | }
20 |
21 | var ivo = createPerson("ivo", 22);
22 | ivo.name = ivo.getName();
23 | ivo.name = "Rado";
24 | console.log(ivo);
25 |
26 |
--------------------------------------------------------------------------------
/week4/1-Keeping-up-the-Score/README.md:
--------------------------------------------------------------------------------
1 | # Keeping up the Score
2 |
3 | We are going to introduce ourselves to the DOM by creating elements and attaching events to them.
4 |
5 | Check the [page.html](page.html) file - it is a blank HTML with one `div` container.
6 |
7 | We are going to need a `page.js` file to control our code.
8 |
9 | ## Two Buttons
10 |
11 | We are going to need two buttons:
12 |
13 | * One for `TeamA`
14 | * One for `TeamB`
15 |
16 | Also, we are going to need to paragraphs of text, which will hold the score.
17 |
18 | When we click `TeamA`'s button, we are going to increase their score. The same thing goes for `TeamB`.
19 |
20 | See this mockup:
21 |
22 | 
23 |
--------------------------------------------------------------------------------
/week4/1-Keeping-up-the-Score/mockup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Frontend-JavaScript-2/280c9d0fc8a1cb30c86101f3928afa3c05090df1/week4/1-Keeping-up-the-Score/mockup.png
--------------------------------------------------------------------------------
/week4/1-Keeping-up-the-Score/page.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/week4/1-Keeping-up-the-Score/page.js:
--------------------------------------------------------------------------------
1 | function text(content) {
2 | return document.createTextNode(content);
3 | }
4 |
5 | function hasKey(dict, key) {
6 | return typeof dict[key] !== "undefined";
7 | }
8 |
9 | Element.createElement = function(tagName, content, attributes) {
10 | attributes = attributes || {};
11 |
12 | var obj = document.createElement(tagName);
13 | obj.appendChild(text(content));
14 |
15 | if(hasKey(attributes, "id")) {
16 | obj.id = attributes["id"];
17 | }
18 |
19 | return new Element(obj);
20 | };
21 |
22 | function Element(domElement) {
23 | this.domElement = domElement;
24 | }
25 |
26 | Element.prototype.appendChild = function(child) {
27 | if(child instanceof Element) {
28 | child = child.domElement;
29 | }
30 |
31 | this.domElement.appendChild(child);
32 | };
33 |
34 | Element.prototype.on = function(type, callback) {
35 | this.domElement.addEventListener(type, callback);
36 | };
37 |
38 | Element.prototype.attr = function(attributeName, attributeValue) {
39 | var aliases = {
40 | "class": "className"
41 | };
42 |
43 | if(hasKey(aliases, attributeName)) {
44 | attributeName = aliases[attributeName];
45 | }
46 |
47 | if(hasKey(this.domElement, attributeName)) {
48 | if (typeof attributeValue === "undefined") {
49 | return this.domElement[attributeName];
50 | } else {
51 | this.domElement[attributeName] = attributeValue;
52 | return attributeValue;
53 | }
54 | }
55 | };
56 |
57 |
58 | function print(obj) {
59 | console.log(obj);
60 | }
61 |
62 | document.addEventListener("DOMContentLoaded", function(event) {
63 | function buttonClickHandler(event) {
64 | var id = event.target.id;
65 | scores[id] += 1;
66 |
67 | document.getElementById(id + "Score").firstChild.data = scores[id];
68 | }
69 |
70 | var scores = {
71 | "teamA": 0,
72 | "teamB": 0
73 | },
74 | container = document.getElementById("container");
75 |
76 | var teamAButton = Element.createElement("button", "Team A", {
77 | id: "teamA"
78 | });
79 |
80 | var teamAScoreText = "Team A Score: ";
81 | var teamAHeading = Element.createElement("h1", teamAScoreText);
82 |
83 | var teamASpan = Element.createElement("span", "0", {
84 | id: "teamAScore"
85 | });
86 |
87 | teamAHeading.appendChild(teamASpan);
88 |
89 | teamAButton.on("click", function(event) {
90 | console.log("Does it work?");
91 | console.log(event);
92 | });
93 |
94 | // var teamBButton = document.createElement("button");
95 | // teamBButton.id = "teamB";
96 | // teamBButton.appendChild(text("Team B"));
97 |
98 | // var teamBScoreText = "Team B Score: ";
99 | // var teamBHeading = document.createElement("h1");
100 | // var teamBSpan = document.createElement("span");
101 | // teamBSpan.appendChild(text("0"));
102 | // teamBSpan.id = "teamBScore";
103 |
104 | // teamBHeading.appendChild(text(teamBScoreText));
105 | // teamBHeading.appendChild(teamBSpan);
106 |
107 | // teamAButton.onclick = buttonClickHandler;
108 | // teamBButton.onclick = buttonClickHandler;
109 |
110 | container.appendChild(teamAHeading.domElement);
111 | container.appendChild(teamAButton.domElement);
112 |
113 | // container.appendChild(teamBHeading);
114 | // container.appendChild(teamBButton);
115 | });
116 |
--------------------------------------------------------------------------------
/week4/2-DOM-Todo/README.md:
--------------------------------------------------------------------------------
1 | # Really dead simple Todo list with DOM
2 |
3 | Every JavaScripter should implement at least one todo list in his life!
4 |
5 | We are going to honor this, right now.
6 |
7 | Again, use the pure DOM + JavaScript API, but this time, write whatever HTML and CSS you like. Think of how you can achieve that.
8 |
9 | We want to have the following feature:
10 |
11 | **A userinput, where we enter text, click the `Add` button and the task goes to a list of tasks.**
12 |
13 | That's it.
14 |
15 | Here is a mockup:
16 |
17 | 
18 |
19 | ## How to take a value from an input
20 |
21 | Consider the following HTML:
22 |
23 | ```html
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | ```
33 |
34 | And the following JavaScript:
35 |
36 | ```javascript
37 | window.onload = function() {
38 | var button = document.getElementById("add-task-button");
39 | button.onclick = function(event) {
40 | var input = document.getElementById("task-input");
41 |
42 | console.log(input.value);
43 | };
44 | };
45 | ```
46 |
47 | They are called `example.html` and `example.js`. Run them and check the console, by typing and clickin on the button.
48 |
--------------------------------------------------------------------------------
/week4/2-DOM-Todo/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/week4/2-DOM-Todo/example.js:
--------------------------------------------------------------------------------
1 | window.onload = function() {
2 | var button = document.getElementById("add-task-button");
3 | button.onclick = function(event) {
4 | var input = document.getElementById("task-input");
5 |
6 | console.log(input.value);
7 | };
8 | };
9 |
--------------------------------------------------------------------------------
/week4/2-DOM-Todo/mockup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Frontend-JavaScript-2/280c9d0fc8a1cb30c86101f3928afa3c05090df1/week4/2-DOM-Todo/mockup.png
--------------------------------------------------------------------------------
/week4/README.md:
--------------------------------------------------------------------------------
1 | # The DOM API
2 |
3 | We are now going to write our JavaScript code in the browser and start manipulating the DOM.
4 |
5 | Here are some essential materials:
6 |
7 | * [Introduction to DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction)
8 | * [Events in the DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Events)
9 | * [More DOM examples](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Examples)
10 | * [Difference between window, document and screen](http://stackoverflow.com/questions/9895202/what-is-the-difference-between-window-screen-and-document-in-javascript)
11 | * [Code examples for DOM API](materials/dom.js)
12 | * [How to listen for DOM ready event](materials/page.js)
13 |
14 |
--------------------------------------------------------------------------------
/week4/hangout/README.md:
--------------------------------------------------------------------------------
1 | # Hangout 3 - DOM and jQuery like implementation
2 |
3 | In that hangout we implement a simple class, that behaves like jQuery.
4 |
5 | The main idea is to provide our own DOM API, which is much better than the original. We do this by wrappingthe DOM API with methods of our own.
6 |
7 | [Here is the video from the hangout](https://www.youtube.com/watch?v=AnHwvAO2q0U)
8 |
--------------------------------------------------------------------------------
/week4/hangout/dom-wrapper.js:
--------------------------------------------------------------------------------
1 | // s(element) -> element/s
2 | // element.text
3 | // element.appendTo(anotherElement)
4 | // element.on
5 | // element.attr
6 | // element.addClass()
7 | // element.removeClass()
8 | // element.show()
9 | // element.hide()
10 |
11 | // element.forEach
12 |
13 | function hasKey(dict, key) {
14 | return typeof dict[key] !== "undefined";
15 | }
16 |
17 |
18 | function isArrayLike(object) {
19 | return Array.isArray(object) ||
20 | (typeof(object.length) !== "undefined" && typeof(object.item) !== "undefined");
21 | }
22 |
23 |
24 | function s(selector) {
25 | if(selector instanceof Element) {
26 | return selector;
27 | } else if(typeof(selector) === "string") {
28 | var domObjects = document.querySelectorAll(selector);
29 |
30 | return new Element(domObjects);
31 | } else if(typeof(selector) === "object") {
32 | return new Element(selector);
33 | } else {
34 | throw {
35 | "name": "Selection Error",
36 | "message": "Cannot select: " + selector.toString()
37 | };
38 | }
39 | }
40 |
41 | function c(tag) {
42 | var domObject = document.createElement(tag);
43 | return new Element(domObject);
44 | }
45 |
46 | function Element(domObjects) {
47 | this.domRepr = function() {
48 | if(isArrayLike(domObjects) && domObjects.length === 1) {
49 | return domObjects[0];
50 | }
51 |
52 | return domObjects;
53 | };
54 | }
55 |
56 | Element.prototype.text = function(text) {
57 | var textNode = document.createTextNode(text);
58 | this.domRepr().appendChild(textNode);
59 |
60 | return this;
61 | };
62 |
63 | Element.prototype.appendTo = function(container) {
64 | container.domRepr().appendChild(this.domRepr());
65 | return this;
66 | };
67 |
68 | Element.prototype.on = function(event, callback) {
69 | this.forEach(function(domElement) {
70 | domElement.addEventListener(event, callback);
71 | });
72 |
73 | return this;
74 | };
75 |
76 | Element.prototype.addClass = function(newClass) {
77 | this.forEach(function(domElement) {
78 | if(domElement.className === "") {
79 | domElement.className = newClass;
80 | return this;
81 | }
82 |
83 | var classes = domElement.className.split(" ");
84 | classes.push(newClass);
85 | domElement.className = classes.join(" ");
86 |
87 | });
88 |
89 | return this;
90 | };
91 |
92 |
93 | Element.prototype.removeClass = function(className) {
94 | var domElement = this.domRepr();
95 | var classes = domElement.className.split(" ");
96 |
97 | classes = classes.filter(function(currentClass) {
98 | return currentClass !== className;
99 | });
100 |
101 | domElement.className = classes.join(" ");
102 |
103 | return this;
104 | };
105 |
106 | Element.prototype.hide = function() {
107 | this.domRepr().style.visibility = "hidden";
108 |
109 | return this;
110 | };
111 |
112 | Element.prototype.show = function() {
113 | this.domRepr().style.visibility = "";
114 |
115 | return this;
116 | };
117 |
118 | // s("#container").attr("id") == getter
119 | // s("#container").attr("class", "container2") == setter
120 | Element.prototype.attr = function(attributeName, attributeValue) {
121 | var aliases = {
122 | "class": "className"
123 | };
124 | var domElement = this.domRepr();
125 |
126 | if(hasKey(aliases, attributeName)) {
127 | attributeName = aliases[attributeName];
128 | }
129 |
130 | if(hasKey(domElement, attributeName)) {
131 | if (typeof attributeValue === "undefined") {
132 | return domElement[attributeName];
133 | } else {
134 | domElement[attributeName] = attributeValue;
135 | return this;
136 | }
137 | }
138 | };
139 |
140 | Element.prototype.forEach = function(f) {
141 | var domElement = this.domRepr();
142 |
143 | if(!isArrayLike(domElement)) {
144 | domElement = [domElement];
145 | }
146 |
147 | for(var i = 0; i < domElement.length; i += 1) {
148 | f(domElement[i]);
149 | }
150 |
151 | return this;
152 | };
153 |
154 |
--------------------------------------------------------------------------------
/week4/hangout/index.html:
--------------------------------------------------------------------------------
1 |
2 | jQuery-like example
3 |
4 |
Buy!!!
5 |
6 |
7 |
Item 1
8 |
Item 2
9 |
Item 3
10 |
Item 4
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/week4/hangout/interface.js:
--------------------------------------------------------------------------------
1 | // s - query
2 | // do something with elements
3 |
4 | s(document).on("DOMContentLoaded", function() {
5 | console.log("DOM Loaded");
6 |
7 | var container = s("#container"),
8 | lists = s("#lists"),
9 | hideButton = c("button"),
10 | showButton = c("button");
11 |
12 | hideButton
13 | .addClass("btn")
14 | .attr("id", "hide-button")
15 | .text("Hide")
16 | .appendTo(container);
17 |
18 | showButton
19 | .addClass("btn")
20 | .attr("id", "show-button")
21 | .text("Show!")
22 | .appendTo(container);
23 |
24 | s("button").on("click", function(event) {
25 | console.log(this);
26 | console.log(s(this).attr("id"));
27 | var id = s(this).attr("id");
28 |
29 | if(id === "show-button") {
30 | lists.show();
31 | } else if(id === "hide-button") {
32 | lists.hide();
33 | }
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/week4/materials/dom.js:
--------------------------------------------------------------------------------
1 | // PART1 - QUERING
2 | // If you want to take an element by tag:
3 |
4 | // ps is an array
5 | var ps = document.getElementsByTagName("p");
6 |
7 | for(var i = 0; i < ps.length; i += 1) {
8 | var p = ps[i];
9 | // changing the style of each paragraph
10 | p.style.border = "dashed 1px green";
11 | }
12 |
13 | // EVENTS
14 |
15 | var button = document.getElementById("main-button");
16 | button.onclick = function(event) {
17 | console.log("button was clicked");
18 | };
19 |
20 | // CREATING ELEMENTS
21 | var button = document.createElement("button");
22 | var text = document.createTextNode("I am Groot!");
23 | button.appendChild(text);
24 |
25 | var div = document.getElementById("the-div");
26 | div.appendChild(button);
27 |
--------------------------------------------------------------------------------
/week4/materials/page.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello!
4 |
5 |
6 |
7 |
HEADING!
8 |
9 |
First item
10 |
Second item
11 |
Third item
12 |
Fourh item
13 |
14 |
15 |
16 |
I am Groot!
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/week4/materials/page.js:
--------------------------------------------------------------------------------
1 | document.addEventListener("DOMContentLoaded", function(event) {
2 | console.log("Hip hip");
3 | });
4 |
--------------------------------------------------------------------------------
/week5/2-todo-crud/README.md:
--------------------------------------------------------------------------------
1 | # Week 5 : Task 2 : Todo CRUD App
2 |
3 | ## Reference
4 | - http://learn.jquery.com/code-organization/concepts/
5 | - http://contribute.jquery.org/style-guide/js/
6 |
7 |
8 | ## Last time
9 | - got the code from week 4
10 | - created and inited a new project
11 | - replaced dom modifications and event handling with jQuery
12 | - added "finish task" logic
13 |
14 | ## Today
15 | - no npm & express
16 | - code refactoring
17 | - CRUD pattern
18 | - Module pattern
19 |
20 | ## New Project Steps
21 | for more info see week1 1-hello-node
22 |
23 | - initial file structure
24 | - create new files and directories
25 | - copy the files with repeating functionality
26 | - inits and dependencies (bower, npm)
27 | - initial interface
28 | - initial functionality
29 |
30 |
31 | ## Directory Structure
32 |
33 | ```
34 | .
35 | ├── .bowerrc # change public/lib to just lib here
36 | ├── bower.json # generated by bower init
37 | ├── index.html
38 | ├── js
39 | │ ├── app.js # TodoApp = (fucntion(){...})()
40 | │ └── init.js # $(document).ready(...) here
41 | └── lib
42 | └── jquery # bower install --save jquery
43 | ```
44 |
45 | ## What is a collection
46 |
47 | ```js
48 | var task = {
49 | id: 25,
50 | name: "Do the dishes"
51 | finished: false
52 | }
53 |
54 | var tasks = [
55 | {
56 | id: 15,
57 | name: "Get some groceries",
58 | finished: true
59 | },
60 | {
61 | id: 20,
62 | name: "Call grandma",
63 | finished: false
64 | },
65 | {
66 | id: 25,
67 | name: "Do the dishes"
68 | finished: false
69 | }
70 | ]
71 | ```
72 |
73 | ## app.js
74 |
75 | http://learn.jquery.com/code-organization/concepts/#the-module-pattern
76 |
77 | ```js
78 | var TodoApp = (function() {
79 | // private vars
80 | var tasks = [];
81 | var index = 0;
82 |
83 | // (optional) store the reference with the jQuery selectors here
84 | var refs = {
85 | addTask: "input#addTask",
86 | container: "#container"
87 | }
88 |
89 | // (optional) interface for setting the
90 | var setSelectorRefs = function(refs){
91 |
92 | }
93 |
94 | var addTask = function(taskName) {
95 | // add to tasks
96 | };
97 |
98 | var finishTask = function(id) {
99 | // update task
100 | };
101 |
102 | var displayList = function() {
103 | // clear the contents
104 | // loop through the tasks
105 | // append each task
106 | };
107 |
108 | // public api
109 | return {
110 | createTask: addTask,
111 | finishTask: finishTask,
112 | displayList: displayList
113 | };
114 | })();
115 |
116 | // access via
117 | TodoApp.addTask("Do the dishes")
118 |
119 | ```
120 |
121 | ## init.js
122 |
123 | ```js
124 | 'use strict'
125 |
126 | $(document).ready(function(){
127 | // init stuff
128 | })
129 | ```
--------------------------------------------------------------------------------
/week5/README.md:
--------------------------------------------------------------------------------
1 | # Week5 : jQuery
2 |
3 | Before we start here is a cheat sheet for jQuery
4 |
5 | ## Selecting elements
6 |
7 | ```js
8 | // dom objects
9 | var domObject = document.getElementById("idHere");
10 | $( domObject )
11 |
12 | // select by tagname
13 | $( "div" )
14 |
15 | // select by class
16 | $( "span.superClass" )
17 | $( ".anotherClass")
18 |
19 | // select by id
20 | $( "p#ultraId" )
21 |
22 | // select childs
23 | $( "ul.list > li.list-element")
24 | ```
25 |
26 | ## Getting and Setting
27 |
28 | ```js
29 | // html, text
30 | $("p.article").html("