Alexandru Păvăloi
🔥 will have acquired confidence to start basic Web projects on your own
🚀 will have worked on a personal project which showcases your skills
🎈 will have worked with multiple colleagues and thus grow your team-work skills
❌ Front-end
❌ Learning frameworks
T - 3 teste optionale, neanuntate la curs, maxim 10pct
E - 3 teste optionale, neanuntate la seminar, maxim 10pct
✅ To pass
VS Code
Chrome
glitch.com
codepen.io
Every Saturday I'll post in-advance exercises for the next lab!
This
is
HTML ▶
HTML doesn't look good, but works good!
<img>
<p></p>
✅ Self-closing
✅ Need a closing tag!
<img src="bob.png">
<p>
Hi!
<img src="bob.png">
</p>
Elements can have attributes!
Or contain other elements!
<!DOCTYPE html>
<html>
<head>
<title> My page </title>
</head>
<body>
<h1> Hello! </h1>
</body>
</html>
Week #2
✅ always validate your HTML here: https://validator.w3.org/
✅ don't choose an HTML tag for it's style
✅ `action` and `method` attributes on form
✅ label for each input
<label for="usernameInput"> Username </label>
<input type="text" id="usernameInput" required >
✅ `type` and `required` attributes
✅ <select> or radio input for the gender
✅ if you can click on it, it's a <a> or a <button>
<button type="button"> ❤ </button>
<footer>
<nav>
<ul>
<li> <a href=""> Privacy </a> </li>
<li> <a href=""> Terms </a> </li>
</ul>
</nav>
</footer>
#2 what you had to do
<img srcset="
https://iampava.com/PICTURES/tw-2019/bike-fullhd.jpg 1980w,
https://iampava.com/PICTURES/tw-2019/bike-medium.jpg 1000w,
https://iampava.com/PICTURES/tw-2019/bike-small.jpg 480w"
sizes="100vw"
src="bike-50.jpg"
alt="bikes"
/>
??? {
border: 5px solid black;
background: blue;
}
property
value
selector
@media screen and (max-width: 500px) {
??? {
border: 5px solid black;
background: blue;
}
}
@media screen and (orientation: landscape) {
??? {
background: red;
}
}
<!-- index.html -->
<link rel="stylesheet" href="style.css" />
<!-- style.css -->
footer {
color: #000;
background-color: #fff;
}
<style>
h1 {
text-align: center;
}
</style>
<p style="font-weight: bold">
A simple styled paragraph...
</p>
i want to select same-tag elements from the page
<p>
Who is Batman?
</p>
<p>
...uhm, Bruce Wayne?
</p>
<style>
p {
font-size: 50px;
}
</style>
i want to select similar elements from the page
<button type="button"> Log In </button>
<button type="button"> Register </button>
<button type="button"> Sign Out </button>
<button type="button" class="btn-round">
Log In
</button>
<button type="button" class="btn-round">
Register
</button>
<button type="button"> Sign Out </button>
<style>
.btn-round {
border-radius: 10px;
}
</style>
i want to select a specific element from the page
<p id="hello">
A simple styled paragraph...
</p>
<style>
#hello {
font-weight: bold;
}
</style>
<img
class="square-image round-image"
id="profile" src="user.jpg"
alt="user profile"/>
<style>
img {
border: 1px solid black;
}
.round-image {
border-radius: 50%;
border: 5px dotted red;
}
.square-image {
border-radius: 0;
border: 5px dashed green;
}
#profile {
border: 2px solid blue;
}
</style>
😎 ID
😉 Class
😊 Tag Name
💥 !important
.raining .human {
/*
"human" class elements
inside "raining"-class elements
*/
display: hidden;
position: under-blanket;/
}
.valentines.in-love {
/*
both "valentines" & "in-love"
classes
*/
text-decoration: make-up;
}
Week #3
<meta
name="viewport"
content="width=device-width, initial-scale=1"
>
Without this it won't be responsive on mobile devices...
Bonus
STATIC
RELATIVE
ABSOLUTE
FIXED
Sticky
{ position: ? }
BLOCK
INLINE-BLOCK
INLINE
🧓 TABLE
❤ FLEXBOX
🆕 GRID
{ display: ? }
#logo {
tranform: scale(1.1) rotate(35deg);
}
#logo {
transform: scale(1.1) rotate(30deg);
transform-origin: 0 0;
}
/* transform-origin: center | top left | top right | ... */
.5 sec
#logo {
transition: transform .5s ease-in;
}
#logo:hover {
transform: scale(1.1);
}
property
timing function
duration
#logo {
transition: all .5s ease-in;
}
#logo:hover {
opacity: 0;
transform: scale(2);
/* ... */
}
A
A
A
A
#logo {
animation: rotate 1s linear infinite;
}
@keyframes rotate {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(180deg);
}
100% {
transform: rotate(360deg)
}
}
duration
name
timing function
iteration count
Week #4
<label for="email">
Email*
</label>
Tag
Attribute
<!DOCTYPE html>
<html lang="en">
<head>
<meta
name="viewport"
content="width=device-width,
initial-scale=1.0
">
<title>Document</title>
<!-- Meta data - aka: data about data -->
</head>
<body>
<!-- Actual content of the page -->
</body>
</html>
Must have for responsiveness
.header .logo {
border: 5px solid black;
position: relative;
left: 50px;
}
Selector
Property
Value
✅ external
👎 in-page
👿 inline
ID
#bob {
color: red;
}
Class
.fii {
font-weight: bold;
}
Tag
student {
background: #abcdef;
}
If same selectors, then the last one in the stylesheet wins!
Practical Recommendation
<div>
<p style="display: block">
I'm small but important! Give me all this space!
<p style="display: inline-block">
<p style="display: inline-block">
I'just need this much :)
I'just need this much :)
static
Default - aka - nothing special.
relative
Relative to it's static position.
{ top: 20px; left: 15%; }
{ bottom: 3em; right: 5px; }
absolute
Relative to the first ancestor with a non-static position
{ top: 20px; left: 15%; }
{ bottom: 3em; right: 5px; }
fixed
Relative to the first ancestor with a transform property
{ top: 20px; left: 15%; }
{ bottom: 3em; right: 5px; }
🤔 Do you have all the project's pages implemented?
🤔 Have you implemented most of the user-interactions? Sliding menus, pop'ups, etc...
❗ Validate all your HTML - https://validator.w3.org/
❗ Every team-member will be marked according to his contribution to the project as seen in the public GitHub repo!
❗ Having all the pages is not enough. Make sure you've written quality HTML & CSS
Evaluation timetable soon on: https://iampava.com/tw
OR
Week #6
Download and install XAMPP if you've chosen PHP!
Server
3rd party API's
DB
Microservices
Client
Server
Browser
Math operations
✅ PHP intro
✅ Add 2 numbers using a Form
✅ Decide order based on checkbox
Add dropdown to choose betweeen
➕
➖
❌
➗
Users
✅ Read users from JSON and show on screen
Insert users into that JSON via a form!
Implement "Delete users" functionality!
Week #7
Prea putin timp la test
Enunt la test, nu doar un GIF/Video
Mai multe "joculete" gen CSS Dinner
?
Poate ar trebui pe viitor sa acorzi mici puncte bonus pentru exercitiile corecte trimise pe platforma.
Poate ca nu ar trebui sa fie doua designuri diferite care sa faca diferenta la teste si putin mai mult timp. La celelalte grupe, nu am auzit sa fie acelasi principiu de notare.
Obligarea studentilor sa foloseasca git pentru a publica laboratoarele. Si dupa sa fie corectate
<?php
$CONFIG = [
'servername' => "localhost",
'username' => "root",
'password' => '',
'db' => 'test'
];
$conn = new mysqli($CONFIG["servername"], $CONFIG["username"], $CONFIG["password"], $CONFIG["db"]);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
} else {
echo "Successfully connected to DB";
}
?>
Query'ing the DB
We're using Prepared Statement to prevent this 👇
Query'ing the DB
<?php
$username = "Bob";
$pass = "12345";
$insertStatement = $conn -> prepare("INSERT INTO users VALUES(?, ?)");
$insertStatement -> bind_param("ss", $username, $pass);
$insertStatement -> execute();
$insertStatement -> close();
?>
<?php
$getUsersStatement = $conn -> prepare("SELECT * FROM users WHERE username = ?");
$getUsersStatement -> bind_param("s", $username);
$getUsersStatement -> execute();
$users = $getUsersStatement -> get_result();
foreach($users as $row) {
echo $row['username'];
echo ' -- ';
echo $row['password'];
echo '<br/>';
}
?>
Bob
Login
Login Controller
Auth Model
Check
Credentials
store
🍪 session id
🍪 username & hashed pass
JWT
<?php
/** START - Persist session for 2 hours,
even after closing the browser
*/
$TWO_HOURS = 60 * 60 * 2;
ini_set('session.cookie_lifetime', $TWO_HOURS);
ini_set('session.gc_maxlifetime', $TWO_HOURS);
/** END - Needs to be called only once,
when starting the server
*/
session_start();
if(isset($_SESSION['count'])) {
$_SESSION['count'] ++;
} else {
$_SESSION['count'] = 1;
}
echo $_SESSION['count'];
?>
sessions
Week #8
Descrieți arhitectura aplicației via diagrame/desene/info-grafice/text etc...
Acest pas pregătește următoarea etapă: soluția finală. Scopul vostru e să descrieți cât mai în detaliu ce și cum se întâmplă, pentru a face implementarea o simplă formalitate.
PS: nu trebuie sa scrieți cod pentru această evaluare.
#0 Use-case flows
Prezentați - eventual via diagrame Use case - cele mai importante flow'uri ale aplicației.
#1 DB
În cazul unei baze de date relaționale, prezentați structura și relațiile între toate tabelele necesare aplicației - PK/FK/1-to-1/1-to-many/many-to-1 etc.
În cazul unei baze de date No-SQL, prezentați structura acesteia și oferiți argumente pentru a motiva alegerea.
#2 MV*
Detaliați design-pattern'ul principal folosit în aplicație.
De exemplu, în cazul MVC, prezentați:
Check out și tutorial ăsta.
#3 Autentificare
Descieți metoda aleasă pentru a persista utilizatorii logați. De exemplu, la DevDrive eu folosesc un JSON Web Token in care criptez ID'ul unic al utilizatorului logat.
Acesta expira dupa 2 ore pentru a preveni atacuri ce au la baza "furtul" JWT'ului.
#4 API'uri externe
Dacă aplicația se va folosi de diverse API'uri externe, prezentați pentru fiecare endpoint:
Recomand formatul RAML.
Dacă aplicația va expune un API REST, documentați cele de mai sus pentru API'ul oferit.
#5 Microservicii
Decideți care sunt microserviciile în care veți împărți proiectul. Acestea trebuie sa fie total independente unele de altele, inclusiv BD'uri separate.
Apoi, pentru fiecare microserviciu, descrieți toate cele enunțate mai sus.
#6 Bonus
Orice alt aspect arhitectural care contribuie la produsul final.
Spor, si dacă aveți orice fel de întrebări/nelămuriri, știți unde să-mi scrieți 😉
ful
Week #10
A Web service is a software system designed to support inter-operable machine-to-machine interaction over a network.
Usecase
⭐⭐⭐⭐⭐
online ratings about the book
Book review Blog
#1 Web Scrapping
#2 Web Services
REpresentational
State Transfer
REST
=
The computational results are actually resource representations
each resource representation has an associated URL
clients interact with those resources via http verbs
https://demo.app/v3/users
https://demo.app/v3/users/iampava
{
"users": [{
"username": "iampava",
"avatar": "https://demo.app/avatar.png"
}]
}
{
"username": "iampava",
"avatar": "https://demo.app/avatar.png"
}
📄 Accept: application/json
https://demo.app/v3/users/iampava/settings
{
"theme": "light-gray",
"notifications": false
}
https://demo.app/v3/users/
{
"username": "iampava",
"avatar": "https://demo.app/avatar.png"
}
{
"username": "iampava",
"avatar": "https://demo.app/avatar.png",
"id": 1234
}
https://demo.app/v3/users/1234
AND/OR
I code
Install this 👇
You code
/got_api/key
{
"key": "ZO5zFDWk"
}
Retrieve a secret key which allows you to call this API 5 times.
/got_api/character/${name}
📄 Bearer: {secret_key}
Get details about that GOT characters
or
or
/got_api/season/${s_no}/episode/${e_no}
📄 Bearer: {secret_key}
Add details to that episode
{
"title": "Battle of the bastards",
"length": 60.23
}
or
or
/got_api/season/${s_no}/episode/${e_no}
📄 Bearer: {secret_key}
Get details about an episode in the requested format
or
or
📄 Accept: application/json || text/html
ful
Week #11
<?php
$endpoint = $_SERVER['REQUEST_URI'];
$method = $_SERVER['REQUEST_METHOD'];
$requestHeaders = getallheaders();
$requestBodyAsString = file_get_contents('php://input');
// check which endpoint it is via Regular Expressions
preg_match('/^\/api\/users\/(.+)$/', $endpoint, $matches)
// to set Response Headers
header('Content-type: application/json');
http_response_code(201);
// to set Response Body
echo $body;
?>
RewriteEngine On
RewriteBase /
RewriteRule ^got_api/.+$ ./my_file.php [NC,L]
.htaccess flags:
NC - no case
L - last (stop if the rule matches)
/got_api/key
{
"key": "ZO5zFDWk"
}
Request an API key which allows you to call this API 5 times.
📝 Content-type: application/json
#1
/got_api/episodes
[{
"title": "Winterfell",
"duration": 60
}]
Get all episodes
📝 Content-type: application/json
#1
#2
Create/override an episode
/got_api/season/{s_no}/episode/{e_no}
{
"title": "Battle of the bastards",
"duration": 61
}
📝 Bearer: {key}
{
"reason": "Invalid"
}
{
"reason": "Expired"
}
#3
/got_api/season/{s_no}/episode/{e_no}
Get info about an episode!
📝 Bearer: {key}
{
"reason": "Invalid"
}
{
"reason": "Expired"
}
{
"title": "Battle of the bastards",
"duration": 61
}
#4
Update parts of an episode
/got_api/season/{s_no}/episode/{e_no}
📝 Bearer: {key}
{
"title": "The red wedding"
}
{
"reason": "Invalid"
}
{
"reason": "Expired"
}
#5
/got_api/season/{s_no}/episode/{e_no}
Delete all information about a specific episode!
📝 Bearer: {key}
{
"reason": "Invalid"
}
{
"reason": "Expired"
}
#6
Write a tiny app which consumes this API via a nice User Interface.
<?php
$req = curl_init("http://iampava.com/got_api/episodes");
$headers = array(
'Content-Type:application/json',
'Accept: application/json'
);
$body = array(
"title" => "1234",
"duration" => 12344
);
curl_setopt($req, CURLOPT_CUSTOMREQUEST, 'GET');
// curl_setopt($req, CURLOPT_HTTPHEADER, $headers);
// curl_setopt($req, CURLOPT_POSTFIELDS, json_encode($body));
curl_setopt($req, CURLOPT_RETURNTRANSFER, 1);
$responseBody = curl_exec($req);
$responseCode = curl_getinfo($req)['http_code'];
curl_close($req);
// echo $responseCode;
echo json_encode($respAsJson);
// echo $responseBody;
// echo gettype($respAsJson);
?>
ful
Week #12
Let's consume a REST API from PHP with cURL
<?php
$req = curl_init("http://iampava.com/got_api/episodes");
$headers = array(
'Content-Type:application/json',
'Accept: application/json'
);
$body = array(
"title" => "1234",
"duration" => 12344
);
curl_setopt($req, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($req, CURLOPT_HTTPHEADER, $headers);
curl_setopt($req, CURLOPT_POSTFIELDS, json_encode($body));
curl_setopt($req, CURLOPT_RETURNTRANSFER, 1);
$responseBody = curl_exec($req);
$responseCode = curl_getinfo($req)['http_code'];
curl_close($req);
echo $responseCode;
echo json_encode($responseBody);
?>
Week #12
Before AJAX we were stuck to this 👇
Fat
Server
Thin
Client
But now, we have a choice between 👆 and 👇
Thin
Server
Fat
Client
Or variations in between *
Today's focus
I code
Let's ask for a Chuck Norris joke and add it to a simple HTML page.
<!DOCTYPE html>
<html lang="en">
<head> <title>Chuck Norris API</title> </head>
<body>
<button id="refreshBtn" type="button">Refresh Joke</button>
<script>
let body = document.querySelector('body');
let btnEl = document.getElementById('refreshBtn');
btnEl.addEventListener('click', () => {
btnEl.disabled = true;
fetch('https://api.chucknorris.io/jokes/random', {
method: 'GET'
})
.then(resp => resp.json())
.then(jsonResp => {
const p = document.createElement('p');
p.innerText = jsonResp.value;
body.appendChild(p);
btnEl.disabled = false;
})
.catch(err => {
alert(err);
btnEl.disabled = false;
});
});
</script>
</body>
</html>
Fetch API
fetch('URL', options? : FetchOptions): Promise
interface FetchOptions {
method: string;
headers: Headers;
body: string;
}
interface Headers {
[name]: string
}
const body = {
username: 'bob',
password: '1234'
};
fetch('URL', {
method: 'POST',
headers: new Headers({
'Content-type': 'application/json',
'Accept': 'text/plain'
}),
body: JSON.stringify(body)
});
You code #1
Let's ask for all joke categories and print them as a list of buttons
You code #2
Let's append a new joke from that category when we click it!
You code #3
Let's turn the buttons into radios & add a text input to free search for jokes in that category.
DEMO
Week #13
☑ fully functional solution
☑ at least one AJAX call
☑ project report in Scholarly HTML
☑ instructions manual also in Scholarly HTML format
☑ demonstrative video (for M projects) 🔗 additional details
Feedback: https://forms.gle/pBGMmu2Xruu3nUbY7