Freelance - JavaScript developer and architect
Détecte le support d'une fonctionnalité par le navigateur
Ajoute en JavaScript une fonctionnalité native qu'un navigateur n'implémente pas
🔎 <nom_fonctionalité> polyfill <navigateur_cible>
Permet de faire fonctionner une version récente de javascript (ES6) sur un navigateur qui ne le supporte.
Quelques mots clés :
Les smartphones se sont développés au moment de HTML 5 : Très bon support globalement
Popularité des applications webview (ex: cordova)
Popularité des Progressive Web Applications (PWA)
clic droit -> afficher la source
<!doctype html>
<section></section>
<li itemtype="http://microformats.org/profile/hcard" itemscope>
<div itemprop="fn">Tony Stark</div>
</li>
<input name="myinput" type="choisir_ci-dessous" />
https://caniuse.com/#search=sliders (94.5%)
<input type="range" min="0" max="100" step="10" name="range" />
<input type="range" list="rangelist" min="0" max="100" name="range" />
<datalist id="rangelist">
<option value="20" label="low">
<option value="50">
<option value="80" label="high">
</datalist>
https://caniuse.com/#search=placeholder (97.7%)
<input type="text" list="valuelist" name="val" placeholder="Saisir une valeur" />
<datalist id="valuelist">
<option value="abc" label="low">
<option value="bcd">
<option value="cde" label="high">
</datalist>
Exemple 1:
const dateRegexp = /[0-9]{2}-[0-9]{2}-[0-9]{4}/gi
document.getElementById('regexpDate').innerHTML = 'test de dates:' + '<br/>'
document.getElementById('regexpDate').innerHTML += '20/10/1987'.match(dateRegexp) + '<br/>'
document.getElementById('regexpDate').innerHTML += '20-10-1987'.match(dateRegexp) + '<br/>'
</div>
Exemple 2:
const bulletLine = /\* (.*)/g
const text =
`* une ligne
* une autre
* ça va changer !`;
document.getElementById('regexpText').innerHTML = text.replace(bulletLine, '- $1<br/>')
Impossible de penser à tous les cas du premier coup :
🔎 regexp date_fr
Avec un pattern
<form action="#" name="validate1" onsubmit="alert(document.validate1.val.value);return false;">
<input type="text" list="valuelist2" name="val" placeholder="Saisir une valeur"
pattern="[A-Za-z]{3}" title="3 lettres minuscule ou majuscules"/>
<datalist id="valuelist2">
<option value="dfg" label="low">
<option value="fgh">
<option value="ghj" label="high">
</datalist>
<input type="submit" />
</form>
Avec un required
<form action="#" name="validate2" onsubmit="alert(document.validate2.val.value);return false;">
<input type="text" list="valuelist3" name="val" placeholder="Saisir une valeur"
required pattern="[A-Za-z]{3}" title="3 lettres minuscule ou majuscules" />
<datalist id="valuelist3">
<option value="jkl" label="low">
<option value="klm">
<option value="mpo" label="high">
</datalist>
<input type="submit" />
</form>
Par exemple en forçant une valeur de la datalist
<form … onsubmit="return formIsValid();">
function formIsValid() {
const value = document.validate2.val.value
const list = document.getElementById('valuelist3').options
if (value === 'secret') return true
for(var i = 0; i < list.length; i++) {
if (list.item(i).value === value) return true
}
return false;
}
https://developer.mozilla.org/fr/docs/Web/HTML/Element/Video
<video src="https://zippy.gfycat.com/WavyMeanDesertpupfish.webm"
height="150" loop controls
poster="https://cdn.pixabay.com/photo/2017/11/11/23/31/curtain-2940999__340.png">
Votre navigateur ne permet pas de lire les vidéos.
Mais vous pouvez toujours <a href="https://zippy.gfycat.com/WavyMeanDesertpupfish.webm">la télécharger</a> !
</video>
https://developer.mozilla.org/fr/docs/Web/HTML/Element/audio
<audio src="http://developer.mozilla.org/@api/deki/files/2926/=AudioTest_(1).ogg"
autoplay>
Votre navigateur ne supporte pas l'élément <code>audio</code>.
</audio>
<canvas id='canvas1' width='480' height='320'> Canvas not supported</canvas>
const c = document.getElementById('canvas1');
const ctx = c.getContext('2d');
let x = 100, y = 160, i = 0;
ctx.fillStyle = 'lightgrey'; ctx.fillRect(0, 0, 480, 320);
// axis
ctx.beginPath();ctx.strokeStyle='red';
ctx.moveTo(0,y);ctx.lineTo(480,y);ctx.stroke();
ctx.moveTo(x,0);ctx.lineTo(x,320);ctx.stroke();
// draw function
ctx.beginPath();ctx.moveTo(x,y + Math.sin(0) * 100);
setInterval(function() {
i++;
ctx.lineTo(x + i, y + Math.sin(i/50) * 100);
ctx.strokeStyle='black';ctx.stroke();
}, 1000/60)
<svg width="480" height="320">
<rect width="480" height="320" style="fill:lightgrey;" />
<rect x="100" y="0" width="1" height="320" style="fill:red;" />
<rect x="0" y="160" width="480" height="1" style="fill:red;" />
<path id="svgpath" d="M 100 160 L 101 162 L 102 164 L 103 166 L 104 168 L 105 170 L 106 172 L 107 174 L 108 176 L 109 178 L 110 180 L 111 182 L 112 184 L 113 186 L 114 188 L 115 190 L 116 191 L 117 193 L 118 195 L 119 197 L 120 199 L 121 201 L 122 203 L 123 204 L 124 206 L 125 208 L 126 210 L 127 211 L 128 213 L 129 215 L 130 216 L 131 218 L 132 220 L 133 221 L 134 223 L 135 224 L 136 226 L 137 227 L 138 229 L 139 230 L 140 232 L 141 233 L 142 234 L 143 236 L 144 237 L 145 238 L 146 240 L 147 241 L 148 242 L 149 243 L 150 244 L 151 245 L 152 246 L 153 247 L 154 248 L 155 249 L 156 250 L 157 251 L 158 252 L 159 252 L 160 253 L 161 254 L 162 255 L 163 255 L 164 256 L 165 256 L 166 257 L 167 257 L 168 258 L 169 258 L 170 259 L 171 259 L 172 259 L 173 259 L 174 260 L 175 260 L 176 260 L 177 260 L 178 260 L 179 260 L 180 260 L 181 260 L 182 260 L 183 260 L 184 259 L 185 259 L 186 259 L 187 259 L 188 258 L 189 258 L 190 257 L 191 257 L 192 256 L 193 256 L 194 255 L 195 255 L 196 254 L 197 253 L 198 253 L 199 252 L 200 251 L 201 250 L 202 249 L 203 248 L 204 247 L 205 246 L 206 245 L 207 244 L 208 243 L 209 242 L 210 241 L 211 240 L 212 238 L 213 237 L 214 236 L 215 235 L 216 233 L 217 232 L 218 230 L 219 229 L 220 228 L 221 226 L 222 225 L 223 223 L 224 221 L 225 220 L 226 218 L 227 217 L 228 215 L 229 213 L 230 212 L 231 210 L 232 208 L 233 206 L 234 205 L 235 203 L 236 201 L 237 199 L 238 197 L 239 195 L 240 193 L 241 192 L 242 190 L 243 188 L 244 186 L 245 184 L 246 182 L 247 180 L 248 178 L 249 176 L 250 174 L 251 172 L 252 170 L 253 168 L 254 166 L 255 164 L 256 162 L 257 160 L 258 158 L 259 156 L 260 154 L 261 152 L 262 150 L 263 148 L 264 146 L 265 144 L 266 142 L 267 140 L 268 138 L 269 136 L 270 134 L 271 133 L 272 131 L 273 129 L 274 127 L 275 125 L 276 123 L 277 121 L 278 119 L 279 118 L 280 116 L 281 114 L 282 112 L 283 110 L 284 109 L 285 107 L 286 105 L 287 104 L 288 102 L 289 100 L 290 99 L 291 97 L 292 96 L 293 94 L 294 93 L 295 91 L 296 90 L 297 88 L 298 87 L 299 86 L 300 84 L 301 83 L 302 82 L 303 81 L 304 79 L 305 78 L 306 77 L 307 76 L 308 75 L 309 74 L 310 73 L 311 72 L 312 71 L 313 70 L 314 69 L 315 68 L 316 68 L 317 67 L 318 66 L 319 65 L 320 65 L 321 64 L 322 64 L 323 63 L 324 63 L 325 62 L 326 62 L 327 61 L 328 61 L 329 61 L 330 61 L 331 60 L 332 60 L 333 60 L 334 60 L 335 60 L 336 60 L 337 60 L 338 60 L 339 60 L 340 60 L 341 61 L 342 61 L 343 61 L 344 61 L 345 62 L 346 62 L 347 63 L 348 63 L 349 64 L 350 64 L 351 65 L 352 65 L 353 66 L 354 67 L 355 67 L 356 68 L 357 69 L 358 70 L 359 71 L 360 72 L 361 73 L 362 74 L 363 75 L 364 76 L 365 77 L 366 78 L 367 79 L 368 80 L 369 81 L 370 83 L 371 84 " stroke="black" stroke-width="3" fill="none" />
</svg>
const path = document.getElementById('svgpath');
let x = 100, y = 160, i = 0;
path.setAttribute('d', /* … */);
setInterval(function() {
i++;
path.setAttribute('d', /* … */);
}, 1000/60)
<canvas id='canvas' width='480' height='320'> Canvas not supported</canvas>
const c = document.getElementById('canvas2');
const gl = c.getContext('webgl');
// instructions opengl a partir d'ici
// c'est trop long pour une slide
Architecture client / serveur
HTTP = protocole de transfert
format du message HTTP = headers + payload
headers = request [ + response ] + métadonnées
compatible avec l'objet JavaScript
Autres formats similaires : xml, yaml, formats binaires
{
"menu": "Fichier",
"commandes": [
{
"titre": "Nouveau",
"action":"CreateDoc"
},
{
"titre": "Ouvrir",
"action": "OpenDoc"
}
]
}
Ne pas utiliser XHR2 !
https://developer.mozilla.org/fr/docs/Web/API/Fetch_API
+ polyfills si besoin (https://github.com/github/fetch)
fetch('/users.json')
.then(function(response) {
return response.json()
}).then(function(json) {
console.log('parsed json', json)
}).catch(function(ex) {
console.log('parsing failed', ex)
})
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response
} else {
var error = new Error(response.statusText)
error.response = response
throw error
}
}
function parseJSON(response) {
return response.json()
}
fetch('/users')
.then(checkStatus)
.then(parseJSON)
.then(function(data) {
console.log('request succeeded with JSON response', data)
}).catch(function(error) {
console.log('request failed', error)
})
Système de sécurité implémenté par les navigateurs
Empêche par défaut les requêtes cross-sites
(En anglais cross-domain)
Se configure au niveau du serveur web, les informations sont transmises à travers les headers http
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER
Access-Control-Max-Age: 1728000
https://developer.mozilla.org/fr/docs/HTTP/Access_control_CORS
https://html.spec.whatwg.org/multipage/web-messaging.html#crossDocumentMessages
Ouverture d'un socket réseau direct entre un serveur et un client. socket = adresse IP + port
Nécessite un serveur websocket dédié, application différente du serveur http
Utiliser des bibliothèques plutôt que l'API native, https://socket.io/
WebRTC est une autre API qui met l'accent sur les performances du streaming, plus complexe
Agents qui exécutent du code Asynchrone
localStorage.setItem("username", "John");
alert( "username = " + localStorage.getItem("username"));
~ 10Mo de capacité
https://caniuse.com/#search=Service%20Workers (73.67%) https://developer.mozilla.org/fr/docs/Web/API/Service_Worker_API/Using_Service_Workers
https://caniuse.com/#search=indexedDB (93.98%)
Stocker des données dans une base de données objets sur le navigateur du client
https://developer.mozilla.org/fr/docs/Web/API/API_IndexedDB
Capacité dépends des navigateur et du disque dur de l'utilisateur, en théorie beaucoup (> 100 Mo partagés)
https://caniuse.com/#search=file%20API (94.62%)
Manipuler des fichiers sélectionnés par l'utilisateur côté client
https://developer.mozilla.org/fr/docs/Web/API/File/Using_files_from_web_applications
Plusieurs cas d'utilisation (téléchargement, affichage des images, modification avec envoi)
https://caniuse.com/#search=Geolocation (95.01%)
Connaitre la position de l'utilisateur
if ("geolocation" in navigator) {
/* géolocalisation possible */
navigator.geolocation.getCurrentPosition(function(position) {
do_something(position.coords.latitude, position.coords.longitude);
})
} else {
alert("Le service de géolocalisation n'est pas disponible sur votre ordinateur.");
}
https://caniuse.com/#search=Orientation (91.8%)
Connaitre l'orientation du téléphone
window.addEventListener('deviceorientation', handleOrientation); function handleOrientation(event) { // true pour un référentiel terrestre // false pour un référentiel arbitraire const absolute = event.absolute; // inclinaison autour de l"axe Z const alpha = event.alpha; // inclinaison autour de l"axe X const beta = event.beta; // inclinaison autour de l"axe Y const gamma = event.gamma; }
https://caniuse.com/#search=battery (69.15%)
Connaitre l'état de charge du périphérique. Support en baisse pour confidentialité.
const battery = navigator.battery || navigator.mozBattery || navigator.webkitBattery;
function updateBatteryStatus() {
console.log("Batterie chargée à : " + battery.level * 100 + " %");
if (battery.charging) { console.log("Chargement de la batterie"); }
}
battery.addEventListener("chargingchange", updateBatteryStatus);
battery.addEventListener("levelchange", updateBatteryStatus);
updateBatteryStatus();
https://caniuse.com/#search=getUserMedia (84.56%)
Obtenir un flux de données du micro ou de la webcam.
Nombreux changement d'API, utilisation d'un Shim ou d'un polyfill recommandé.
🔎 Shim getUserMedia
Problématique très complèxe
🔎 css font stack
Problématique très complèxe
Approche naïve
@font-face {
font-family: 'League Gothic';
src: url('league-gothic.eot');
src: url('league-gothic.eot?#iefix') format('embedded-opentype'),
url('league-gothic.woff') format('woff'),
url('league-gothic.ttf') format('truetype');
}
Je suis en League Gothic !
<span style="font-family: 'League Gothic'">Je suis en League Gothic !</span>
https://caniuse.com/#search=CSS3%20selectors (98.16%)
sélecteurs CSS utilisés également dans les biblitohèque de requêtage du DOM
🔎 css selecteur <motif>
https://developer.mozilla.org/fr/docs/Web/CSS/S%C3%A9lecteurs_CSS
.shadowBox {
width: 200px;
color: #444444;
background-color: #ddd; /* Fallback for older browsers */
background-image: linear-gradient(#E5E5E5, #CFCFCF);
box-shadow: -1px 2px 5px 1px rgba(0, 0, 0, 0.7) /* inset */;
margin: 2rem;
padding: 1rem;
}
espace de couleur sRGB sur le web (sRGB color space)
.shadowBoxLeft {
background-color: rgba(255, 0, 0, 0.5);
}
.shadowBoxRight {
background-image: linear-gradient(#0000FF, rgba(0, 0, 255, 0));
/* #0000FFFF = rgba(0, 0, 255, 1)
= rgb(0, 0, 255)
= hsla(240, 100%, 50%, 1)
= hsl(240, 100%, 50%) */
}
.spinButton {
transition: transform 0.5s ease-in;
}
.spinButton:active {
transform: rotate(270deg);
}
.spinButton.easeout {
transition: transform 0.5s ease-out;
}
<button class="spinButton">Click me ! Ease-in</button>
<button class="spinButton easeout">Click me ! Ease-out</button>
@keyframes alwaysSpinButtonAnimation {
from {transform: rotate(0deg);}
50% {transform: rotate(90deg);}
to {transform: rotate(360deg);}
}
.alwaysSpinButton {
animation-name: alwaysSpinButtonAnimation;
animation-duration: 1s;
animation-iteration-count: 10;
animation-timing-function: linear;
}
<button class="alwaysSpinButton">Click me !</button>
Contenu qui s'adapte à l'espace d'affichage disponible
@media screen and (min-width: 1024px) {
)https://developer.mozilla.org/fr/Apps/app_layout/responsive_design_building_blocks
Retrouver les slides sur https://github.com/Lythom/formation-api-html5-css3