├── .env.example ├── .gitignore ├── .vscode ├── github-markdown.css ├── settings.json └── spellchecker.json ├── Gemfile ├── Gemfile.lock ├── README.md ├── SUMMARY.md ├── _config.yml ├── _layouts └── default.html ├── assets ├── css │ ├── default.css │ └── style.css └── javascript │ └── anchor-js │ └── anchor.min.js ├── book.json ├── exercices ├── 1-solutions │ ├── 1-quel-type.js │ ├── 2-creation-variables.js │ ├── 3-chatbot1.js │ ├── 4-chatbot2-arbre.jpg │ └── 4-chatbot2-code.js ├── 10-composants │ ├── README.md │ ├── docs │ │ ├── accordeon.html │ │ ├── carousel.html │ │ └── videos.html │ ├── index.html │ ├── lib │ │ ├── accordeon-v1.css │ │ ├── accordeon-v1.js │ │ ├── accordeon.css │ │ ├── accordeon.js │ │ ├── carousel-v1.css │ │ ├── carousel-v1.js │ │ ├── carousel.css │ │ ├── carousel.js │ │ ├── videos-v1.css │ │ ├── videos-v1.js │ │ ├── videos.css │ │ └── videos.js │ ├── samples │ │ ├── accordeon-v1.html │ │ ├── accordeon.html │ │ ├── carousel-v1.html │ │ ├── carousel.html │ │ ├── videos-v1.html │ │ └── videos.html │ └── test.html ├── 14-ajax2 │ ├── server │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── google-auth.js │ │ ├── nitrous-post-create.sh │ │ ├── nitrous.json │ │ ├── nitrous.readme.md │ │ ├── package.json │ │ ├── public │ │ │ ├── client-ajax.html │ │ │ ├── client-ajax.js │ │ │ ├── client.html │ │ │ └── index.html │ │ └── server.js │ ├── solution │ │ └── jsbin.yisari.2.html │ └── squelette │ │ └── jsbin.bucilir.6.html ├── 2-solutions │ ├── 1-fizzbuzz.js │ ├── 2-devine.js │ ├── 3-fonctions.js │ ├── 4-chifoumi-phase-1.js │ └── 4-chifoumi-phase-2.js ├── 3-solutions │ ├── 1-calendrier.js │ ├── 2-epicerie.js │ ├── 3-pendu-bonus.js │ ├── 3-pendu.js │ ├── 4-annuaire.js │ └── 5-repertoire.js ├── 4-solutions │ ├── JS-FORM-1 │ │ ├── index.html │ │ └── index.js │ ├── bonjour.html │ ├── bonjour.js │ ├── calculatrice-bonus │ │ ├── index.html │ │ └── index.js │ └── calculatrice │ │ ├── index.html │ │ └── index.js ├── 5-solutions │ └── produits │ │ ├── index.html │ │ └── index.js ├── 6-solutions │ ├── accordeon-v2-doc.html │ ├── accordeon-v2-example.html │ ├── accordeon-v2.css │ ├── accordeon-v2.js │ ├── accordeon.css │ ├── accordeon.html │ ├── accordeon.js │ ├── carousel-v2-doc.html │ ├── carousel-v2-example.html │ ├── carousel-v2.css │ ├── carousel-v2.js │ ├── carousel.css │ ├── carousel.html │ ├── carousel.js │ ├── videos-v2-doc.html │ ├── videos-v2-example.html │ ├── videos-v2.css │ ├── videos-v2.js │ ├── videos.css │ ├── videos.html │ └── videos.js ├── 8-solutions │ ├── ajax-get-images-flickr.html │ ├── ajax-get-images-giphy.html │ ├── ajax-get-ip.js │ ├── ajax-get-time.js │ ├── ajax-get-weather.html │ ├── ajax-get-weather.js │ └── ajax-post-twitter.html └── 9-code │ ├── jsbin.haxeqad.2.html │ └── jsbin.tuyofec.5.html ├── icon.png ├── img ├── 4-1-accordion.gif ├── 4-2-carousel.gif ├── 4-3-videos.gif ├── ajax.svg ├── apple-calculator-landscape.jpg ├── arbre-decision.png ├── buttons.png ├── categories.gif ├── chrome-console.png ├── composant-multi-avec-api.png ├── composant-multi-groupe.png ├── cookbook.gif ├── diagram.svg ├── doesnotcompute.jpg ├── error-oper.png ├── error-prog.png ├── geoloc.gif ├── isnotjava.png ├── jsconsole.png ├── netscape.jpg └── screenshot.jpg ├── js-logo.png ├── package-lock.json ├── package.json ├── qcms ├── js-controle-1-solutions.pdf ├── js-controle-2-solutions.pdf ├── js-controle-3-solutions.pdf ├── js-partiel-1-solutions.pdf ├── js-test-1-solutions.pdf ├── js-test-2-solutions.pdf ├── js-test-3-solutions.pdf ├── js-test-4-solutions.pdf ├── js-test-5-solutions.pdf ├── js-test-6-solutions.pdf ├── js-test-7-solutions.pdf ├── js-test-8-solutions.pdf ├── js-test-9-solutions.pdf └── qcm-10-solutions.pdf ├── slides ├── .vscode │ └── spellchecker.json ├── 01-intro │ ├── img │ │ ├── apple-calculator-landscape.jpg │ │ ├── chrome-console.png │ │ ├── isnotjava.png │ │ ├── netscape.jpg │ │ └── yoda.png │ ├── index.html │ └── slides.md ├── 02-conditions │ ├── img │ │ └── arbre-decision.png │ ├── index.html │ └── slides.md ├── 03-algo │ ├── index.html │ └── slides.md ├── 05-fonctions │ ├── img │ │ ├── fct-appel-valeurs.png │ │ ├── fct-appel.png │ │ └── fct-chaine.png │ ├── index.html │ └── slides.md ├── 06-tableaux │ ├── index.html │ └── slides.md ├── 07-objets │ ├── index.html │ └── slides.md ├── 08-dom │ ├── index.html │ └── slides.md ├── 09-styling │ ├── img │ │ └── categories.gif │ ├── index.html │ └── slides.md ├── 10-composants │ ├── img │ │ ├── 1-accordion.gif │ │ ├── 2-carousel.gif │ │ └── 3-videos.gif │ ├── index.html │ └── slides.md ├── 11-poo │ ├── index.html │ └── slides.md ├── 12-advdom │ ├── index.html │ └── slides.md ├── 13-ajax │ ├── ajax.svg │ ├── index.html │ └── slides.md ├── 14-ajax2 │ ├── diagram-get.svg │ ├── diagram-post.svg │ ├── index.html │ └── slides.md ├── 15-auth │ ├── img │ │ ├── buttons.png │ │ ├── diagram.svg │ │ ├── screenshot.jpg │ │ └── thumbs-up.jpg │ ├── index.html │ └── slides.md ├── 16-jquery │ ├── img │ │ ├── dom-tree.png │ │ ├── dom.png │ │ └── jquery.svg │ ├── index.html │ └── slides.md ├── 17-error │ ├── img │ │ ├── error-oper.png │ │ ├── error-prog.png │ │ └── geoloc.gif │ ├── index.html │ └── slides.md ├── remark-styling.css └── remark.min.js ├── tp01.md ├── tp02.md ├── tp03.md ├── tp04.md ├── tp05.md ├── tp06.md ├── tp07.md ├── tp08.md ├── tp09.md ├── tp10.md ├── tp11.md ├── tp12.md ├── tp13.md ├── tp14.md ├── tp15.md ├── tp16.md └── tp17.md /.env.example: -------------------------------------------------------------------------------- 1 | # Create a token from https://github.com/settings/tokens 2 | # with just access to public repos, then paste it below, 3 | # and save this file as `.env` 4 | JEKYLL_GITHUB_TOKEN="xxx" 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node rules: 2 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 3 | .grunt 4 | 5 | ## Dependency directory 6 | ## Commenting this out is preferred by some people, see 7 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 8 | node_modules 9 | 10 | # Book build output 11 | _book 12 | 13 | # eBook build output 14 | *.epub 15 | *.mobi 16 | /*.pdf 17 | 18 | # Jekyll / GitHub pages 19 | _site 20 | .jekyll-metadata 21 | 22 | # Other 23 | .env 24 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "markdown.styles": [ 3 | "./.vscode/github-markdown.css" 4 | ], 5 | "cSpell.language": ",fr" 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/spellchecker.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "fr", 3 | "ignoreWordsList": [ 4 | "closure", 5 | "Surbrillance", 6 | "spoilers", 7 | "Généricité", 8 | "ajax" 9 | ], 10 | "documentTypes": [ 11 | "markdown", 12 | "latex", 13 | "plaintext" 14 | ], 15 | "ignoreRegExp": [], 16 | "ignoreFileExtensions": [], 17 | "checkInterval": 5000 18 | } -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # for Jekyll, static md to html file generation 2 | # see https://help.github.com/articles/setting-up-your-github-pages-site-locally-with-jekyll/#step-2-install-jekyll-using-bundler 3 | source 'https://rubygems.org' 4 | gem 'dotenv' 5 | gem 'github-pages', group: :jekyll_plugins 6 | gem 'jekyll-seo-tag' 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Logo JavaScript](js-logo.png) 2 | 3 | # Cours JavaScript 4 | 5 | * [TP 1 - Les Bases](tp01.md) 6 | * [TP 2 - Conditions](tp02.md) 7 | * [TP 3 - Algorithmes et Jeux](tp03.md) 8 | * [TP 4 - Fonctions](tp04.md) 9 | * [TP 5 - Tableaux](tp05.md) 10 | * [TP 6 - Objets](tp06.md) 11 | * [TP 7 - Classes et POO](tp07.md) 12 | * [TP 8 - Manipuler le Web avec DOM](tp08.md) 13 | * [TP 9 - Manipuler les classes et styles CSS](tp09.md) 14 | * [TP 10 - Manipulation DOM avancée](tp10.md) 15 | * [TP 11 - Récupération de données avec AJAX](tp11.md) 16 | * [TP 12 - Envoi de données avec AJAX](tp12.md) 17 | * [TP 13 - Composants Web](tp13.md) 18 | * [TP 14 - Composants et POO](tp14.md) 19 | * [TP 15 - jQuery, Node.js et frameworks](tp15.md) 20 | * [TP 16 - Identification avec Google et Facebook](tp16.md) 21 | * [TP 17 - Gestion d'erreurs et Geolocation API](tp17.md) 22 | 23 | 47 | 48 | ## Ressources alternatives 49 | 50 | - [Formation JavaScript de Grafikart](https://www.grafikart.fr/formations/debuter-javascript) 51 | - [(Cours/TP) Apprentissage JavaScript](https://docs.google.com/document/d/1j9KsH-YtlYuMhmcPRlqtNJ_JdrD2JUiErmwEUTWt23I), par Julien Guézennec 52 | - OpenClassrooms: [Apprenez à coder avec JavaScript](https://openclassrooms.com/courses/apprenez-a-coder-avec-javascript) 53 | - OpenClassrooms: [Créez des pages web interactives avec JavaScript](https://openclassrooms.com/courses/creez-des-pages-web-interactives-avec-javascript) 54 | - Khan Academy: [HTML/JS : faire des pages Web interactives](https://fr.khanacademy.org/computing/computer-programming/html-css-js) 55 | 56 | ## Ressources alternatives en langue anglaise 57 | 58 | - [JS for cats](http://jsforcats.com/), une explication simple et amusante des concepts de base 59 | - [You-Dont-Know-JS](https://github.com/getify/You-Dont-Know-JS/), free book series on JavaScript 60 | - [JS Books](http://jsbooks.revolunet.com/) 61 | - [JavaScript basics](https://medium.freecodecamp.com/my-giant-javascript-basics-course-is-now-live-on-youtube-and-its-100-free-9020a21bbc27), videos by Beau Carnes + [challenges on freeCampCode](http://beta.freecodecamp.com/en/map) 62 | - [JavaScript 30 — Build 30 things with vanilla JS in 30 days with 30 tutorials](https://javascript30.com/) 63 | - [leonardomso/33-js-concepts: 📜 33 concepts every JavaScript developer should know.](https://github.com/leonardomso/33-js-concepts) 64 | - [The JavaScript Bits You Skipped the First Time Around - Illustrated Notes](https://illustrated.dev/advancedjs) 65 | - [A Fruitful Guide to JavaScript's Comparison Operators - A Visual Explanation](https://illustrated.dev/fruit-comparison) 66 | - [🔥🕺🏼 JavaScript Visualized: Hoisting - DEV Community 👩‍💻👨‍💻](https://dev.to/lydiahallie/javascript-visualized-hoisting-478h) 67 | 68 | ## Ressources annexes au cours 69 | 70 | - [Apprendre à apprendre: deux modes d’apprentissage](http://www.internetactu.net/2015/09/08/apprendre-a-apprendre-14-deux-modes-dapprentissage/) 71 | - [Startup Noob Guide](http://bit.ly/startupnoob) 72 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [Introduction](README.md) 4 | * [TP 1 - Les Bases](tp01.md) 5 | * [TP 2 - Conditions](tp02.md) 6 | * [TP 3 - Algorithmes et Jeux](tp03.md) 7 | * [TP 4 - Fonctions](tp04.md) 8 | * [TP 5 - Tableaux](tp05.md) 9 | * [TP 6 - Objets](tp06.md) 10 | * [TP 7 - Classes et POO](tp07.md) 11 | * [TP 8 - Manipuler le Web avec DOM](tp08.md) 12 | * [TP 9 - Manipuler les classes et styles CSS](tp09.md) 13 | * [TP 10 - Manipulation DOM avancée](tp10.md) 14 | * [TP 11 - Récupération de données avec AJAX](tp11.md) 15 | * [TP 12 - Envoi de données avec AJAX](tp12.md) 16 | * [TP 13 - Composants Web](tp13.md) 17 | * [TP 14 - Composants et POO](tp14.md) 18 | * [TP 15 - jQuery, Node.js et frameworks](tp15.md) 19 | * [TP 16 - Identification avec Google et Facebook](tp16.md) 20 | * [TP 17 - Gestion d'erreurs et Geolocation API](tp17.md) 21 | 22 | 29 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | title: # Name of your blog (this will show up at the top of your page and in the RSS feed) 2 | Cours JavaScript 3 | 4 | author: # Your name, as you want it to appear underneath each post and in the footer 5 | Adrien Joly 6 | 7 | avatar: # URL of your avatar or profile pic (you could use your GitHub profile pic) 8 | /icon.png 9 | 10 | desc: 11 | Supports de cours JavaScript pour étudiants EEMI de 1ère année. 12 | 13 | keywords: javascript,initiation,exercices,cours,tuto,web,développement,dom 14 | 15 | repository: adrienjoly/cours-javascript 16 | 17 | google_analytics: UA-1858235-4 18 | 19 | twitter: # used by the jekyll seo plugin 20 | username: adrienjoly 21 | card: summary 22 | 23 | social: 24 | name: Adrien Joly 25 | links: 26 | - https://twitter.com/adrienjoly 27 | - https://www.linkedin.com/in/adrienjoly 28 | - https://github.com/adrienjoly 29 | - https://medium.com/@adrienjoly 30 | 31 | defaults: 32 | - scope: 33 | path: "" 34 | values: 35 | image: "/js-logo.png" 36 | author: "@adrienjoly" 37 | 38 | # github defaults 39 | encoding: UTF-8 40 | lang: fr-FR 41 | kramdown: 42 | input: GFM 43 | hard_wrap: false 44 | future: true 45 | jailed: false 46 | theme: jekyll-theme-primer 47 | gfm_quirks: paragraph_end 48 | 49 | # additional config 50 | exclude: 51 | - node_modules 52 | - "**/node_modules" 53 | - Gemfile 54 | - Gemfile.lock 55 | - src 56 | 57 | plugins: 58 | - jekyll-seo-tag 59 | -------------------------------------------------------------------------------- /_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {% seo %} 9 | 10 | 11 | 12 | 22 | 23 | 24 |
25 | {% if site.title and site.title != page.title %} 26 |

27 | {% unless page.title %} 28 | {{ site.author }} - 29 | {% endunless %} 30 | {{ site.title }} 31 | {% if page.title %} - {{ page.title }}{% endif %} 32 |

33 | 34 | 35 | {% endif %} 36 | 37 | {{ content }} 38 | 39 | 42 |
43 | 44 | 45 | {% if site.google_analytics %} 46 | 54 | {% endif %} 55 | 56 | 57 | 64 | 65 | -------------------------------------------------------------------------------- /assets/css/default.css: -------------------------------------------------------------------------------- 1 | /* partially imported from /index.css */ 2 | 3 | /* 4 | * Web Fonts from fontspring.com 5 | * 6 | * All OpenType features and all extended glyphs have been removed. 7 | * Fully installable fonts can be purchased at http://www.fontspring.com 8 | * 9 | * The fonts included in this stylesheet are subject to the End User License you purchased 10 | * from Fontspring. The fonts are protected under domestic and international trademark and 11 | * copyright law. You are prohibited from modifying, reverse engineering, duplicating, or 12 | * distributing this font software. 13 | * 14 | * (c) 2010 Fontspring 15 | * 16 | * The fonts included are copyrighted by the vendor listed below. 17 | * 18 | * Vendor: FontSite Inc. 19 | * License URL: http://www.fontspring.com/fflicense/fontsite 20 | */ 21 | 22 | @font-face { 23 | font-family: 'AlternateGothicFSNo3'; 24 | src: url('/fonts/AlternateGothicNo3-webfont.eot'); 25 | src: url('/fonts/AlternateGothicNo3-webfont.woff') format('woff'), url('/fonts/AlternateGothicNo3-webfont.ttf') format('truetype'), url('/fonts/AlternateGothicNo3-webfont.svg#webfontUJOPMwss') format('svg'); 26 | font-weight: normal; 27 | font-style: normal; 28 | } 29 | 30 | a { 31 | color: #0091BE; 32 | } 33 | 34 | .clear { 35 | clear:both; 36 | } 37 | 38 | iframe { 39 | width: 100%; 40 | } 41 | 42 | /* project listings */ 43 | 44 | .thumb { 45 | color: #333; 46 | } 47 | 48 | .thumbs p { 49 | margin-top: 0px !important; 50 | margin-bottom: 5px; 51 | } 52 | 53 | .thumbs b { 54 | font-weight: normal; 55 | background-color: rgba(69, 185, 57, 0.20); 56 | padding: 2px; 57 | } 58 | 59 | .thumbs li { 60 | display:inline-block; 61 | vertical-align:top; 62 | list-style: none; 63 | text-shadow: 0 1px 0 white; 64 | width:270px; 65 | margin-right: 30px; 66 | margin-bottom: 30px; 67 | } 68 | 69 | .thumbs li .screenshot > * { 70 | border-radius: 5px; 71 | border: 2px solid #5B6A79; 72 | width:260px; 73 | height:180px; 74 | margin-bottom: 15px; 75 | opacity:0.8; 76 | transition: opacity 0.1s; 77 | -moz-transition: opacity 0.1s; /* Firefox 4 */ 78 | -webkit-transition: opacity 0.1s; /* Safari and Chrome */ 79 | -o-transition: opacity 0.1s; /* Opera */ 80 | text-align: center; 81 | } 82 | 83 | .thumbs li .screenshot > div > div { 84 | display: inline-block; 85 | margin-top: 76px; 86 | border: 1px solid #DFDFDF; 87 | color: #DFDFDF; 88 | padding: 8px; 89 | } 90 | 91 | .thumbs li:hover img { 92 | opacity:1; 93 | } 94 | 95 | .thumbs h2 { 96 | width: 260px; 97 | margin-bottom: 15px; 98 | padding-bottom: 0; 99 | font-family: AlternateGothicFSNo3,"Arial Narrow"; 100 | text-transform: uppercase; 101 | font-weight: normal; 102 | border-bottom: 0 none; 103 | } 104 | 105 | .thumbs h2 a { 106 | font-size: 24px; 107 | color: #5B6A79; 108 | } 109 | 110 | .thumbs h2 a:hover { 111 | color: #0091BE; 112 | } 113 | 114 | .thumbs h2 small { 115 | font-size:16px; 116 | float:right; 117 | color: #5B6A79; 118 | } 119 | 120 | .thumbs li p { 121 | font-size: 12px; 122 | width: 260px; 123 | } 124 | 125 | .thumbs li:hover h2 a, .content li a:focus h2 a { 126 | color: #0091BE; 127 | text-decoration: none; 128 | } 129 | 130 | .thumbs li:hover img, .content li a:focus img { 131 | border: 2px solid #0091BE; 132 | } 133 | 134 | .thumbs h3 { 135 | margin-top: 20px; 136 | margin-bottom: 10px; 137 | } 138 | 139 | 140 | /* icons */ 141 | 142 | .pdf { 143 | background: url('/img/page_white_acrobat.gif') left center no-repeat; 144 | padding-left: 22px; 145 | } 146 | 147 | 148 | .whyd { 149 | background: url('/img/icon-whyd.png') left center no-repeat; 150 | padding-left: 22px; 151 | } 152 | 153 | .openwhyd { 154 | background: url('/img/icon-openwhyd.png') left center no-repeat; 155 | background-size: 16px 16px; 156 | padding-left: 22px; 157 | } 158 | 159 | .youtube { 160 | background: url('/img/icon-youtube.png') left center no-repeat; 161 | padding-left: 22px; 162 | } 163 | 164 | .github { 165 | background: url('/img/icon-github.png') left center no-repeat; 166 | padding-left: 22px; 167 | } 168 | 169 | .medium { 170 | background: url('/img/logo-medium.png') left center no-repeat; 171 | background-size: 16px 16px; 172 | padding-left: 22px; 173 | } 174 | 175 | .wunderlist { 176 | background: url('/img/icon-wunderlist.png') left center no-repeat; 177 | background-size: 16px 16px; 178 | padding-left: 22px; 179 | } 180 | 181 | .ideas { 182 | background: url('/img/icon-idea.png') left center no-repeat; 183 | background-size: 16px 16px; 184 | padding-left: 22px; 185 | } 186 | 187 | .news { 188 | background: url('/img/icon-news.png') left center no-repeat; 189 | background-size: 16px 16px; 190 | padding-left: 22px; 191 | } 192 | 193 | .patreon { 194 | background: url('/img/icon-patreon.png') left center no-repeat; 195 | background-size: 16px 16px; 196 | padding-left: 22px; 197 | } 198 | 199 | .npm { 200 | background: url('/img/icon-npm.png') left center no-repeat; 201 | padding-left: 22px; 202 | } 203 | 204 | .maddyness { 205 | background: url('/img/icon-maddyness.png') left center no-repeat; 206 | padding-left: 22px; 207 | } 208 | 209 | .liris { 210 | background: url('/img/icon-liris.png') left center no-repeat; 211 | padding-left: 22px; 212 | } 213 | 214 | .eventbrite { 215 | background: url('/img/icon-eventbrite.png') left center no-repeat; 216 | padding-left: 22px; 217 | } 218 | 219 | .instagram { 220 | background: url('/img/icon-instagram.png') left center no-repeat; 221 | padding-left: 22px; 222 | } 223 | 224 | .geeklist { 225 | background: url('/img/icon-geeklist.png') left center no-repeat; 226 | padding-left: 22px; 227 | } 228 | 229 | .lastfm { 230 | background: url('/img/lastfm.png') left center no-repeat; 231 | padding-left: 22px; 232 | } 233 | -------------------------------------------------------------------------------- /assets/css/style.css: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | @import "{{ site.theme }}"; 5 | -------------------------------------------------------------------------------- /assets/javascript/anchor-js/anchor.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AnchorJS - v4.1.0 - 2017-09-20 3 | * https://github.com/bryanbraun/anchorjs 4 | * Copyright (c) 2017 Bryan Braun; Licensed MIT 5 | */ 6 | !function(A,e){"use strict";"function"==typeof define&&define.amd?define([],e):"object"==typeof module&&module.exports?module.exports=e():(A.AnchorJS=e(),A.anchors=new A.AnchorJS)}(this,function(){"use strict";return function(A){function e(A){A.icon=A.hasOwnProperty("icon")?A.icon:"",A.visible=A.hasOwnProperty("visible")?A.visible:"hover",A.placement=A.hasOwnProperty("placement")?A.placement:"right",A.ariaLabel=A.hasOwnProperty("ariaLabel")?A.ariaLabel:"Anchor",A.class=A.hasOwnProperty("class")?A.class:"",A.truncate=A.hasOwnProperty("truncate")?Math.floor(A.truncate):64}function t(A){var e;if("string"==typeof A||A instanceof String)e=[].slice.call(document.querySelectorAll(A));else{if(!(Array.isArray(A)||A instanceof NodeList))throw new Error("The selector provided to AnchorJS was invalid.");e=[].slice.call(A)}return e}function i(){if(null===document.head.querySelector("style.anchorjs")){var A,e=document.createElement("style");e.className="anchorjs",e.appendChild(document.createTextNode("")),void 0===(A=document.head.querySelector('[rel="stylesheet"], style'))?document.head.appendChild(e):document.head.insertBefore(e,A),e.sheet.insertRule(" .anchorjs-link { opacity: 0; text-decoration: none; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }",e.sheet.cssRules.length),e.sheet.insertRule(" *:hover > .anchorjs-link, .anchorjs-link:focus { opacity: 1; }",e.sheet.cssRules.length),e.sheet.insertRule(" [data-anchorjs-icon]::after { content: attr(data-anchorjs-icon); }",e.sheet.cssRules.length),e.sheet.insertRule(' @font-face { font-family: "anchorjs-icons"; src: url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype"); }',e.sheet.cssRules.length)}}this.options=A||{},this.elements=[],e(this.options),this.isTouchDevice=function(){return!!("ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch)},this.add=function(A){var n,o,s,a,r,c,h,l,u,d,f,p=[];if(e(this.options),"touch"===(f=this.options.visible)&&(f=this.isTouchDevice()?"always":"hover"),A||(A="h2, h3, h4, h5, h6"),0===(n=t(A)).length)return this;for(i(),o=document.querySelectorAll("[id]"),s=[].map.call(o,function(A){return A.id}),r=0;r\]\.\/\(\)\*\\]/g;return this.options.truncate||e(this.options),A.trim().replace(/\'/gi,"").replace(t,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&(" "+A.firstChild.className+" ").indexOf(" anchorjs-link ")>-1,t=A.lastChild&&(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ")>-1;return e||t||!1}}}); -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Cours JavaScript", 3 | "author": "Adrien Joly" 4 | } 5 | -------------------------------------------------------------------------------- /exercices/1-solutions/1-quel-type.js: -------------------------------------------------------------------------------- 1 | typeof 0 // => number 2 | typeof true // => boolean 3 | typeof 2 - 1.2 // => number 4 | typeof 'hello' // => string 5 | typeof 'bonjour' + 4 // => string (car concaténation) 6 | typeof { a: 0.4 } // => object 7 | typeof [ 'a', 'b', 'c' ] // => object (car un tableau est une sorte d'objet) 8 | -------------------------------------------------------------------------------- /exercices/1-solutions/2-creation-variables.js: -------------------------------------------------------------------------------- 1 | // solution: 2 | var monNombre = 4; 3 | var maChaine = 'bonjour ! :-)'; // string => apostrophes, et respecter chaque caractère 4 | var monBooleen = false; // boolean => pas d'apostrophes 5 | var sansValeur; // pas de valeur => pas d'affectation 6 | 7 | // vérification: 8 | monNombre === 4; // => true 9 | maChaine === 'bonjour ! :-)'; // => true 10 | monBooleen === false; // => true 11 | sansValeur === undefined; // => true 12 | -------------------------------------------------------------------------------- /exercices/1-solutions/3-chatbot1.js: -------------------------------------------------------------------------------- 1 | // on commence par poser une question avec prompt 2 | var reponse = prompt('bonjour?'); 3 | // la réponse a été stockée dans la variable reponse 4 | 5 | // maintenant, on définit le comportement du programme 6 | // pour 3 réponses possibles (alternatives) 7 | if (reponse === 'bonjour') { 8 | alert('Bonjour à toi !'); 9 | } else if (reponse === 'tu vas bien ?') { 10 | alert('Bien, et toi ?'); 11 | } else { 12 | // cette partie sera executée par défaut, si aucune des 13 | // conditions ci-dessus n'est vraie 14 | alert('Désolé, je n\'ai pas compris...'); 15 | } 16 | -------------------------------------------------------------------------------- /exercices/1-solutions/4-chatbot2-arbre.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/exercices/1-solutions/4-chatbot2-arbre.jpg -------------------------------------------------------------------------------- /exercices/1-solutions/4-chatbot2-code.js: -------------------------------------------------------------------------------- 1 | // ce programme est une évolution de chatbot1.js 2 | 3 | // on commence par poser une question avec prompt 4 | var reponse = prompt('bonjour?'); 5 | // la réponse a été stockée dans la variable reponse 6 | 7 | // maintenant, on définit le comportement du programme 8 | // pour 3 réponses possibles (alternatives) 9 | if (reponse === 'bonjour') { 10 | // nous sommes à l'intérieur des accolades => indentation de 2 espaces 11 | 12 | // à ce stade, l'utilisateur a saisi bonjour, 13 | // on va lui poser une deuxieme question avec prompt 14 | var reponse2 = prompt('Bonjour ! Comment vas-tu ?'); 15 | 16 | // condition imbriquée dans notre 1ère condition: 17 | if (reponse2 === 'oui') { 18 | // on est à nouveau entre accolades => indentation supplémentaire 19 | alert('Je suis content pour toi.'); 20 | } else { 21 | alert('Désolé, il faut que je file.'); 22 | } 23 | // nous allons sortir des accolades => fin de l'indentation de 2 espaces 24 | } else if (reponse === 'tu vas bien ?') { 25 | // observez bien l'expression ci-dessous, elle est liée à la 1ère 26 | // question prompt, et non à la deuxième. 27 | alert('Bien, et toi ?'); 28 | } else { 29 | alert('Désolé, je n\'ai pas compris...'); 30 | } 31 | -------------------------------------------------------------------------------- /exercices/10-composants/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/exercices/10-composants/README.md -------------------------------------------------------------------------------- /exercices/10-composants/docs/accordeon.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

Composant "accordéon"

9 | 10 |

Description

11 | 12 | Ce composant permet d'afficher une liste de dépêches, et de permettre à l'utilisateur d'afficher le contenu d'une seule dépêche à la fois, en cliquant sur son titre. 13 | 14 |

Exemple d'intégration

15 | 16 |
17 |
18 |
Le programme de Donald Trump
19 |
La durée de vie d'un décret est par ailleurs limitée: un président donc abroger un décret d'un prédécesseur, comme l'a fait Donald Trump en annulant plusieurs textes signés par Barack Obama, sur les projets d'oléoducs Keystone ou sur le financement ...
20 |
21 |
22 |
Donald Trump accuse les juges...
23 |
Dire que Donald Trump a peu apprécié le blocage de son décret anti-immigration par un juge fédéral est un euphémisme. Samedi 4 février, il l'a désigné à la vindicte des 23 millions d'abonnés de son compte Twitter, le qualifiant de « soi-disant juge ...
24 |
25 |
26 |
Donald Trump rencontrera ses alliés de l'Otan
27 |
En mai aura lieu une rencontre entre Donald Trump et ses alliés de l'Otan, a annoncé dimanche la Maison Blanche, après un entretien téléphonique entre le président américain et le secrétaire général de l'Alliance atlantique Jens Stoltenberg. Donald ...
28 |
29 |
30 | 31 |

Instructions d'intégration

32 | 33 |
    34 |
  1. Structurez chaque dépêche dans un élément <section>, contenant son titre dans un sous-élément <header>, et son contenu associé dans un sous-élément <article>, de la manière suivante: 35 | 36 | <div class="accordeon"> 37 | <section> 38 | <header>Titre 1</header> 39 | <article>Texte 1</article> 40 | </section> 41 | <section> 42 | <header>Titre 2</header> 43 | <article>Texte 2</article> 44 | </section> 45 | <section> 46 | <header>Titre 3</header> 47 | <article>Texte 3</article> 48 | </section> 49 | </div> 50 | 51 |
  2. 52 |
  3. Ajoutez les dépendances suivantes à votre page: 53 | 54 | <link rel="stylesheet" href="https://adrienjoly.com/cours-javascript/exercices/10-composants/lib/accordeon.css"> 55 | <script src="https://adrienjoly.com/cours-javascript/exercices/10-composants/lib/accordeon.js"></script> 56 | 57 |
  4. 58 |
  5. Vous pouvez intégrer plusieurs accordéons sur votre page, il suffit de regrouper vos dépêches dans des <div> séparés portant chacun la classe accordeon. 59 |
60 | 61 |

Code source du composant

62 | 63 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /exercices/10-composants/docs/carousel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Composant "Carousel"

11 | 12 |

Description

13 | 14 | Ce composant permet à l'utilisateur de naviguer parmi une liste d'images, une par une. 15 | 16 |

Exemple d'intégration

17 | 18 | 24 | 25 |

Instructions d'intégration

26 | 27 |
    28 | 29 |
  1. Insérez vos images dans votre page à l'aide d'éléments <img>, ajoutez un élément <button> portant la classe next, et placez tous ces éléments à l'intérieur d'un élément portant la classe carousel, de la manière suivante: 30 | 31 | <div class="carousel"> 32 | <button class="next">Image suivante</button> 33 | <img src="http://lorempixel.com/output/food-q-c-640-480-1.jpg"> 34 | <img src="http://lorempixel.com/output/food-q-c-640-480-2.jpg"> 35 | <img src="http://lorempixel.com/output/food-q-c-640-480-3.jpg"> 36 | </div> 37 | 38 |
  2. 39 | 40 |
  3. Ajoutez les dépendances suivantes à votre page: 41 | 42 | <link rel="stylesheet" href="https://adrienjoly.com/cours-javascript/exercices/10-composants/lib/carousel.css"> 43 | <script src="https://adrienjoly.com/cours-javascript/exercices/10-composants/lib/carousel.js"></script> 44 | 45 |
  4. 46 | 47 |
  5. Vous pouvez intégrer plusieurs Carousels sur votre page, il suffit que chaque galerie d'images de votre page soit regroupée dans un élément portant la classe carousel, au moment où la dépendance carousel.js sera chargée. 48 |
  6. 49 | 50 |
51 | 52 |

Code source du composant

53 | 54 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /exercices/10-composants/docs/videos.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Composant "Galerie Vidéo"

11 | 12 |

Description

13 | 14 | Ce composant permet à l'utilisateur de regarder une sélection de vidéos Youtube. 15 | 16 |

Exemple d'intégration

17 | 18 |
19 |
20 | 21 | 22 | 23 | 30 | 31 |

Instructions d'intégration

32 | 33 |
    34 | 35 |
  1. Ajoutez les dépendances suivantes à votre page: 36 | 37 | <link rel="stylesheet" href="https://adrienjoly.com/cours-javascript/exercices/10-composants/lib/videos.css"> 38 | <script src="https://adrienjoly.com/cours-javascript/exercices/10-composants/lib/videos.js"></script> 39 | 40 |
  2. 41 | 42 |
  3. Puis, pour chaque galerie vidéo à intégrer sur votre page, il vous suffira d'intégrer un élément <div>, puis d'appeler la fonction initialiseGalerieVideo() en passant en paramètres une référence de cet élément, et un tableau d'URLs de vidéos Youtube sous la forme https://www.youtube.com/embed/0uaQMxBjd5E. (cf documentation d'API ci-dessous) 43 |
  4. 44 | 45 |
46 | 47 |

API du composant

48 | 49 |

Fonction initialiseGalerieVideo(conteneur, videos)

50 | 51 |

Cette fonction permet d'intégrer une galerie vidéo à l'intérieur de l'élément conteneur (qui doit exister dans la page au moment de l'appel).

52 | 53 |

Au moment de l'appel, la fonction va ajouter un bouton par vidéo, afin de permettre à l'utilisateur de choisir la vidéo à consulter.

54 | 55 |

Paramètres:

56 | 60 | 61 |

Code source du composant

62 | 63 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /exercices/10-composants/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Exemples de composants 6 | 7 | 8 |

Exemples de composants

9 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /exercices/10-composants/lib/accordeon-v1.css: -------------------------------------------------------------------------------- 1 | header { 2 | background: black; 3 | color: white; 4 | } 5 | 6 | article { 7 | display: none; 8 | background: white; 9 | color: black; 10 | } 11 | 12 | article.visible { 13 | display: block; 14 | } 15 | -------------------------------------------------------------------------------- /exercices/10-composants/lib/accordeon-v1.js: -------------------------------------------------------------------------------- 1 | var headers = document.getElementsByTagName('header'); 2 | var articles = document.getElementsByTagName('article'); 3 | 4 | // cette fonction affiche le i-ème article 5 | function afficherArticle(i) { 6 | articles[i].classList.add('visible'); 7 | } 8 | 9 | // cette fonction cache tous les articles 10 | function cacherArticles() { 11 | for (var i = 0; i < articles.length; i++) { 12 | articles[i].classList.remove('visible'); 13 | } 14 | } 15 | 16 | // cette fonction retourne une fonction qui sert à n'afficher que l'i-ème article 17 | function pourAfficherArticle(i) { 18 | return function(){ 19 | cacherArticles(); 20 | afficherArticle(i); 21 | }; 22 | } 23 | 24 | // initialisation des headers 25 | for (var i = 0; i < headers.length; i++) { 26 | headers[i].onclick = pourAfficherArticle(i); 27 | } 28 | -------------------------------------------------------------------------------- /exercices/10-composants/lib/accordeon.css: -------------------------------------------------------------------------------- 1 | .accordeon header { 2 | background: black; 3 | color: white; 4 | } 5 | 6 | .accordeon article { 7 | display: none; 8 | background: white; 9 | color: black; 10 | } 11 | 12 | .accordeon article.visible { 13 | display: block; 14 | } 15 | -------------------------------------------------------------------------------- /exercices/10-composants/lib/accordeon.js: -------------------------------------------------------------------------------- 1 | function initialiseAccordeon(element) { 2 | 3 | // ces variables auront une valeur différente pour chaque appel de initialiseAccordeon() 4 | var headers = element.getElementsByTagName('header'); 5 | var articles = element.getElementsByTagName('article'); 6 | 7 | // cette fonction affiche le i-ème article de cet accordéon 8 | function afficherArticle(i) { 9 | articles[i].classList.add('visible'); 10 | } 11 | 12 | // cette fonction cache tous les articles de cet accordéon 13 | function cacherArticles() { 14 | for (var i = 0; i < articles.length; i++) { 15 | articles[i].classList.remove('visible'); 16 | } 17 | } 18 | 19 | // cette fonction retourne une fonction qui sert à n'afficher que l'i-ème article 20 | function pourAfficherArticle(i) { 21 | return function(){ 22 | cacherArticles(); 23 | afficherArticle(i); 24 | }; 25 | } 26 | 27 | // initialisation des headers 28 | for (var i = 0; i < headers.length; i++) { 29 | headers[i].onclick = pourAfficherArticle(i); 30 | } 31 | 32 | } 33 | 34 | // intégration des accordéons de la page 35 | var accordeons = document.getElementsByClassName('accordeon'); 36 | for (var i = 0; i < accordeons.length; i++) { 37 | initialiseAccordeon(accordeons[i]); 38 | } 39 | -------------------------------------------------------------------------------- /exercices/10-composants/lib/carousel-v1.css: -------------------------------------------------------------------------------- 1 | #carousel { 2 | position: relative; 3 | width: 300px; 4 | height: 200px; 5 | overflow: hidden; 6 | } 7 | 8 | .carousel-img { 9 | display: none; 10 | position: absolute; 11 | min-width: 100%; 12 | min-height: 100%; 13 | } 14 | 15 | .carousel-img.visible { 16 | display: block; 17 | } 18 | -------------------------------------------------------------------------------- /exercices/10-composants/lib/carousel-v1.js: -------------------------------------------------------------------------------- 1 | //var carousel = document.getElementById('carousel'); 2 | var images = document.getElementsByClassName('carousel-img'); 3 | 4 | var imageVisible = 0; 5 | 6 | // cette fonction affiche l'image suivante, et cache la précédente 7 | function changerImage() { 8 | images[imageVisible].classList.remove('visible'); 9 | imageVisible = (imageVisible + 1) % images.length; 10 | images[imageVisible].classList.add('visible'); 11 | } 12 | 13 | document.getElementById('next').onclick = changerImage; 14 | 15 | changerImage(); 16 | -------------------------------------------------------------------------------- /exercices/10-composants/lib/carousel.css: -------------------------------------------------------------------------------- 1 | .carousel { 2 | position: relative; 3 | width: 300px; 4 | height: 200px; 5 | overflow: hidden; 6 | } 7 | 8 | .carousel img { 9 | display: none; 10 | position: absolute; 11 | width: 100%; 12 | height: 100%; 13 | } 14 | 15 | .carousel img.visible { 16 | display: block; 17 | } 18 | -------------------------------------------------------------------------------- /exercices/10-composants/lib/carousel.js: -------------------------------------------------------------------------------- 1 | function initialiseCarousel(groupe) { 2 | 3 | var images = groupe.getElementsByTagName('img'); 4 | var imageVisible = 0; 5 | 6 | // cette fonction affiche l'image suivante, et cache la précédente 7 | function changerImage() { 8 | images[imageVisible].classList.remove('visible'); 9 | imageVisible = (imageVisible + 1) % images.length; 10 | images[imageVisible].classList.add('visible'); 11 | } 12 | 13 | groupe.getElementsByClassName('next')[0].onclick = changerImage; 14 | 15 | changerImage(); 16 | } 17 | 18 | var carousels = document.getElementsByClassName('carousel'); 19 | for (var i = 0; i < carousels.length; i++) { 20 | initialiseCarousel(carousels[i]); 21 | } 22 | -------------------------------------------------------------------------------- /exercices/10-composants/lib/videos-v1.css: -------------------------------------------------------------------------------- 1 | #video { 2 | width: 300px; 3 | height: 200px; 4 | background: black; 5 | } 6 | -------------------------------------------------------------------------------- /exercices/10-composants/lib/videos-v1.js: -------------------------------------------------------------------------------- 1 | // URL d'intégration de chaque vidéo Youtube 2 | var videos = [ 3 | 'https://www.youtube.com/embed/0uaQMxBjd5E', 4 | 'https://www.youtube.com/embed/c8ZPn6p5khI', 5 | 'https://www.youtube.com/embed/ikkrEOD1BbQ', 6 | ]; 7 | 8 | // références vers le DOM 9 | var video = document.getElementById('video'); 10 | var buttons = document.getElementsByTagName('button'); 11 | 12 | // fonction qui retourne une fonction permettant d'intégrer la i-ème vidéo 13 | function pourAfficherVideo(i) { 14 | return function() { 15 | video.innerHTML = '' 16 | }; 17 | } 18 | 19 | // initialisation des boutons 20 | for (var i = 0; i < buttons.length; i++) { 21 | buttons[i].onclick = pourAfficherVideo(i); 22 | } 23 | -------------------------------------------------------------------------------- /exercices/10-composants/lib/videos.css: -------------------------------------------------------------------------------- 1 | .video { 2 | width: 300px; 3 | height: 200px; 4 | background: black; 5 | } 6 | -------------------------------------------------------------------------------- /exercices/10-composants/lib/videos.js: -------------------------------------------------------------------------------- 1 | function initialiseGalerieVideo(conteneur, videos) { 2 | 3 | // insertion du div de la video en cours 4 | conteneur.innerHTML = '
'; 5 | 6 | // insertion des boutons 7 | for (var i = 0; i < videos.length; i++) { 8 | conteneur.innerHTML += ''; 9 | } 10 | 11 | // références vers le DOM 12 | var video = conteneur.getElementsByClassName('video')[0]; 13 | var buttons = conteneur.getElementsByTagName('button'); 14 | 15 | // fonction qui retourne une fonction permettant d'intégrer la i-ème vidéo 16 | function pourAfficherVideo(i) { 17 | return function() { 18 | video.innerHTML = '' 19 | }; 20 | } 21 | 22 | // initialisation des boutons 23 | for (var i = 0; i < buttons.length; i++) { 24 | buttons[i].onclick = pourAfficherVideo(i); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /exercices/10-composants/samples/accordeon-v1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |
Le programme de Donald Trump
10 |
La durée de vie d'un décret est par ailleurs limitée: un président donc abroger un décret d'un prédécesseur, comme l'a fait Donald Trump en annulant plusieurs textes signés par Barack Obama, sur les projets d'oléoducs Keystone ou sur le financement ...
11 |
12 |
13 |
Donald Trump accuse les juges...
14 |
Dire que Donald Trump a peu apprécié le blocage de son décret anti-immigration par un juge fédéral est un euphémisme. Samedi 4 février, il l'a désigné à la vindicte des 23 millions d'abonnés de son compte Twitter, le qualifiant de « soi-disant juge ...
15 |
16 |
17 |
Donald Trump rencontrera ses alliés de l'Otan
18 |
En mai aura lieu une rencontre entre Donald Trump et ses alliés de l'Otan, a annoncé dimanche la Maison Blanche, après un entretien téléphonique entre le président américain et le secrétaire général de l'Alliance atlantique Jens Stoltenberg. Donald ...
19 |
20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /exercices/10-composants/samples/accordeon.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

Intégration 1

10 | 11 |
12 |
13 |
Le programme de Donald Trump
14 |
La durée de vie d'un décret est par ailleurs limitée: un président donc abroger un décret d'un prédécesseur, comme l'a fait Donald Trump en annulant plusieurs textes signés par Barack Obama, sur les projets d'oléoducs Keystone ou sur le financement ...
15 |
16 |
17 |
Donald Trump accuse les juges...
18 |
Dire que Donald Trump a peu apprécié le blocage de son décret anti-immigration par un juge fédéral est un euphémisme. Samedi 4 février, il l'a désigné à la vindicte des 23 millions d'abonnés de son compte Twitter, le qualifiant de « soi-disant juge ...
19 |
20 |
21 |
Donald Trump rencontrera ses alliés de l'Otan
22 |
En mai aura lieu une rencontre entre Donald Trump et ses alliés de l'Otan, a annoncé dimanche la Maison Blanche, après un entretien téléphonique entre le président américain et le secrétaire général de l'Alliance atlantique Jens Stoltenberg. Donald ...
23 |
24 |
25 | 26 |

Intégration 2

27 | 28 |
29 |
30 |
Titre 1
31 |
Texte 1
32 |
33 |
34 |
Titre 2
35 |
Texte 2
36 |
37 |
38 |
Titre 3
39 |
Texte 3
40 |
41 |
42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /exercices/10-composants/samples/videos-v1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /exercices/10-composants/samples/videos.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Intégration 1

11 |
12 |
13 | 14 |

Intégration 2

15 |
16 |
17 | 18 | 19 | 20 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /exercices/10-composants/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Carousel 1

11 | 12 | 18 | 19 |

Carousel 2

20 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /exercices/14-ajax2/server/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | -------------------------------------------------------------------------------- /exercices/14-ajax2/server/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Adrien Joly 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /exercices/14-ajax2/server/README.md: -------------------------------------------------------------------------------- 1 | [![Deploy with Nitrous Quickstart](https://nitrous-image-icons.s3.amazonaws.com/quickstart.svg)](https://www.nitrous.io/quickstart) 2 | 3 | # js-ajax-twitter 4 | 5 | A minimal client-server chat/twitter-like application using AJAX. 6 | 7 | Developed for educational use, to train students with AJAX calls. 8 | 9 | ## Usage 10 | 11 | ### Run the server (including on Heroku): 12 | 13 | - `npm install` 14 | - `npm start` 15 | 16 | ### From the browser: 17 | 18 | - `/index.html` renders the received chat messages in real-time (thanks to socket.io) 19 | - `/client.html` renders a form-based client 20 | 26 | 27 | ### API 28 | 29 | - POST `/tweet` endpoint accepts URL-encoded and JSON payloads. 30 | - The tweet / chat message is read from the `message` parameter. 31 | - The token provided by Google Auth must be provided in the `token` parameter. 32 | - It returns `{ok: "OK"}`, or `{error: 'error message'}` otherwise. 33 | - Google auth was only activated for the `https://js-ajax-twitter.herokuapp.com` and `https://*.jsbin.com` domains. 34 | - Access is restricted to EEMI students (i.e. signed in using the `eemi.com` domain). 35 | -------------------------------------------------------------------------------- /exercices/14-ajax2/server/google-auth.js: -------------------------------------------------------------------------------- 1 | var CLIENT_ID = '247219641427-ifeq88p7rgor9al5ksduds7ug0ba7djr.apps.googleusercontent.com'; 2 | 3 | var GoogleAuth = require('google-auth-library'); 4 | var auth = new GoogleAuth; 5 | var client = new auth.OAuth2(CLIENT_ID, '', ''); 6 | 7 | function checkToken(token, callback) { 8 | client.verifyIdToken(token, CLIENT_ID, function(e, login) { 9 | var payload = {}; 10 | if (!e) { 11 | payload = login.getPayload(); 12 | } 13 | callback(e, { 14 | id: payload['sub'], 15 | name: payload['name'], 16 | domain: payload['hd'], 17 | }); 18 | }); 19 | } 20 | 21 | exports.checkToken = checkToken; 22 | -------------------------------------------------------------------------------- /exercices/14-ajax2/server/nitrous-post-create.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # optional: commands to run after cloning the repo into nitrous.io 4 | # cf https://community.nitrous.io/docs/nitrous-quickstarts 5 | -------------------------------------------------------------------------------- /exercices/14-ajax2/server/nitrous.json: -------------------------------------------------------------------------------- 1 | { 2 | "template": "nodejs", 3 | "ports": [ 8080 ], 4 | "name": "js-ajax-twitter", 5 | "scripts": { 6 | "Start Nodejs server": "node server.js" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /exercices/14-ajax2/server/nitrous.readme.md: -------------------------------------------------------------------------------- 1 | The nitrous.readme.md file documents this nitrous-ready repo. 2 | -------------------------------------------------------------------------------- /exercices/14-ajax2/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-ajax-twitter", 3 | "description": "A minimal client-server chat/twitter-like application using AJAX and socketio.", 4 | "version": "1.0.0", 5 | "main": "server.js", 6 | "scripts": { 7 | "setup-host": "scutil --set LocalHostName \"aj-mbp\"; scutil --set HostName \"aj-mbp\";", 8 | "test": "curl localhost:8080/tweet -d '{\"message\":\"bonjour\"}'", 9 | "deploy": "echo \"don't forget to commit first!\" && heroku git:remote -a js-ajax-twitter && (cd ../../../ && git subtree push --prefix exercices/14-ajax2/server heroku master)", 10 | "deploy:force": "heroku git:remote -a js-ajax-twitter && (cd ../../../ && git push heroku `git subtree split --prefix exercices/14-ajax2/server master`:master --force)", 11 | "start": "node server.js" 12 | }, 13 | "author": "Adrien Joly ", 14 | "license": "MIT", 15 | "dependencies": { 16 | "body-parser": "^1.14.2", 17 | "connect": "^3.4.1", 18 | "cookies": "^0.7.0", 19 | "google-auth-library": "^0.10.0", 20 | "serve-static": "^1.10.2", 21 | "socket.io": "^1.4.4" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /exercices/14-ajax2/server/public/client-ajax.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | 16 | 17 |

Connexion: 18 |

19 | Sign out 20 |

21 |

Twittez:

22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /exercices/14-ajax2/server/public/client-ajax.js: -------------------------------------------------------------------------------- 1 | var message = document.getElementById('message'); 2 | 3 | function sendMessage() { 4 | if (message.value.length === 0) { 5 | return; 6 | } 7 | message.disabled = true; 8 | var xhr = new XMLHttpRequest(); 9 | xhr.open('POST', '/tweet'); 10 | xhr.onreadystatechange = function() { 11 | if (xhr.readyState === 4) { 12 | console.log('response:', xhr.responseText); 13 | message.disabled = false; 14 | var responseObject = JSON.parse(xhr.responseText); 15 | if (responseObject.error) { 16 | alert('Error: ' + responseObject.error); 17 | } else { 18 | console.log('Message was sent successfully :-)'); 19 | message.value = ''; 20 | message.focus(); 21 | } 22 | } 23 | }; 24 | xhr.send(JSON.stringify({ 25 | message: message.value, 26 | token: window.token, // provided by Google Auth / login on client-ajax.html 27 | })); 28 | } 29 | 30 | // the change event is emitted from the input every time the user presses ENTER 31 | document.getElementById('message').onchange = function() { 32 | console.log('user pressed ENTER'); 33 | sendMessage(); 34 | }; 35 | -------------------------------------------------------------------------------- /exercices/14-ajax2/server/public/client.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | 16 | 17 |

Connexion: 18 |

19 | Sign out 20 |

21 |

Twittez:

22 | 23 | 24 | 25 |
26 | 27 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /exercices/14-ajax2/server/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

Send your tweet by sending a HTTP POST request to the /tweet API endpoint of this server.

9 |

Example: form-based client

10 |

Latest tweets

11 | 12 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /exercices/14-ajax2/server/server.js: -------------------------------------------------------------------------------- 1 | // inspired from http://code.runnable.com/Umgo967vRZQMAABQ/a-simple-webserver-with-connect-for-node-js 2 | 3 | var HIDE_MESSAGES = false; // if true, content of messages will not be displayed on index 4 | 5 | var http = require('http'); 6 | var connect = require('connect'); 7 | var socketio = require('socket.io'); 8 | var bodyParser = require('body-parser'); 9 | var serveStatic = require('serve-static'); 10 | //var Cookies = require('cookies'); 11 | var GoogleAuth = require('./google-auth.js') 12 | 13 | var PORT = process.env.PORT || 8080; 14 | var COOKIE_NAME = 'js-ajax-twitter'; 15 | var TWEET_ENDPOINT = '/tweet'; 16 | var GOOGLE_DOMAIN = 'eemi.com'; 17 | 18 | var allowCrossDomain = function(req, res, next) { 19 | res.setHeader('Access-Control-Allow-Origin', '*'); 20 | res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS'); // TODO: reduce 21 | res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With'); 22 | // intercept OPTIONS method 23 | if ('OPTIONS' == req.method) { 24 | res.send(200); 25 | } 26 | else { 27 | next(); 28 | } 29 | }; 30 | 31 | // Configure the app 32 | var app = connect(); 33 | app.use(allowCrossDomain); 34 | app.use(bodyParser.urlencoded({ extended: false })); // parse urlencoded request bodies into req.body 35 | app.use(bodyParser.json({ type: '*/*', strict: false })); // parse json request bodies into req.body 36 | app.use(function(req, res, next) { 37 | /* 38 | var cookies = new Cookies(req); 39 | var cookieJSON = decodeURIComponent(cookies.get(COOKIE_NAME) || ''); 40 | console.log('(i) cookie:', cookieJSON); 41 | req.cookie = cookieJSON ? JSON.parse(cookieJSON) : null; 42 | */ 43 | var token = (req.body || {}).token/* || (req.cookie || {}).token*/; 44 | if (token) { 45 | GoogleAuth.checkToken(token, function(err, user) { 46 | if (err) { 47 | console.error('GoogleAuth error:', err); 48 | } else { 49 | req.googleUser = user; 50 | } 51 | next(); 52 | }); 53 | } else { 54 | next(); 55 | } 56 | }); 57 | app.use(serveStatic('./public', {'index': ['index.html']})); // Serve public files 58 | 59 | // Prepare socket.io server for public/log.html 60 | var httpServer = http.createServer(app) 61 | var io = socketio(httpServer); 62 | 63 | // /tweet is a POST API endpoint for users to connect and send messages 64 | app.use(/*TWEET_ENDPOINT,*/ function (req, response, next) { 65 | console.log('-', req.method, req.url, req.body, 'from', req.googleUser || req.cookie); 66 | function error(text) { 67 | console.log('=> /!\\ error:', text); 68 | response.end(JSON.stringify({ error: text })); 69 | } 70 | if (req.url !== TWEET_ENDPOINT) { 71 | error('please use the ' + TWEET_ENDPOINT + ' URL.'); 72 | } else if (req.method !== 'POST') { 73 | error('please use a POST request. not a GET.'); 74 | } else if (!(req.body || {}).token) { 75 | error('missing property: token.'); 76 | /* 77 | } else if (!req.cookie) { 78 | error('cookie not found. please log in.'); 79 | */ 80 | } else if (!req.googleUser) { 81 | error('google auth failed / invalid token. please log in with provided code.'); 82 | } else if (req.googleUser.domain != GOOGLE_DOMAIN) { 83 | error('unauthorized domain. please log in with your ' + GOOGLE_DOMAIN + ' account.'); 84 | } else if (!(req.body || {}).message) { 85 | error('missing property: message.'); 86 | } else { 87 | response.end(JSON.stringify({ ok: 'OK' })); 88 | // display message on log.html 89 | io.emit('chat', { 90 | message: HIDE_MESSAGES ? (req.body.message || '')[0] + '...' : req.body.message, 91 | 'content-type': req.headers['content-type'], 92 | user: req.googleUser, 93 | ip: req.connection.remoteAddress, 94 | }); 95 | } 96 | }); 97 | 98 | // Listen for HTTP/HTTPS conncections on port 3000 99 | httpServer.listen(PORT); 100 | 101 | console.log('Server running on port', PORT, '...'); 102 | //console.log('Try http://' + os.hostname() + '.local:' + PORT + '/'); // note: hostname is not reachable on EEMI LAN 103 | -------------------------------------------------------------------------------- /exercices/14-ajax2/solution/jsbin.yisari.2.html: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |

Connexion: 21 |

22 | Sign out 23 |

24 |

Twittez:

25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /exercices/14-ajax2/squelette/jsbin.bucilir.6.html: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |

Connexion: 21 |

22 | Sign out 23 |

24 |

Twittez:

25 | 26 | 27 | 28 |
29 | 30 | 31 |
32 | 33 | 34 | 35 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /exercices/2-solutions/1-fizzbuzz.js: -------------------------------------------------------------------------------- 1 | // fonctions fournies dans l'énoncé 2 | 3 | function estMultipleDeTrois(nombre) { 4 | return nombre % 3 === 0; 5 | } 6 | function estMultipleDeCinq(nombre) { 7 | return nombre % 5 === 0; 8 | } 9 | 10 | // algorithme "fizzbuzz": 11 | 12 | for(var i = 1; i < 200; i++) { 13 | if (estMultipleDeCinq(i) && estMultipleDeTrois(i)) { 14 | console.log('FizzBuzz'); 15 | } else if (estMultipleDeTrois(i)) { 16 | console.log('Fizz'); 17 | } else if (estMultipleDeCinq(i)) { 18 | console.log('Buzz'); 19 | } else { 20 | console.log(i); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /exercices/2-solutions/2-devine.js: -------------------------------------------------------------------------------- 1 | var nbTours = 10; 2 | 3 | var aleatoire = Math.round(Math.random() * 100); 4 | console.log('nombre à trouver:', aleatoire); 5 | 6 | for (var i = 0; i < nbTours; ++i) { 7 | var joueur = prompt('devinez le nombre'); 8 | if (joueur > aleatoire) { 9 | alert('Plus petit'); 10 | } else if (joueur < aleatoire) { 11 | alert('Plus grand'); 12 | } else if (joueur == aleatoire) { 13 | alert('Bravo !'); 14 | break; // sort de la boucle avant la fin 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /exercices/2-solutions/3-fonctions.js: -------------------------------------------------------------------------------- 1 | function diviserParDeux (nombre) { 2 | return nombre / 2; 3 | } 4 | 5 | function somme (nombre1, nombre2) { 6 | return nombre1 + nombre2; 7 | } 8 | 9 | function signe (nombre) { 10 | if (nombre === 0) { 11 | return 'nul'; 12 | } else if (nombre > 0) { 13 | return 'positif'; 14 | } else if (nombre < 0) { 15 | return 'négatif'; 16 | } 17 | } 18 | 19 | function factorielle (nombre) { 20 | var res = 1; 21 | for(var i = 1; i <= nombre; i++) { 22 | res = i * res; 23 | } 24 | return res; 25 | } 26 | -------------------------------------------------------------------------------- /exercices/2-solutions/4-chifoumi-phase-1.js: -------------------------------------------------------------------------------- 1 | // definition de la fonction comparer 2 | // qui renvoie le nom de l'élément gagnant, entre les deux passés en paramètres 3 | function comparer(choix1, choix2) { 4 | if (choix1 === choix2) { 5 | return 'Egalité !'; 6 | } else if (choix1 === 'pierre') { 7 | if (choix2 === 'ciseaux') { 8 | return 'pierre'; 9 | } else if (choix2 === 'feuille') { 10 | return 'feuille'; 11 | } 12 | } else if (choix1 === 'feuille') { 13 | if (choix2 === 'pierre') { 14 | return 'feuille'; 15 | } else if (choix2 === 'ciseaux') { 16 | return 'ciseaux'; 17 | } 18 | } else if (choix1 === 'ciseaux') { 19 | if (choix2 === 'pierre') { 20 | return 'pierre'; 21 | } else if (choix2 === 'feuille') { 22 | return 'ciseaux'; 23 | } 24 | } 25 | } 26 | 27 | // début de partie 28 | 29 | var choixUtilisateur = prompt('Choisissez-vous pierre, feuille, ou ciseaux ?'); 30 | 31 | var choixOrdi = Math.random(); 32 | if (choixOrdi < 0.34) { 33 | choixOrdi = 'pierre'; 34 | } else if(choixOrdi <= 0.67) { 35 | choixOrdi = 'feuille'; 36 | } else { 37 | choixOrdi = 'ciseaux'; 38 | } 39 | 40 | console.log('Ordinateur:', choixOrdi); 41 | 42 | var resultat = comparer(choixUtilisateur, choixOrdi); 43 | 44 | console.log('=> Gagnant:', resultat); 45 | 46 | -------------------------------------------------------------------------------- /exercices/2-solutions/4-chifoumi-phase-2.js: -------------------------------------------------------------------------------- 1 | // definition de la fonction comparer 2 | // qui renvoie le nom de l'élément gagnant, entre les deux passés en paramètres 3 | 4 | function comparer(choix1, choix2) { 5 | if (choix1 === choix2) { 6 | return 'Egalité !'; 7 | } else if (choix1 === 'pierre') { 8 | if (choix2 === 'ciseaux') { 9 | return 'pierre'; 10 | } else if (choix2 === 'feuille') { 11 | return 'feuille'; 12 | } 13 | } else if (choix1 === 'feuille') { 14 | if (choix2 === 'pierre') { 15 | return 'feuille'; 16 | } else if (choix2 === 'ciseaux') { 17 | return 'ciseaux'; 18 | } 19 | } else if (choix1 === 'ciseaux') { 20 | if (choix2 === 'pierre') { 21 | return 'pierre'; 22 | } else if (choix2 === 'feuille') { 23 | return 'ciseaux'; 24 | } 25 | } 26 | } 27 | 28 | // début de partie 29 | 30 | var scoreOrdi = 0; 31 | var scoreJoueur = 0; 32 | 33 | for (var manche = 0; manche < 3; manche++) { 34 | 35 | // choix aléatoire de l'ordinateur 36 | 37 | var choixOrdi = Math.random(); 38 | if (choixOrdi < 0.34) { 39 | choixOrdi = 'pierre'; 40 | } else if(choixOrdi <= 0.67) { 41 | choixOrdi = 'feuille'; 42 | } else { 43 | choixOrdi = 'ciseaux'; 44 | } 45 | 46 | console.log('Ordinateur:', choixOrdi); 47 | 48 | // choix du joueur 49 | 50 | var choixUtilisateur = prompt('Choisissez-vous pierre, feuille, ou ciseaux ?'); 51 | 52 | // déterminer qui remporte la manche 53 | 54 | var resultat = comparer(choixUtilisateur, choixOrdi); 55 | 56 | // afficher les résultats de la manche, et mettre à jour les scores 57 | 58 | if (resultat === 'Egalité !') { 59 | console.log('=> Egalité !'); 60 | } else if (resultat === choixUtilisateur) { 61 | console.log('=> Gagnant de la manche:', resultat, '(joueur)'); 62 | scoreJoueur++; 63 | } else { 64 | console.log('=> Gagnant de la manche:', resultat, '(ordi)'); 65 | scoreOrdi++; 66 | } 67 | 68 | } 69 | 70 | // afficher les résultats du jeu 71 | 72 | var message; 73 | if (scoreOrdi === scoreJoueur) { 74 | message = 'Égalité !'; 75 | } else if (scoreOrdi > scoreJoueur) { 76 | message = 'Perdu !'; 77 | } else { 78 | message = 'Gagné !'; 79 | } 80 | 81 | alert(message + ' Votre score: ' + scoreJoueur + ', ordi: ' + scoreOrdi); 82 | -------------------------------------------------------------------------------- /exercices/3-solutions/1-calendrier.js: -------------------------------------------------------------------------------- 1 | var jours = [ 'lun', '007', 'mer', 'jeu', 'ven', 'sam', 'BUG' ]; 2 | jours.pop(); 3 | console.log(jours); 4 | jours.push('dim'); 5 | jours[1] = 'mar'; 6 | console.log(jours.length); 7 | console.log(jours[2]); 8 | -------------------------------------------------------------------------------- /exercices/3-solutions/2-epicerie.js: -------------------------------------------------------------------------------- 1 | var fruits = [ 'Mangue', 'Raisin', 'Figue', 'Kiwi' ]; 2 | console.log(fruits); 3 | var reponse = prompt('quel fruit desirez vous'); 4 | var indice = fruits.indexOf(reponse); 5 | if (indice !== -1) { 6 | fruits.splice(indice, 1); 7 | console.log('ok!'); 8 | } else { 9 | alert('indisponible...'); 10 | } 11 | console.log(fruits); 12 | -------------------------------------------------------------------------------- /exercices/3-solutions/3-pendu-bonus.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var MAX_TENTATIVES = 10; 4 | var mauvaisesLettres = [ ]; // sera complété pendant le jeu 5 | var lettresAttendues = [ 'a', 'n', 'n', 'a' ]; 6 | 7 | for (; mauvaisesLettres.length < MAX_TENTATIVES && lettresAttendues.length > 0; ) { 8 | console.log('lettres à trouver:', lettresAttendues); 9 | alert('Lettres à trouver: ' + lettresAttendues.length + '. ' 10 | + 'Tentatives restantes: ' + (MAX_TENTATIVES - mauvaisesLettres.length)); 11 | var lettre = prompt('Devinez une lettre'); 12 | 13 | // tant qu'on trouve des occurrences, on continue de les supprimer une à une 14 | var trouvees = 0; 15 | for (var indice = 0; indice != -1 ;) { 16 | indice = lettresAttendues.indexOf(lettre); // cherche la prochaine occurrence de la lettre 17 | if (indice != -1) { 18 | lettresAttendues.splice(indice, 1); // retire cette occurrence de la lettre trouvée dans le tableau 19 | trouvees++; 20 | } 21 | } 22 | 23 | if (trouvees > 0) { 24 | alert('Bonne pioche ! Il y avait bien ' + trouvees + ' fois la lettre ' 25 | + lettre + ' dans le mot à trouver !'); 26 | } else { 27 | mauvaisesLettres.push(lettre); 28 | alert('Le mot à trouver ne contient pas la lettre ' + lettre + ', désolé...'); 29 | } 30 | } 31 | 32 | if (lettresAttendues.length == 0) { 33 | alert('Bravo, vous avez trouvé le mot !'); 34 | } else if (mauvaisesLettres.length == MAX_TENTATIVES) { 35 | alert('Perdu... Faites une autre partie !'); 36 | } 37 | -------------------------------------------------------------------------------- /exercices/3-solutions/3-pendu.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var MAX_TENTATIVES = 10; 4 | var mauvaisesLettres = [ ]; // sera complété pendant le jeu 5 | var lettresAttendues = [ 's', 'u', 'p', 'e', 'r' ]; 6 | 7 | for (; mauvaisesLettres.length < MAX_TENTATIVES && lettresAttendues.length > 0; ) { 8 | console.log('lettres à trouver:', lettresAttendues); 9 | alert('Lettres à trouver: ' + lettresAttendues.length + '. ' 10 | + 'Tentatives restantes: ' + (MAX_TENTATIVES - mauvaisesLettres.length)); 11 | var lettre = prompt('Devinez une lettre'); 12 | var indice = lettresAttendues.indexOf(lettre); 13 | if (indice != -1) { 14 | lettresAttendues.splice(indice, 1); // retire la 1ère occurrence de cette lettre trouvée dans le tableau 15 | alert('Bonne pioche! Continuez!'); 16 | } else { 17 | mauvaisesLettres.push(lettre); 18 | alert('Le mot à trouver ne contient pas la lettre ' + lettre + ', désolé...'); 19 | } 20 | } 21 | 22 | if (lettresAttendues.length == 0) { 23 | alert('Bravo, vous avez trouvé le mot !'); 24 | } else if (mauvaisesLettres.length == MAX_TENTATIVES) { 25 | alert('Perdu... Faites une autre partie !'); 26 | } 27 | -------------------------------------------------------------------------------- /exercices/3-solutions/4-annuaire.js: -------------------------------------------------------------------------------- 1 | var annuaire = { 2 | patricia: '06 66 66 66 66', 3 | david: '07 77 77 77 77', 4 | }; 5 | 6 | // 1. Afficher dans la console le numéro de téléphone de `patricia`, en utilisant la notation pointée sur l'objet `annuaire`; 7 | 8 | console.log(annuaire.patricia); 9 | 10 | // 2. Demander à l'utilisateur de saisir un prénom, puis afficher le numéro de téléphone associé à ce prénom. 11 | 12 | var nom = prompt('donner le nom d\'un ami'); 13 | alert('numéro de téléphone de ' + nom + ': ' + annuaire[nom]); 14 | -------------------------------------------------------------------------------- /exercices/3-solutions/5-repertoire.js: -------------------------------------------------------------------------------- 1 | var repertoire = { 2 | 'luke' : '0666666666', 3 | 'yoda' : '0688888888', 4 | }; 5 | 6 | // non demandé dans l'énoncé, juste pour vérifier le bon fonctionnement dans la console: 7 | console.log('[debug] repertoire:', repertoire); 8 | 9 | // l'utilisateur peut effectuer plusieurs opération, jusqu'à ce qu'il presse `q` 10 | for (var choix; choix != 'q';) { 11 | choix = prompt('fonction: (r)echerche, (l)iste, (a)jout, (s)uppression, ou (q)uitter ?'); 12 | if (choix === 'r') { 13 | var nom = prompt('donner le nom d\'un ami'); 14 | alert('numéro associé: ' + repertoire[nom]); 15 | } else if (choix === 'l') { 16 | for (var nom in repertoire) { 17 | console.log(nom, ':', repertoire[nom]); 18 | } 19 | } else if (choix === 'a') { 20 | var nom = prompt('donner le nom de l\'ami à ajouter'); 21 | var num = prompt('donner son numéro de téléphone'); 22 | repertoire[nom] = num; 23 | } else if (choix === 's') { 24 | var nom = prompt('donner le nom de l\'ami à supprimer du répertoire'); 25 | delete repertoire[nom]; 26 | } 27 | // non demandé dans l'énoncé, juste pour vérifier le bon fonctionnement dans la console: 28 | console.log('[debug] repertoire:', repertoire); 29 | } 30 | -------------------------------------------------------------------------------- /exercices/4-solutions/JS-FORM-1/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

Bonjour !

5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /exercices/4-solutions/JS-FORM-1/index.js: -------------------------------------------------------------------------------- 1 | alert(document.getElementById('nom').value); 2 | alert(document.getElementById('prenom').value); 3 | -------------------------------------------------------------------------------- /exercices/4-solutions/bonjour.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

Bonjour !

5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /exercices/4-solutions/bonjour.js: -------------------------------------------------------------------------------- 1 | alert('Bonjour le monde !'); 2 | -------------------------------------------------------------------------------- /exercices/4-solutions/calculatrice-bonus/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

Calculatrice

5 | 6 |

premier nombre:

7 | 8 | 9 |

opération:

10 | 16 | 17 |

deuxieme nombre:

18 | 19 | 20 | 21 | 22 |

résultat:

23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /exercices/4-solutions/calculatrice-bonus/index.js: -------------------------------------------------------------------------------- 1 | document.getElementById('mon-bouton').onclick = function() { 2 | var nombre1 = parseInt(document.getElementById('premier-nombre').value); 3 | var nombre2 = parseInt(document.getElementById('deuxieme-nombre').value); 4 | var operation = document.getElementById('operation').value; 5 | var result; 6 | if (operation === '-') { 7 | result = nombre1 - nombre2; 8 | } else if (operation === '*') { 9 | result = nombre1 * nombre2; 10 | } else if (operation === '/') { 11 | result = nombre1 / nombre2; 12 | } else { 13 | result = nombre1 + nombre2; 14 | } 15 | document.getElementById('resultat').value = result; 16 | }; 17 | -------------------------------------------------------------------------------- /exercices/4-solutions/calculatrice/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

Calculatrice

5 | 6 |

premier nombre:

7 | 8 | 9 |

deuxieme nombre:

10 | 11 | 12 | 13 | 14 |

résultat:

15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /exercices/4-solutions/calculatrice/index.js: -------------------------------------------------------------------------------- 1 | document.getElementById('mon-bouton').onclick = function() { 2 | var nombre1 = parseInt(document.getElementById('premier-nombre').value); 3 | var nombre2 = parseInt(document.getElementById('deuxieme-nombre').value); 4 | document.getElementById('resultat').value = nombre1 + nombre2; 5 | }; 6 | -------------------------------------------------------------------------------- /exercices/5-solutions/produits/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

Filtrage par catégorie

5 | 6 | 7 | 8 | 9 | 10 | 11 |
iPad
12 |
Batte de baseball
13 |
Ventilateur
14 |
XBox
15 |
Gants de golf
16 |
Porte-clés
17 |
Carnet
18 |
Balle de baseball
19 |
Boules de pétanque
20 |
Yoyo
21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /exercices/5-solutions/produits/index.js: -------------------------------------------------------------------------------- 1 | function changerDisplay(classe, valeur) { 2 | var articles = document.getElementsByClassName(classe); 3 | for (var i=0; i 2 | 3 | 4 | 5 | 6 | 7 | 8 |

Composant "accordéon"

9 | 10 |

Description

11 | 12 | Ce composant permet d'afficher une liste de dépêches, et de permettre à l'utilisateur d'afficher le contenu d'une seule dépêche à la fois, en cliquant sur son titre. 13 | 14 |

Exemple d'intégration

15 | 16 |
17 |
18 |
Le programme de Donald Trump
19 |
La durée de vie d'un décret est par ailleurs limitée: un président donc abroger un décret d'un prédécesseur, comme l'a fait Donald Trump en annulant plusieurs textes signés par Barack Obama, sur les projets d'oléoducs Keystone ou sur le financement ...
20 |
21 |
22 |
Donald Trump accuse les juges...
23 |
Dire que Donald Trump a peu apprécié le blocage de son décret anti-immigration par un juge fédéral est un euphémisme. Samedi 4 février, il l'a désigné à la vindicte des 23 millions d'abonnés de son compte Twitter, le qualifiant de « soi-disant juge ...
24 |
25 |
26 |
Donald Trump rencontrera ses alliés de l'Otan
27 |
En mai aura lieu une rencontre entre Donald Trump et ses alliés de l'Otan, a annoncé dimanche la Maison Blanche, après un entretien téléphonique entre le président américain et le secrétaire général de l'Alliance atlantique Jens Stoltenberg. Donald ...
28 |
29 |
30 | 31 |

Instructions d'intégration

32 | 33 |
    34 |
  1. Structurez chaque dépêche dans un élément <section>, contenant son titre dans un sous-élément <header>, et son contenu associé dans un sous-élément <article>, de la manière suivante: 35 | 36 | <div class="accordeon"> 37 | <section> 38 | <header>Titre 1</header> 39 | <article>Texte 1</article> 40 | </section> 41 | <section> 42 | <header>Titre 2</header> 43 | <article>Texte 2</article> 44 | </section> 45 | <section> 46 | <header>Titre 3</header> 47 | <article>Texte 3</article> 48 | </section> 49 | </div> 50 | 51 |
  2. 52 |
  3. Ajoutez les dépendances suivantes à votre page: 53 | 54 | <link rel="stylesheet" href="https://adrienjoly.com/cours-javascript/exercices/10-composants/lib/accordeon.css"> 55 | <script src="https://adrienjoly.com/cours-javascript/exercices/10-composants/lib/accordeon.js"></script> 56 | 57 |
  4. 58 |
  5. Vous pouvez intégrer plusieurs accordéons sur votre page, il suffit de regrouper vos dépêches dans des <div> séparés portant chacun la classe accordeon. 59 |
60 | 61 |

Code source du composant

62 | 63 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /exercices/6-solutions/accordeon-v2-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

Intégration 1

10 | 11 |
12 |
13 |
Le programme de Donald Trump
14 |
La durée de vie d'un décret est par ailleurs limitée: un président donc abroger un décret d'un prédécesseur, comme l'a fait Donald Trump en annulant plusieurs textes signés par Barack Obama, sur les projets d'oléoducs Keystone ou sur le financement ...
15 |
16 |
17 |
Donald Trump accuse les juges...
18 |
Dire que Donald Trump a peu apprécié le blocage de son décret anti-immigration par un juge fédéral est un euphémisme. Samedi 4 février, il l'a désigné à la vindicte des 23 millions d'abonnés de son compte Twitter, le qualifiant de « soi-disant juge ...
19 |
20 |
21 |
Donald Trump rencontrera ses alliés de l'Otan
22 |
En mai aura lieu une rencontre entre Donald Trump et ses alliés de l'Otan, a annoncé dimanche la Maison Blanche, après un entretien téléphonique entre le président américain et le secrétaire général de l'Alliance atlantique Jens Stoltenberg. Donald ...
23 |
24 |
25 | 26 |

Intégration 2

27 | 28 |
29 |
30 |
Titre 1
31 |
Texte 1
32 |
33 |
34 |
Titre 2
35 |
Texte 2
36 |
37 |
38 |
Titre 3
39 |
Texte 3
40 |
41 |
42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /exercices/6-solutions/accordeon-v2.css: -------------------------------------------------------------------------------- 1 | .accordeon header { 2 | background: black; 3 | color: white; 4 | } 5 | 6 | .accordeon article { 7 | display: none; 8 | background: white; 9 | color: black; 10 | } 11 | 12 | .accordeon article.visible { 13 | display: block; 14 | } 15 | -------------------------------------------------------------------------------- /exercices/6-solutions/accordeon-v2.js: -------------------------------------------------------------------------------- 1 | function initialiseAccordeon(element) { 2 | 3 | // ces variables auront une valeur différente pour chaque appel de initialiseAccordeon() 4 | var headers = element.getElementsByTagName('header'); 5 | var articles = element.getElementsByTagName('article'); 6 | 7 | // cette fonction affiche le i-ème article de cet accordéon 8 | function afficherArticle(i) { 9 | articles[i].classList.add('visible'); 10 | } 11 | 12 | // cette fonction cache tous les articles de cet accordéon 13 | function cacherArticles() { 14 | for (var i = 0; i < articles.length; i++) { 15 | articles[i].classList.remove('visible'); 16 | } 17 | } 18 | 19 | // cette fonction retourne une fonction qui sert à n'afficher que l'i-ème article 20 | function pourAfficherArticle(i) { 21 | return function(){ 22 | cacherArticles(); 23 | afficherArticle(i); 24 | }; 25 | } 26 | 27 | // initialisation des headers 28 | for (var i = 0; i < headers.length; i++) { 29 | headers[i].onclick = pourAfficherArticle(i); 30 | } 31 | 32 | } 33 | 34 | // intégration des accordéons de la page 35 | var accordeons = document.getElementsByClassName('accordeon'); 36 | for (var i = 0; i < accordeons.length; i++) { 37 | initialiseAccordeon(accordeons[i]); 38 | } 39 | -------------------------------------------------------------------------------- /exercices/6-solutions/accordeon.css: -------------------------------------------------------------------------------- 1 | header { 2 | background: black; 3 | color: white; 4 | } 5 | 6 | article { 7 | display: none; 8 | background: white; 9 | color: black; 10 | } 11 | 12 | article.visible { 13 | display: block; 14 | } 15 | -------------------------------------------------------------------------------- /exercices/6-solutions/accordeon.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |
Le programme de Donald Trump
10 |
La durée de vie d'un décret est par ailleurs limitée: un président donc abroger un décret d'un prédécesseur, comme l'a fait Donald Trump en annulant plusieurs textes signés par Barack Obama, sur les projets d'oléoducs Keystone ou sur le financement ...
11 |
12 |
13 |
Donald Trump accuse les juges...
14 |
Dire que Donald Trump a peu apprécié le blocage de son décret anti-immigration par un juge fédéral est un euphémisme. Samedi 4 février, il l'a désigné à la vindicte des 23 millions d'abonnés de son compte Twitter, le qualifiant de « soi-disant juge ...
15 |
16 |
17 |
Donald Trump rencontrera ses alliés de l'Otan
18 |
En mai aura lieu une rencontre entre Donald Trump et ses alliés de l'Otan, a annoncé dimanche la Maison Blanche, après un entretien téléphonique entre le président américain et le secrétaire général de l'Alliance atlantique Jens Stoltenberg. Donald ...
19 |
20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /exercices/6-solutions/accordeon.js: -------------------------------------------------------------------------------- 1 | var headers = document.getElementsByTagName('header'); 2 | var articles = document.getElementsByTagName('article'); 3 | 4 | // cette fonction affiche le i-ème article 5 | function afficherArticle(i) { 6 | articles[i].classList.add('visible'); 7 | } 8 | 9 | // cette fonction cache tous les articles 10 | function cacherArticles() { 11 | for (var i = 0; i < articles.length; i++) { 12 | articles[i].classList.remove('visible'); 13 | } 14 | } 15 | 16 | // cette fonction retourne une fonction qui sert à n'afficher que l'i-ème article 17 | function pourAfficherArticle(i) { 18 | return function(){ 19 | cacherArticles(); 20 | afficherArticle(i); 21 | }; 22 | } 23 | 24 | // initialisation des headers 25 | for (var i = 0; i < headers.length; i++) { 26 | headers[i].onclick = pourAfficherArticle(i); 27 | } 28 | -------------------------------------------------------------------------------- /exercices/6-solutions/carousel-v2-doc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Composant "Carousel"

11 | 12 |

Description

13 | 14 | Ce composant permet à l'utilisateur de naviguer parmi une liste d'images, une par une. 15 | 16 |

Exemple d'intégration

17 | 18 | 24 | 25 |

Instructions d'intégration

26 | 27 |
    28 | 29 |
  1. Insérez vos images dans votre page à l'aide d'éléments <img>, ajoutez un élément <button> portant la classe next, et placez tous ces éléments à l'intérieur d'un élément portant la classe carousel, de la manière suivante: 30 | 31 | <div class="carousel"> 32 | <button class="next">Image suivante</button> 33 | <img src="http://lorempixel.com/output/food-q-c-640-480-1.jpg"> 34 | <img src="http://lorempixel.com/output/food-q-c-640-480-2.jpg"> 35 | <img src="http://lorempixel.com/output/food-q-c-640-480-3.jpg"> 36 | </div> 37 | 38 |
  2. 39 | 40 |
  3. Ajoutez les dépendances suivantes à votre page: 41 | 42 | <link rel="stylesheet" href="https://adrienjoly.com/cours-javascript/exercices/10-composants/lib/carousel.css"> 43 | <script src="https://adrienjoly.com/cours-javascript/exercices/10-composants/lib/carousel.js"></script> 44 | 45 |
  4. 46 | 47 |
  5. Vous pouvez intégrer plusieurs Carousels sur votre page, il suffit que chaque galerie d'images de votre page soit regroupée dans un élément portant la classe carousel, au moment où la dépendance carousel.js sera chargée. 48 |
  6. 49 | 50 |
51 | 52 |

Code source du composant

53 | 54 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /exercices/6-solutions/carousel-v2.css: -------------------------------------------------------------------------------- 1 | .carousel { 2 | position: relative; 3 | width: 300px; 4 | height: 200px; 5 | overflow: hidden; 6 | } 7 | 8 | .carousel img { 9 | display: none; 10 | position: absolute; 11 | width: 100%; 12 | height: 100%; 13 | } 14 | 15 | .carousel img.visible { 16 | display: block; 17 | } 18 | -------------------------------------------------------------------------------- /exercices/6-solutions/carousel-v2.js: -------------------------------------------------------------------------------- 1 | function initialiseCarousel(groupe) { 2 | 3 | var images = groupe.getElementsByTagName('img'); 4 | var imageVisible = 0; 5 | 6 | // cette fonction affiche l'image suivante, et cache la précédente 7 | function changerImage() { 8 | images[imageVisible].classList.remove('visible'); 9 | imageVisible = (imageVisible + 1) % images.length; 10 | images[imageVisible].classList.add('visible'); 11 | } 12 | 13 | groupe.getElementsByClassName('next')[0].onclick = changerImage; 14 | 15 | changerImage(); 16 | } 17 | 18 | var carousels = document.getElementsByClassName('carousel'); 19 | for (var i = 0; i < carousels.length; i++) { 20 | initialiseCarousel(carousels[i]); 21 | } 22 | -------------------------------------------------------------------------------- /exercices/6-solutions/carousel.css: -------------------------------------------------------------------------------- 1 | #carousel { 2 | position: relative; 3 | width: 300px; 4 | height: 200px; 5 | overflow: hidden; 6 | } 7 | 8 | .carousel-img { 9 | display: none; 10 | position: absolute; 11 | min-width: 100%; 12 | min-height: 100%; 13 | } 14 | 15 | .carousel-img.visible { 16 | display: block; 17 | } 18 | -------------------------------------------------------------------------------- /exercices/6-solutions/carousel.js: -------------------------------------------------------------------------------- 1 | //var carousel = document.getElementById('carousel'); 2 | var images = document.getElementsByClassName('carousel-img'); 3 | 4 | var imageVisible = 0; 5 | 6 | // cette fonction affiche l'image suivante, et cache la précédente 7 | function changerImage() { 8 | images[imageVisible].classList.remove('visible'); 9 | imageVisible = (imageVisible + 1) % images.length; 10 | images[imageVisible].classList.add('visible'); 11 | } 12 | 13 | document.getElementById('next').onclick = changerImage; 14 | 15 | changerImage(); 16 | -------------------------------------------------------------------------------- /exercices/6-solutions/videos-v2-doc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Composant "Galerie Vidéo"

11 | 12 |

Description

13 | 14 | Ce composant permet à l'utilisateur de regarder une sélection de vidéos Youtube. 15 | 16 |

Exemple d'intégration

17 | 18 |
19 |
20 | 21 | 22 | 23 | 30 | 31 |

Instructions d'intégration

32 | 33 |
    34 | 35 |
  1. Ajoutez les dépendances suivantes à votre page: 36 | 37 | <link rel="stylesheet" href="https://adrienjoly.com/cours-javascript/exercices/10-composants/lib/videos.css"> 38 | <script src="https://adrienjoly.com/cours-javascript/exercices/10-composants/lib/videos.js"></script> 39 | 40 |
  2. 41 | 42 |
  3. Puis, pour chaque galerie vidéo à intégrer sur votre page, il vous suffira d'intégrer un élément <div>, puis d'appeler la fonction initialiseGalerieVideo() en passant en paramètres une référence de cet élément, et un tableau d'URLs de vidéos Youtube sous la forme https://www.youtube.com/embed/0uaQMxBjd5E. (cf documentation d'API ci-dessous) 43 |
  4. 44 | 45 |
46 | 47 |

API du composant

48 | 49 |

Fonction initialiseGalerieVideo(conteneur, videos)

50 | 51 |

Cette fonction permet d'intégrer une galerie vidéo à l'intérieur de l'élément conteneur (qui doit exister dans la page au moment de l'appel).

52 | 53 |

Au moment de l'appel, la fonction va ajouter un bouton par vidéo, afin de permettre à l'utilisateur de choisir la vidéo à consulter.

54 | 55 |

Paramètres:

56 |
    57 |
  • conteneur: référence d'élément du DOM HTML de la page
  • 58 |
  • videos: tableau de chaînes de caractères sous la forme https://www.youtube.com/embed/0uaQMxBjd5E
  • 59 |
60 | 61 |

Code source du composant

62 | 63 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /exercices/6-solutions/videos-v2-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Intégration 1

11 |
12 |
13 | 14 |

Intégration 2

15 |
16 |
17 | 18 | 19 | 20 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /exercices/6-solutions/videos-v2.css: -------------------------------------------------------------------------------- 1 | .video { 2 | width: 300px; 3 | height: 200px; 4 | background: black; 5 | } 6 | -------------------------------------------------------------------------------- /exercices/6-solutions/videos-v2.js: -------------------------------------------------------------------------------- 1 | function initialiseGalerieVideo(conteneur, videos) { 2 | 3 | // insertion du div de la video en cours 4 | conteneur.innerHTML = '
'; 5 | 6 | // insertion des boutons 7 | for (var i = 0; i < videos.length; i++) { 8 | conteneur.innerHTML += ''; 9 | } 10 | 11 | // références vers le DOM 12 | var video = conteneur.getElementsByClassName('video')[0]; 13 | var buttons = conteneur.getElementsByTagName('button'); 14 | 15 | // fonction qui retourne une fonction permettant d'intégrer la i-ème vidéo 16 | function pourAfficherVideo(i) { 17 | return function() { 18 | video.innerHTML = '' 19 | }; 20 | } 21 | 22 | // initialisation des boutons 23 | for (var i = 0; i < buttons.length; i++) { 24 | buttons[i].onclick = pourAfficherVideo(i); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /exercices/6-solutions/videos.css: -------------------------------------------------------------------------------- 1 | #video { 2 | width: 300px; 3 | height: 200px; 4 | background: black; 5 | } 6 | -------------------------------------------------------------------------------- /exercices/6-solutions/videos.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /exercices/6-solutions/videos.js: -------------------------------------------------------------------------------- 1 | // URL d'intégration de chaque vidéo Youtube 2 | var videos = [ 3 | 'https://www.youtube.com/embed/0uaQMxBjd5E', 4 | 'https://www.youtube.com/embed/c8ZPn6p5khI', 5 | 'https://www.youtube.com/embed/ikkrEOD1BbQ', 6 | ]; 7 | 8 | // références vers le DOM 9 | var video = document.getElementById('video'); 10 | var buttons = document.getElementsByTagName('button'); 11 | 12 | // fonction qui retourne une fonction permettant d'intégrer la i-ème vidéo 13 | function pourAfficherVideo(i) { 14 | return function() { 15 | video.innerHTML = '' 16 | }; 17 | } 18 | 19 | // initialisation des boutons 20 | for (var i = 0; i < buttons.length; i++) { 21 | buttons[i].onclick = pourAfficherVideo(i); 22 | } 23 | -------------------------------------------------------------------------------- /exercices/8-solutions/ajax-get-images-flickr.html: -------------------------------------------------------------------------------- 1 |

Recherche d'images

2 | 3 | 4 |
    5 | 6 | 32 | -------------------------------------------------------------------------------- /exercices/8-solutions/ajax-get-images-giphy.html: -------------------------------------------------------------------------------- 1 |

    Recherche d'animations

    2 | 3 | 4 |
      5 | 6 | 32 | -------------------------------------------------------------------------------- /exercices/8-solutions/ajax-get-ip.js: -------------------------------------------------------------------------------- 1 | var xhr = new XMLHttpRequest(); 2 | xhr.open('GET', 'https://httpbin.org/ip'); 3 | xhr.onreadystatechange = function() { 4 | if (xhr.readyState === 4) { 5 | console.log('réponse du serveur:', xhr.responseText); 6 | var objet = JSON.parse(xhr.responseText); 7 | alert(objet.origin); 8 | } 9 | }; 10 | xhr.send(); 11 | -------------------------------------------------------------------------------- /exercices/8-solutions/ajax-get-time.js: -------------------------------------------------------------------------------- 1 | var xhr = new XMLHttpRequest(); 2 | xhr.open('GET', 'http://time.jsontest.com'); 3 | xhr.onreadystatechange = function() { 4 | if (xhr.readyState === 4) { 5 | console.log('réponse du serveur:', xhr.responseText); 6 | var objet = JSON.parse(xhr.responseText); 7 | alert(objet.time); 8 | } 9 | }; 10 | xhr.send(); 11 | -------------------------------------------------------------------------------- /exercices/8-solutions/ajax-get-weather.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

      Météo

      6 | 7 | 8 |
      9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /exercices/8-solutions/ajax-get-weather.js: -------------------------------------------------------------------------------- 1 | // 0. Clé API générée depuis https://home.openweathermap.org/api_keys 2 | var API_KEY = 'd1ffc9be1384dd411ba612942d571977'; 3 | 4 | var champ = document.getElementById('ville'); 5 | var meteo = document.getElementById('meteo'); 6 | 7 | document.getElementById('bouton').onclick = function() { 8 | 9 | // 1. génération de l'URL en fonction de la saisie 10 | var url = 'http://api.openweathermap.org/data/2.5/weather?q=' 11 | + encodeURIComponent(champ.value) // conversion des caractères spéciaux 12 | + '&appid=' + API_KEY; 13 | console.log('ajax request url:', url); 14 | 15 | // 2. initialisation de la requête AJAX 16 | var xhr = new XMLHttpRequest(); 17 | xhr.open('GET', url); 18 | xhr.onreadystatechange = function() { 19 | if (xhr.readyState === 4) { 20 | // 4. traitement de la réponse du serveur à la requête 21 | console.log(xhr.responseText); 22 | var objet = JSON.parse(xhr.responseText); 23 | meteo.innerHTML = 'Weather: ' + objet.weather[0].main; 24 | } 25 | }; 26 | // 3. envoi de la requête AJAX 27 | xhr.send(); 28 | 29 | }; 30 | -------------------------------------------------------------------------------- /exercices/8-solutions/ajax-post-twitter.html: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |

      Connexion: 21 |

      22 | Sign out 23 |

      24 |

      Twittez:

      25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /exercices/9-code/jsbin.haxeqad.2.html: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 29 | 30 | 31 | 32 |
      33 | [[ Insérer bouton de connexion ici ]] 34 |
      35 | 36 |
      37 |

      Bonjour,

      38 | [[ Insérer bouton de déconnexion ici ]] 39 |
      40 | 41 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /exercices/9-code/jsbin.tuyofec.5.html: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 31 | 32 | 33 | 34 |
      35 |
      36 |
      37 | 38 |
      39 |

      Bonjour,

      40 |
      42 | 43 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/icon.png -------------------------------------------------------------------------------- /img/4-1-accordion.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/4-1-accordion.gif -------------------------------------------------------------------------------- /img/4-2-carousel.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/4-2-carousel.gif -------------------------------------------------------------------------------- /img/4-3-videos.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/4-3-videos.gif -------------------------------------------------------------------------------- /img/apple-calculator-landscape.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/apple-calculator-landscape.jpg -------------------------------------------------------------------------------- /img/arbre-decision.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/arbre-decision.png -------------------------------------------------------------------------------- /img/buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/buttons.png -------------------------------------------------------------------------------- /img/categories.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/categories.gif -------------------------------------------------------------------------------- /img/chrome-console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/chrome-console.png -------------------------------------------------------------------------------- /img/composant-multi-avec-api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/composant-multi-avec-api.png -------------------------------------------------------------------------------- /img/composant-multi-groupe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/composant-multi-groupe.png -------------------------------------------------------------------------------- /img/cookbook.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/cookbook.gif -------------------------------------------------------------------------------- /img/doesnotcompute.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/doesnotcompute.jpg -------------------------------------------------------------------------------- /img/error-oper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/error-oper.png -------------------------------------------------------------------------------- /img/error-prog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/error-prog.png -------------------------------------------------------------------------------- /img/geoloc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/geoloc.gif -------------------------------------------------------------------------------- /img/isnotjava.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/isnotjava.png -------------------------------------------------------------------------------- /img/jsconsole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/jsconsole.png -------------------------------------------------------------------------------- /img/netscape.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/netscape.jpg -------------------------------------------------------------------------------- /img/screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/img/screenshot.jpg -------------------------------------------------------------------------------- /js-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/js-logo.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cours-javascript", 3 | "version": "3.0.0", 4 | "scripts": { 5 | "start-http": "python -m SimpleHTTPServer", 6 | "gitbook:preinstall": "# brew install Caskroom/cask/calibre", 7 | "gitbook:postinstall": "./node_modules/.bin/gitbook install", 8 | "gitbook:gen-pdf": "node_modules/.bin/gitbook pdf ./ ./_book/cours-javascript.pdf", 9 | "gitbook:build": "node_modules/.bin/gitbook build", 10 | "gitbook:deploy": "git push gitbook master", 11 | "gitbook:start": "node_modules/.bin/gitbook serve", 12 | "install": "gem install bundler && bundle install # requires ruby-lang.org", 13 | "build": "bundle exec jekyll build", 14 | "start": "bundle exec jekyll serve --incremental" 15 | }, 16 | "author": "Adrien Joly", 17 | "dependencies": { 18 | "gitbook-cli": "^2.3.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /qcms/js-controle-1-solutions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/qcms/js-controle-1-solutions.pdf -------------------------------------------------------------------------------- /qcms/js-controle-2-solutions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/qcms/js-controle-2-solutions.pdf -------------------------------------------------------------------------------- /qcms/js-controle-3-solutions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/qcms/js-controle-3-solutions.pdf -------------------------------------------------------------------------------- /qcms/js-partiel-1-solutions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/qcms/js-partiel-1-solutions.pdf -------------------------------------------------------------------------------- /qcms/js-test-1-solutions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/qcms/js-test-1-solutions.pdf -------------------------------------------------------------------------------- /qcms/js-test-2-solutions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/qcms/js-test-2-solutions.pdf -------------------------------------------------------------------------------- /qcms/js-test-3-solutions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/qcms/js-test-3-solutions.pdf -------------------------------------------------------------------------------- /qcms/js-test-4-solutions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/qcms/js-test-4-solutions.pdf -------------------------------------------------------------------------------- /qcms/js-test-5-solutions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/qcms/js-test-5-solutions.pdf -------------------------------------------------------------------------------- /qcms/js-test-6-solutions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/qcms/js-test-6-solutions.pdf -------------------------------------------------------------------------------- /qcms/js-test-7-solutions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/qcms/js-test-7-solutions.pdf -------------------------------------------------------------------------------- /qcms/js-test-8-solutions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/qcms/js-test-8-solutions.pdf -------------------------------------------------------------------------------- /qcms/js-test-9-solutions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/qcms/js-test-9-solutions.pdf -------------------------------------------------------------------------------- /qcms/qcm-10-solutions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/qcms/qcm-10-solutions.pdf -------------------------------------------------------------------------------- /slides/.vscode/spellchecker.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "fr", 3 | "ignoreWordsList": [ 4 | "closure", 5 | "Généricité" 6 | ], 7 | "documentTypes": [ 8 | "markdown", 9 | "latex", 10 | "plaintext" 11 | ], 12 | "ignoreRegExp": [], 13 | "ignoreFileExtensions": [], 14 | "checkInterval": 5000 15 | } -------------------------------------------------------------------------------- /slides/01-intro/img/apple-calculator-landscape.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/01-intro/img/apple-calculator-landscape.jpg -------------------------------------------------------------------------------- /slides/01-intro/img/chrome-console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/01-intro/img/chrome-console.png -------------------------------------------------------------------------------- /slides/01-intro/img/isnotjava.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/01-intro/img/isnotjava.png -------------------------------------------------------------------------------- /slides/01-intro/img/netscape.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/01-intro/img/netscape.jpg -------------------------------------------------------------------------------- /slides/01-intro/img/yoda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/01-intro/img/yoda.png -------------------------------------------------------------------------------- /slides/01-intro/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TP Slides 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /slides/02-conditions/img/arbre-decision.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/02-conditions/img/arbre-decision.png -------------------------------------------------------------------------------- /slides/02-conditions/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TP Slides 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /slides/02-conditions/slides.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # JavaScript 4 | ## 🌵 Conditions 5 | 6 | ??? 7 | 8 | Avant de commencer, interroger les étudiants sur: 9 | - quels sont les types en Javascript 10 | - comment nommer une variable 11 | - comment créer une variable 12 | - comment afficher la valeur d'une variable depuis la console 13 | - comment changer la valeur d'une variable 14 | - est-ce qu'il est possible de donner une valeur d'un autre type a une variable 15 | - comment ouvrir la console de google chrome 16 | 17 | => préciser qu'il vaut mieux ouvrir la console en mode incognito / navigation privée 18 | 19 | --- 20 | class: center, middle, dbl-size 21 | 22 | # 🎯 Objectifs 23 | 24 | - 🤖 Développer un chat-bot simple 25 | - 🌵 Conditions et comparaison de valeurs 26 | 27 | --- 28 | class: center, middle 29 | 30 | ## Ex: diagnostic médical 31 | 32 | --- 33 | class: center 34 | background-image: url(./img/arbre-decision.png) 35 | 36 | ## 🌵 Arbre de décision 37 | 38 | --- 39 | class: center, middle, dbl-size 40 | 41 | ## 🌵 ...en pseudo-code 42 | 43 | - `si` *douleur à abdomen*, `alors` **appendicite** 44 | - `sinon, si` *douleur à la gorge* `et`: 45 | - `si` *fièvre*, `alors` **rhume** 46 | - `sinon`, **mal de gorge** 47 | - 48 | - `sinon, si`... 49 | 50 | --- 51 | class: center, middle, dbl-size, dbl-line 52 | 53 | ## 🌵 ... en JavaScript 54 | 55 | ```js 56 | if (douleur === 'abdomen') { 57 | diag = 'appendicite'; 58 | } else if (douleur === 'gorge') { 59 | if (fievre === true) { 60 | diag = 'rhume'; 61 | } else { 62 | diag = 'mal de gorge'; 63 | } 64 | } 65 | ``` 66 | 67 | --- 68 | class: center, middle 69 | 70 | ## 🌵 Condition 71 | ## ⇓ 72 | ## ⚖ Comparer des valeurs 73 | 74 | --- 75 | class: center, middle, dbl-size 76 | 77 | ## ⚖ Égalité 78 | 79 | - Stricte: `===` 80 | - Laxiste: `==` 81 | 82 | -- 83 | 84 | .red-bg[ 85 | ## ⚠️ Ne pas confondre avec `=` (📥) 86 | ] 87 | 88 | --- 89 | class: center, middle, dbl-size 90 | 91 | ## ⚖ Égalité stricte VS laxiste 92 | 93 | ```js 94 | 1 == '1' 95 | 1 === '1' 96 | 0 == false 97 | 0 === false 98 | ``` 99 | 100 | -- 101 | 102 | .yellow-bg[ 103 | ## 📌️ Comportement différent sur types avancés 🆎 104 | ] 105 | 106 | --- 107 | class: center, middle, dbl-size 108 | 109 | ## ⚖ Inégalité stricte VS laxiste 110 | 111 | ```js 112 | 1 != '1' 113 | 1 !== '1' 114 | 0 != false 115 | 0 !== false 116 | ``` 117 | 118 | --- 119 | class: center, middle, dbl-size 120 | 121 | ## ⚖ Autres inégalités 122 | 123 | - strictement inférieur: `<` 124 | - strictement supérieur: `>` 125 | - inférieur ou égal: `<=` 126 | - supérieur ou égal: `>=` 127 | 128 | --- 129 | class: center, middle, dbl-size 130 | 131 | ## 🌵 Condition en JavaScript 132 | 133 | ```js 134 | if (expression) { 135 | // 136 | // instructions executées 137 | // si expression == true 138 | // 139 | } else { 140 | // 141 | // instructions exécutées 142 | // dans le cas contraire 143 | // 144 | } 145 | ``` 146 | 147 | --- 148 | class: center, middle, dbl-size, dbl-line 149 | 150 | ## 🌵 Exemple de condition 151 | 152 | ```js 153 | var monNombre = 1, resultat; 154 | if (monNombre === 1) { 155 | resultat = 'monNombre vaut 1'; 156 | } else { 157 | resultat = 'monNombre ne vaut pas 1'; 158 | } 159 | ``` 160 | 161 | ⇒ Quelle est la valeur finale de `resultat` ? 162 | 163 | --- 164 | class: center, middle, dbl-size, dbl-line 165 | 166 | ## 🌵🌵 Conditions à alternatives multiples 167 | 168 | ```js 169 | if (monNombre === 1) { 170 | resultat = 'monNombre vaut 1'; 171 | } else if (monNombre > 1) { 172 | resultat = 'monNombre est supérieur à 1'; 173 | } else { 174 | resultat = 'monNombre n\'est ni 1, ni >1'; 175 | } 176 | ``` 177 | 178 | --- 179 | class: center, middle 180 | 181 | # 2. Mise en pratique 🏌 182 | 183 | --- 184 | class: center, middle, dbl-size, dbl-line 185 | 186 | ## Interagir avec l'utilisateur 👤💬 187 | 188 | ```js 189 | var sonPrenom = prompt('Quel est ton prénom ?'); 190 | alert('Bonjour, ' + sonPrenom + ' ! :-)'); 191 | ``` 192 | 193 | --- 194 | class: center, middle, dbl-size, dbl-line 195 | 196 | ## Interagir avec l'utilisateur 👤💬 197 | 198 | ```js 199 | alert(message); 200 | ``` 201 | 202 | ??? 203 | 204 | `alert()` permet d'afficher un `message`. 205 | 206 | --- 207 | class: center, middle, dbl-size, dbl-line 208 | 209 | ## Interagir avec l'utilisateur 👤💬 210 | 211 | ```js 212 | var reponse = prompt(question); 213 | ``` 214 | 215 | ??? 216 | 217 | - `prompt()` permet d'interroger l'utilisateur 218 | - la saisie est retournée sous forme d'une chaîne de caractères. 219 | 220 | --- 221 | class: center, middle 222 | 223 | ## Exercice 1: 🤖💬 Chat-bot bête mais poli 224 | 225 | Programme qui dialogue avec l'utilisateur: 226 | - si l'utilisateur saisit `bonjour`, afficher `Bonjour à toi !`; 227 | - sinon, si l'utilisateur saisit `tu vas bien ?`, afficher `Bien, et toi ?`; 228 | - sinon, afficher `Désolé, je n'ai pas compris...`. 229 | 230 | --- 231 | class: center, middle 232 | 233 | ## Exercice 2: 🤖💬 Chat-bot poli mais pas sympa 234 | 235 | Sur la base de l'exercice précédent, dans le cas où l'utilisateur a saisi `bonjour`: 236 | - afficher `Bonjour ! Ca va ?`, 237 | - inviter l'utilisateur à saisir une deuxième réponse, puis: 238 | - si l'utilisateur saisit `oui`, afficher `Je suis content pour toi.`; 239 | - sinon, afficher `Désolé, il faut que je file.`. 240 | 241 | --- 242 | class: center, middle 243 | 244 | ## Exercice 3: 🤖💬 Votre propre chat-bot 245 | 246 | Produire et rendre deux fichiers: 247 | 1. Arbre de 5 questions, sur 2 niveaux + réponses associées. 248 | 2. Code JavaScript fonctionnel correspondant. 249 | 250 | 📌 Mots clés: `var`, `if`, `else`, `=`, `===`, `prompt` et `alert`. 251 | 252 | --- 253 | class: center, middle 254 | 255 | ## 🏋 256 | ## Exercice 3 à rendre en binôme 257 | ## via Classroom 258 | ## (fichiers: `arbre.jpg` + `chatbot.js`) 259 | ## avant Dimanche, minuit 260 | ## 👋 261 | 262 | ??? 263 | 264 | 📔✍👣💪 265 | -------------------------------------------------------------------------------- /slides/03-algo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TP Slides 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /slides/03-algo/slides.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # JavaScript 4 | ## ➰ Algorithmes et Boucles 5 | 6 | --- 7 | class: center, middle, dbl-size 8 | 9 | # 🎯 Objectifs 10 | 11 | - 👊 Développer un jeu à plusieurs tours 12 | - ➰ Boucles et itérations 13 | 14 | --- 15 | class: center, middle, quote 16 | 17 | Un algorithme est une **suite** finie et non ambiguë d’**opérations** ou d'instructions permettant de résoudre un problème ou d'**obtenir un résultat**. 18 | 19 | --- 20 | class: center, middle, dbl-size 21 | 22 | # Afficher les nombres de 1 à 3 23 | 24 | ```js 25 | console.log(1); 26 | console.log(2); 27 | console.log(3); 28 | ``` 29 | 30 | ??? 31 | 32 | - console.log() permet d'écrire dans la console 33 | - ce code fonctionne bien, mais imaginer si on devait compter jusqu'à 10000! 34 | - => redondant 35 | 36 | --- 37 | class: center, middle, dbl-size 38 | 39 | # Afficher les nombres de 1 à 10000 40 | 41 | ```js 42 | for ( var monNombre = 1; monNombre <= 10000; monNombre++ ) { 43 | console.log( monNombre ); 44 | } 45 | ``` 46 | 47 | ??? 48 | 49 | Pour ce genre de répétition, le mot-clé `for` permet de définir une seule fois les instructions qui doivent êtres répétées, puis de spécifier combien de fois on souhaite qu'elles soient répétées. 50 | 51 | Comment le lire: 52 | - Pour chaque valeur de `monNombre`, 53 | - croissant de `1` à `10000` (compris), 54 | - afficher la valeur de `monNombre` dans la console. 55 | 56 | Donner des exemples d'usage de boucles 57 | 58 | --- 59 | class: center, middle 60 | 61 | # Anatomie d'une boucle `for` 62 | 63 | Syntaxe: 64 | 65 | ```js 66 | for( /* initialisation */ ; /* condition */ ; /* incrémentation */ ) { 67 | /* instructions à répeter */ 68 | } 69 | ``` 70 | 71 | Exemple: 72 | 73 | ```js 74 | for ( var monNombre = 1; monNombre <= 10000; monNombre++ ) { 75 | console.log( monNombre ); 76 | } 77 | ``` 78 | 79 | ??? 80 | 81 | Cette boucle est définie par: 82 | - l'usage du mot clé `for`; 83 | - une liste d'instructions (saisie entre accolades `{}`) à répéter tant que la condition est vraie: `console.log( monNombre );` (dans notre exemple, il n'y a qu'une seule instruction, mais on peut en mettre une infinité); 84 | - une condition (expression conditionnelle, comme dans une condition `if`): `monNombre <= 10000`; 85 | - une instruction d'itération qui sera exécutée après chaque itération de la boucle: `monNombre++` (qui, ici, incrémente la valeur de `monNombre`, c'est à dire augmente sa valeur de `1`); 86 | - et une instruction d'initialisation qui ne sera exécutée qu'une seule fois: `var monNombre = 1` (ici, on créée une variable `monNombre` et on lui affecte la valeur initiale `1`). 87 | 88 | On appelle **itération** chaque répétition de la boucle. 89 | 90 | À noter que, dans la plupart des cas, les boucles sont utilisées pour itérer: 91 | - sur un intervalle (dans notre exemple: nombres entiers entre `1` et `10000`), 92 | - ou sur une énumération de valeurs (ex: un tableau/Array, comme on le verra plus tard). 93 | 94 | --- 95 | class: center, middle, dbl-size 96 | 97 | ### Traçage de l’exécution d'une boucle `for` 98 | 99 | ```js 100 | console.log('on va boucler'); 101 | for ( var i = 0; i < 4; i++ ) { 102 | console.log('i', i, i < 4); 103 | } 104 | console.log('on a fini de boucler'); 105 | ``` 106 | 107 | => Écrire la suite d'instructions qui vont être exécutées. 108 | 109 | ??? 110 | 111 | Il est très pratique de décomposer une boucle de cette manière lorsqu'elle ne se comporte pas comme voulu. (*débogage*) 112 | 113 | --- 114 | class: center, middle 115 | 116 | # Application: FizzBuzz 117 | 118 | - Boucle qui affiche les nombres de `1` à `199` (compris) dans la console. 119 | - Multiples de `3`: afficher `Fizz` au lieu du nombre. 120 | - Multiples de `5`: afficher `Buzz` au lieu du nombre. 121 | - Multiples de `3` et `5`: afficher uniquement `FizzBuzz`. 122 | 123 | ### Fonctions fournies 124 | 125 | ```js 126 | function estMultipleDeTrois(nombre) { return nombre % 3 == 0; } 127 | function estMultipleDeCinq(nombre) { return nombre % 5 == 0; } 128 | ``` 129 | 130 | ??? 131 | 132 | => On devrait obtenir les lignes suivantes dans la console: 133 | 134 | `1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz` (...jusqu'à `199`) 135 | 136 | --- 137 | class: center, middle, dbl-size 138 | 139 | # Exemple d'usage des fonctions 1/2 140 | 141 | ```js 142 | estMultipleDeTrois(2); // => ? 143 | estMultipleDeTrois(6); // => ? 144 | 145 | estMultipleDeCinq(6); // => ? 146 | estMultipleDeCinq(15); // => ? 147 | ``` 148 | 149 | ??? 150 | 151 | estMultipleDeTrois(2); // => retourne false, car 2 n'est pas multiple de 3 152 | estMultipleDeTrois(6); // => retourne true, car 6 est un multiple de 3 153 | 154 | estMultipleDeCinq(6); // => retourne false, car 6 n'est pas un multiple de 5 155 | estMultipleDeCinq(15); // => retourne true, car 15 est un multiple de 5 156 | 157 | --- 158 | class: center, middle, dbl-size 159 | 160 | # Exemple d'usage des fonctions 2/2 161 | 162 | ```js 163 | var monNombre = 5; // valeur fournie en guise d'exemple 164 | if (estMultipleDeCinq(monNombre)) { 165 | console.log('monNombre est multiple de 5'); 166 | } else { 167 | console.log('monNombre n\'est pas multiple de 5'); 168 | } 169 | ``` 170 | 171 | --- 172 | class: center, middle 173 | 174 | # Exercice: Devine le nombre 175 | 176 | - Ordinateur choisit un nombre entre `0` et `100`. 177 | - À chaque tour: 178 | - Si nombre saisi < ordinateur: afficher `Plus grand`. 179 | - Si nombre saisi > ordinateur: afficher `Plus petit`. 180 | - Si joueur a deviné le nombre: afficher `Bravo !`. 181 | - Joueur a droit à `10` tours pour deviner le nombre. 182 | 183 | ### Nombre aléatoire entre 0 et 100 184 | 185 | ```js 186 | Math.round(Math.random() * 100) 187 | ``` 188 | 189 | ??? 190 | 191 | Exemple de partie: 192 | 193 | ``` 194 | joueur: 10 => "Plus grand" 195 | joueur: 20 => "Plus petit" 196 | joueur: 16 => "Bravo !" 197 | ``` 198 | 199 | --- 200 | class: center, middle 201 | 202 | ## 🏋 203 | ## Exercice à rendre en binôme 204 | ## via Classroom 205 | ## (fichier: `devine.js`) 206 | ## avant Dimanche, minuit 207 | ## 👋 208 | -------------------------------------------------------------------------------- /slides/05-fonctions/img/fct-appel-valeurs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/05-fonctions/img/fct-appel-valeurs.png -------------------------------------------------------------------------------- /slides/05-fonctions/img/fct-appel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/05-fonctions/img/fct-appel.png -------------------------------------------------------------------------------- /slides/05-fonctions/img/fct-chaine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/05-fonctions/img/fct-chaine.png -------------------------------------------------------------------------------- /slides/05-fonctions/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TP Slides 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /slides/06-tableaux/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TP Slides 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /slides/07-objets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TP Slides 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /slides/08-dom/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TP Slides 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /slides/08-dom/slides.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # JavaScript 4 | ## et le DOM 5 | 6 | --- 7 | class: center, middle, dbl-size 8 | 9 | # 🎯 Objectifs 10 | 11 | - Exécuter du JS depuis une page HTML 12 | - Manipuler une page HTML depuis JS 13 | - Application: Calculatrice 14 | 15 | --- 16 | class: middle 17 | 18 | # Terminologie Web 19 | 20 | - WWW: *World Wide Web* 21 | - HTML: *HyperText Markup Language* 22 | - CSS: *Cascading Style Sheets* 23 | - JavaScript 24 | - Navigateur Web / *Web Browser* 25 | - DOM: *Document Object Model* 26 | - API: *Application Programming Interface* 27 | 28 | --- 29 | class: center, middle, dbl-size 30 | 31 | # Intégration JavaScript dans HTML 32 | 33 | ```html 34 | 35 | 36 | 37 | 38 | 39 | 40 |

      Bonjour !

      41 | 42 | 43 | 44 | ``` 45 | 46 | ??? 47 | 48 | Trois choses importantes à remarquer: 49 | 50 | - l'élément `` après chaque balise ouvrante ` 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /slides/09-styling/slides.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # JavaScript 4 | ## Classes et styles CSS 5 | 6 | --- 7 | class: center, middle, dbl-size 8 | 9 | # 🎯 Objectif 10 | 11 | ![categories animation](img/categories.gif) 12 | 13 | ??? 14 | 15 | pour faire ça: 16 | 17 | - onclick (cours précédent) 18 | - appliquer classe CSS sur éléments 19 | - récupérer éléments par classe 20 | - aussi: changer style d'éléments 21 | 22 | --- 23 | class: center, middle, dbl-size 24 | 25 | # 🎯 Plan 26 | 27 | 1. Afficher/cacher un `

      ` 28 | 2. Cacher des spoilers 29 | 3. Surbrillance au clic 30 | 4. Filtrage par catégorie (à rendre) 31 | 32 | ??? 33 | 34 | bcp de pratique: 3 exercices + 1 à rendre 35 | 36 | --- 37 | class: center 38 | 39 | # 1. Manipulation de classes CSS 40 | 41 | Règles CSS: 42 | 43 | ```css 44 | .hidden { 45 | display: none; 46 | } 47 | ``` 48 | 49 | ??? 50 | 51 | une classe qui sert à cacher les éléments portant cette classe 52 | 53 | -- 54 | 55 | Page HTML: 56 | 57 | ```html 58 |

      59 |

      texte à cacher

      60 | ``` 61 | 62 | ??? 63 | 64 | deux paragraphes: 1 caché + 1 à cacher en JS 65 | 66 | -- 67 | 68 | Ajout de classe en JS: 69 | 70 | ```js 71 | document.getElementById('second').classList.add('hidden'); 72 | ``` 73 | 74 | ??? 75 | 76 | utilisation de la propriété `classList`, deux fonctions: 77 | 78 | - `add()` pour ajouter 79 | - `remove()` pour retirer 80 | 81 | -- 82 | 83 | ## => Exercice: Afficher/cacher 84 | 85 | ??? 86 | 87 | exercice: 88 | - page avec deux `

      ` 89 | - fichier CSS avec `.hidden` 90 | - code JS pour retirer classe `hidden` du 2ème `

      ` ? 91 | 92 | --- 93 | class: center 94 | 95 | # 2. Accéder à des éléments par classe 96 | 97 | ### Page HTML: 98 | 99 | ```html 100 |

      garçon troublé

      101 |

      ours en peluche disparu

      102 |

      finalement il le retrouve

      103 | ``` 104 | 105 | ??? 106 | 107 | trois paragraphes, dont deux portant la classe `spoiler` 108 | 109 | => on veut cacher les spoilers en JS. 110 | 111 | pour l'instant, on sait récupérer UN élément en JS, en connaissant son `id`. 112 | 113 | -- 114 | 115 | ### Instruction JS: 116 | 117 | ```js 118 | document.getElementsByClassName('spoiler'); // => tableau d'éléments 119 | ``` 120 | 121 | ??? 122 | 123 | pour récupérer les éléments portant une classe donnée. 124 | 125 | => ça renvoie un tableau 126 | 127 | => on peut faire une boucle pour manipuler chaque élément HTML contenu dans le tableau. 128 | 129 | -- 130 | 131 | ## => Exercice: Cacher les spoilers 132 | 133 | ??? 134 | 135 | - page avec trois `

      ` 136 | - fichier CSS avec `.hidden` 137 | - code JS pour ajouter `.hidden` aux paragraphes `.spoiler` ? 138 | - bouton HTML => spoilers cachés au clic 139 | 140 | --- 141 | class: center 142 | 143 | # 3. Manipulation de styles CSS (1/2) 144 | 145 | ### Règle CSS: 146 | 147 | ```css 148 | #encadre { 149 | border: 1 solid black; 150 | background-color: red; 151 | } 152 | ``` 153 | 154 | ??? 155 | 156 | règle CSS associée à l'id `encadre`: 157 | 158 | - une bordure 159 | - une couleur de fond 160 | 161 | -- 162 | 163 | ### JSON / Objet JS correspondant: 164 | 165 | ```js 166 | { 167 | border: '1 solid black', 168 | backgroundColor: 'red' 169 | } 170 | ``` 171 | 172 | ??? 173 | 174 | en JS, on manipule ces propriétés via un Objet 175 | 176 | => quelques différences: 177 | 178 | - valeurs = string => apostrophes 179 | - propriétés séparées par des virgules 180 | - clés composées notées en camel case 181 | 182 | --- 183 | class: center 184 | 185 | # 3. Manipulation de styles CSS (2/2) 186 | 187 | ### Page HTML: 188 | 189 | ```html 190 |

      texte important

      191 |

      autre texte

      192 | ``` 193 | 194 | ??? 195 | 196 | deux paragraphes, avec chacun un `id` 197 | 198 | -- 199 | 200 | ### Modification de style en JS: 201 | 202 | ```js 203 | var element = document.getElementById('premier'); 204 | element.style.backgroundColor = 'red'; 205 | ``` 206 | 207 | ??? 208 | 209 | pour modifier le style du premier: 210 | 211 | - on le récupère du DOM (ici, par son `id`) 212 | - on utilise la propriété `style`, de type objet 213 | 214 | => on peut faire des affectations, comme sur un objet classique ! 215 | 216 | -- 217 | 218 | ## => Exercice: Surbrillance au clic 219 | 220 | ??? 221 | 222 | - page avec deux `

      `, sans CSS 223 | - code JS pour ajouter fond jaune quand utilisateur clique sur un `

      ` 224 | 225 | --- 226 | class: center, middle, dbl-size 227 | 228 | # 4. Exercice: liste avec filtrage dynamique 229 | 230 | ![categories animation](img/categories.gif) 231 | 232 | => URL Codepen, jsfiddle, ou jsbin 233 | 234 | à rendre via devoir Classroom 235 | 236 | avant Dimanche 19 Février, minuit. 237 | 238 | ??? 239 | 240 | - min. 10 produits et 3 catégories; 241 | - produit = élément HTML; 242 | - catégories dans attribut `class`; 243 | - filtrage par classes; 244 | - pouvoir passer rapidement d'une catégorie à une autre, puis afficher la liste complète (non filtrée) des produits; 245 | - au moins 2 produits présents dans plusieurs catégories. 246 | 247 | --- 248 | class: center, middle, dbl-size 249 | 250 | # 5. À découvrir dans le support de cours 251 | 252 | - `getElementsByTagName()` 253 | - `getAttribute()` et `setAttribute()` 254 | - Propriété `innerHTML` 255 | - Scope / portée des variables 256 | -------------------------------------------------------------------------------- /slides/10-composants/img/1-accordion.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/10-composants/img/1-accordion.gif -------------------------------------------------------------------------------- /slides/10-composants/img/2-carousel.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/10-composants/img/2-carousel.gif -------------------------------------------------------------------------------- /slides/10-composants/img/3-videos.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/10-composants/img/3-videos.gif -------------------------------------------------------------------------------- /slides/10-composants/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TP Slides 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /slides/10-composants/slides.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # JavaScript 4 | ## Composants Web 5 | 6 | --- 7 | class: center, middle, dbl-size 8 | 9 | # 🎯 Objectif: Carousel 10 | 11 | ![composant animation](img/2-carousel.gif) 12 | 13 | Ingrédients: Sélecteurs DOM, manip. CSS, `onclick`, modulo... 14 | 15 | --- 16 | class: center, middle, dbl-size 17 | 18 | # 🎯 ... ou: Accordéon 19 | 20 | ![composant animation](img/1-accordion.gif) 21 | 22 | Ingrédients: Sélecteurs DOM, manip. CSS, `onclick`, scope... 23 | 24 | --- 25 | class: center, middle, dbl-size 26 | 27 | # 🎯 ... ou encore: Galerie vidéo 28 | 29 | ![composant animation](img/3-videos.gif) 30 | 31 | Ingrédients: Sélecteurs DOM, `onclick`, intégration Iframe, scope... 32 | 33 | --- 34 | class: center, middle 35 | 36 | # À présenter en groupe 37 | 38 | - description concise 39 | - démo 40 | - instructions d'intégration 41 | - API/paramétrage du composant 42 | -------------------------------------------------------------------------------- /slides/11-poo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TP Slides 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /slides/12-advdom/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TP Slides 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /slides/13-ajax/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TP Slides 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /slides/14-ajax2/diagram-get.svg: -------------------------------------------------------------------------------- 1 | XMLHttpRequest-->Serveur API: GET /data 2 | Serveur API->XMLHttpRequest: responseText 3 | Created with Raphaël 2.1.2XMLHttpRequestXMLHttpRequestServeur APIServeur APIGET /dataresponseText -------------------------------------------------------------------------------- /slides/14-ajax2/diagram-post.svg: -------------------------------------------------------------------------------- 1 | XMLHttpRequest->Serveur API: POST /data 2 | Serveur API-->XMLHttpRequest: responseText 3 | Created with Raphaël 2.1.2XMLHttpRequestXMLHttpRequestServeur APIServeur APIPOST /dataresponseText -------------------------------------------------------------------------------- /slides/14-ajax2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TP Slides 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /slides/14-ajax2/slides.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | # JavaScript 3 | ## Requêtes AJAX POST 🚀 4 | 5 | --- 6 | class: center, middle, dbl-size 7 | # 🎯 Objectifs 8 | 9 | - Envoyer des données sur le Web, en JS 10 | - Développer un client de *chat* 11 | 12 | --- 13 | class: center, middle, dbl-size 14 | # 🗒️ Plan du cours 15 | 16 | 1. Rappels et cours 17 | 2. Exercice en binômes 18 | 19 | --- 20 | class: dbl-size 21 | # Rappels AJAX 22 | 23 | - AJAX: requête HTTP(S) depuis JS 24 | - Requête HTTP `GET`: récupérer des données depuis une API 25 | - `JSON.parse()`: transformer `responseText` en objet 26 | 27 | --- 28 | class: dbl-size 29 | # GET vs POST 30 | 31 | - Récupérer des données: HTTP `GET` 32 | 33 | .pull-left[ 34 | ![diagramme get](./diagram-get.svg) 35 | ] 36 | 37 | .comment[ 38 | [//]: # ( -- as generated from http://bramp.github.io/js-sequence-diagrams/ -- ) 39 | [//]: # (XMLHttpRequest-->Serveur API: GET /data) 40 | [//]: # (Serveur API->XMLHttpRequest: responseText) 41 | ] 42 | 43 | -- 44 | 45 | .pull-left[ 46 | ![diagramme post](./diagram-post.svg) 47 | ] 48 | 49 | .comment[ 50 | [//]: # ( -- as generated from http://bramp.github.io/js-sequence-diagrams/ -- ) 51 | [//]: # (XMLHttpRequest->Serveur API: POST /data) 52 | [//]: # (Serveur API-->XMLHttpRequest: responseText) 53 | ] 54 | 55 | - Envoyer des données: HTTP `POST` avec `send(data)` 56 | 57 | ??? 58 | 59 | Démo: 60 | 61 | - Log du serveur: https://js-ajax-twitter.herokuapp.com/log.html 62 | - Code basé sur formulaire: https://js-ajax-twitter.herokuapp.com/index.html 63 | - URL de l'API: `https://js-ajax-twitter.herokuapp.com/tweet` 64 | - Utilisez l'onglet "Réseau" de Chrome Dev Tools pour tester la requête 65 | 66 | --- 67 | class: dbl-size 68 | # Requête HTTP POST en AJAX 69 | 70 | [//]: # (- Envoi d'une chaine de caractères:) 71 | 72 | ```javascript 73 | var xhr = new XMLHttpRequest(); 74 | xhr.open('POST', 'https://httpbin.org/post'); 75 | xhr.onreadystatechange = function() { 76 | if (xhr.readyState === 4) { 77 | alert(xhr.responseText); 78 | } 79 | }; 80 | // envoi d'une chaine de caractères: 81 | xhr.send('ceci est un exemple de données envoyées'); 82 | ``` 83 | 84 | -- 85 | [//]: # (- Envoi d'un objet JavaScript (JSON):) 86 | 87 | ```javascript 88 | // ... ou envoi d'un objet JSON: 89 | xhr.send(JSON.stringify({ message: 'bonjour!' })); 90 | ``` 91 | 92 | ??? 93 | 94 | - `JSON.stringify()` fait l'opération inverse de `JSON.parse()` 95 | - `JSON.stringify()` transforme un objet JSON en chaine de caractères 96 | - L'API `https://httpbin.org/post` est très pratique pour tester vos requêtes 97 | 98 | --- 99 | # Exercice: *Tweeter* en AJAX 100 | 101 | - Objectif: Faire une requête AJAX POST, au lieu du formulaire. 102 | - Suivre les étapes proposées dans le support de cours. 103 | 104 | Pensez à utiliser l'onglet "Réseau" de Chrome Dev Tools pour diagnostiquer. 105 | -------------------------------------------------------------------------------- /slides/15-auth/img/buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/15-auth/img/buttons.png -------------------------------------------------------------------------------- /slides/15-auth/img/screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/15-auth/img/screenshot.jpg -------------------------------------------------------------------------------- /slides/15-auth/img/thumbs-up.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/15-auth/img/thumbs-up.jpg -------------------------------------------------------------------------------- /slides/15-auth/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TP Slides 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /slides/15-auth/slides.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # JavaScript 4 | ## Identification via plateformes tierces 5 | 6 | .col-33pct[ ] 7 | .col-33pct[ 8 | ![boutons facebook connect et google](./img/buttons.png) 9 | ] 10 | 11 | --- 12 | class: center, middle, dbl-size 13 | # 🎯 Objectifs 14 | 15 | + Identification tierce ? 16 | + Intégrer un bouton de login 17 | + Gérer l'état 18 | 19 | --- 20 | class: center, middle, dbl-size 21 | # Pré-requis 22 | 23 | + Compte Google EEMI 24 | + Définition et appel de fonctions 25 | 26 | --- 27 | class: center, middle, dbl-size 28 | # 🗒️ Plan du cours 29 | 30 | 1. Principe 31 | 2. Pratique 32 | + Google Sign-in avec app et clé fournies 33 | 34 | -- 35 | 3. Exercice 36 | + Mise en production 37 | + Accès limité 38 | + *Bonus: Facebook Connect* 39 | 40 | --- 41 | # Ce que l'utilisateur voit 42 | 43 | .center[ 44 | ![screenshot facebook connect](./img/screenshot.jpg) 45 | ] 46 | 47 | --- 48 | # Comment ça marche ? 49 | 50 | .center[ 51 | ![diagramme facebook auth flow](./img/diagram.svg) 52 | ] 53 | 54 | ??? 55 | 56 | as generated from http://bramp.github.io/js-sequence-diagrams/ 57 | App->Facebook: App id + domain 58 | Facebook->Facebook: Check app 59 | Facebook->User: Dialog 60 | User->User: Login 61 | User->Facebook: Permissions 62 | Facebook->App: Token + User id + permissions 63 | 64 | --- 65 | # Comment ça marche ? 66 | 67 | .column[ 68 | ![diagramme facebook auth flow](./img/diagram.svg) 69 | ] 70 | 71 | .column[ 72 | - **Domain**: déclaré auprès du tiers 73 | - **App/client id**: "clé" fournie par le tiers 74 | - **Permissions**: droits d'accès accordés à l'app par l'utilisateur 75 | - **Token**: chaine de caractères qui sert de "clé temporaire" pour que l'app échange avec l'API du tiers à propos de l'utilisateur 76 | ] 77 | 78 | --- 79 | class: center, middle, dbl-size 80 | # Pratique: Intégration Google Sign-in (30mn) 81 | 82 | - app qui affiche le nom de l'utilisateur quand il est connecté, 83 | - et lui permet de se déconnecter. 84 | 85 | => Cloner et compléter l'app suivante: `https://jsbin.com/haxeqad/edit?html,js,output` 86 | 87 | --- 88 | # Félicitations ! 89 | 90 | .pull-right[ 91 | ![congratulations achievement](./img/thumbs-up.jpg) 92 | ] 93 | 94 | - Vous avez intégré un bouton Google Signin à une application. 95 | 96 | - Par contre, vous avez utilisé une clé `CLIENT_ID` que j'ai **créée pour vous**, et qui ne fonctionne que depuis le domaine `jsbin.com`. 97 | 98 | - Pour que le login de votre application fonctionne **depuis votre propre URL** sur Internet, vous allez devoir la déclarer auprès de Google et configurer votre propre clé `CLIENT_ID`. 99 | 100 | --- 101 | # Exercice: Login en production (45mn) 102 | 103 | 1. Héberger le code précédent sur votre espace étudiant, observer l'erreur obtenue 104 | 2. Se connecter à la [Console Google Developers](https://console.developers.google.com/project/_/apiui/apis/library) avec son compte EEMI 105 | 3. Créer un projet, et moyen de s'identifier à votre application Web avec "OAuth", depuis le domaine où elle est hébergée 106 | 4. Intégrer la clé `CLIENT_ID` fournie dans votre page HTML, puis tester la connexion et déconnexion. 107 | 5. BONUS: restreindre l'accès qu'à certaines personnes. 108 | 6. BONUS: Refaire l'exercice avec Facebook Connect au lieu de Google Signin. 109 | 110 | ??? 111 | 112 | référence principale: 113 | - https://developers.google.com/identity/sign-in/web/devconsole-project 114 | 115 | autres références: 116 | - http://android-developers.blogspot.fr/2016/03/registering-oauth-clients-for-google.html 117 | - https://developers.google.com/+/web/signin/#enable_the_google_api 118 | 119 | --- 120 | class: dbl-size 121 | # Félicitations ! 122 | 123 | .pull-right[ 124 | ![congratulations achievement](./img/thumbs-up.jpg) 125 | ] 126 | 127 | - Vous êtes maintenant capables de créer des applications web avec login Google ! 128 | -------------------------------------------------------------------------------- /slides/16-jquery/img/dom-tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/16-jquery/img/dom-tree.png -------------------------------------------------------------------------------- /slides/16-jquery/img/dom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/16-jquery/img/dom.png -------------------------------------------------------------------------------- /slides/16-jquery/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TP Slides 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /slides/16-jquery/slides.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # JavaScript 4 | .col-33pct[ ] 5 | .col-33pct[ 6 | ![jquery logo](./img/jquery.svg) 7 | ] 8 | 9 | --- 10 | class: center, middle, dbl-size 11 | # 🎯 Objectifs 12 | 13 | + Comprendre la logique d'usage de jQuery 14 | + Intérpréter un composant jQuery 15 | + Convertir du code jQuery code JS DOM natif 16 | 17 | --- 18 | class: center, middle, dbl-size 19 | # 👌 Pré-requis 20 | 21 | + Savoir créer et tester une page HTML avec du code JS 22 | + Savoir utiliser jsfiddle 23 | 24 | --- 25 | class: center, middle, dbl-size 26 | # 🗒️ Plan du TP 27 | 28 | - Explication des bases 29 | - Mise en pratique: (30mn) 30 | + Convertir un composant jQuery simple en JS/DOM natif 31 | - Exercice: (par groupe de projet) 32 | + Convertir un autre composant jQuery en JS/DOM natif 33 | 34 | --- 35 | # Rappel: le DOM 36 | 37 | .center[ 38 | ![html dom](./img/dom.png) 39 | ] 40 | 41 | --- 42 | # Le DOM, JavaScript et jQuery 43 | 44 | .center[ 45 | ![html dom tree](./img/dom-tree.png) 46 | ] 47 | 48 | - **DOM**: structure d'une page HTML chargée dans le navigateur 49 | -- 50 | 51 | - **DOM API**: fonctions permettant de manipuler le DOM 52 | -- 53 | 54 | - **JavaScript**: langage permettant d'utiliser des APIs depuis le navigateur 55 | -- 56 | 57 | - **jQuery**: bibliothèque JavaScript fournissant des raccourcis pour manipuler le DOM 58 | 59 | --- 60 | class: center, middle 61 | # Sélecteurs / structure 62 | 63 | jQuery | ↔ | JavaScript/DOM 64 | --------------------------- | - | --------------------------- 65 | `$('#monDiv')` | | `document.getElementById('monDiv')` 66 | `$('.maClasse')` | | `document.getElementsByClassName('maClasse')` 67 | `$('

      ')` | | `createElement()` + `setAttribute()` 68 | `$('#monDiv').append(html)` | | `.appendChild(node)` / `innerHTML` 69 | 70 | --- 71 | class: center, middle 72 | # Accesseurs / modifieurs 73 | 74 | jQuery | ↔ | JavaScript/DOM 75 | --------------------------- | - | --------------------------- 76 | `$('#monInput').val()` | | `document.getElementById('monInput').value` 77 | `$('#monLien').attr('href', url)` | | `.setAttribute('href', url)` 78 | `$('#monDiv').css('color', 'red')` | | `.style.color = 'red';` 79 | 80 | --- 81 | class: center, middle 82 | ## Propriétés intéressantes 83 | 84 | - Boucles: `$('.maClasse').click(fct)` 85 | - Chaînage: `$('#monDiv').click(fct).addClass(cls).append(html);` 86 | 87 | -- 88 | 89 | ## Événements 90 | 91 | - `$('#monDiv').click(fonction)` ↔ `.onclick = fonction` 92 | 93 | -- 94 | 95 | ## Bonus 96 | 97 | - `$.ajax(url, fct)` = appel Ajax 98 | 99 | --- 100 | class: center, middle, dbl-size 101 | # Mise en pratique: jQuery -> JS/DOM Natif 102 | 103 | - Tester et analyser le [jsfiddle d'exemple](http://jsfiddle.net/adrienjoly/kfev26f3/) 104 | - Forker ce jsfiddle, puis le modifier pour qu'il ne contienne plus de jQuery: 105 | 1. Fonction associée au clic sur *un seul* menu 106 | 2. ... puis sur *chaque* menu (à l'aide d'une boucle) 107 | 3. Cacher les éléments `.content` 108 | 4. Afficher l'élément `.content` du `.menu` qui a été cliqué 109 | 110 | --- 111 | class: center, middle, dbl-size 112 | # Exercice: convertir un composant jQuery 113 | 114 | ## Exemples de composants 115 | 116 | - Slider: [Simple Slider](http://www.webdeveloperjuice.com/2010/01/12/lightest-jquery-content-slider-ever-made-380-bytes/) ou [Craftyslide](http://projects.craftedpixelz.co.uk/craftyslide/) 117 | - Nombre animé: [codepen](http://codepen.io/shivasurya/pen/FatiB), [jsfiddle](http://jsfiddle.net/4v2wK/), ou [github](https://github.com/talmand/jquery-animate-numbers) 118 | 119 | ## Pour vous aider 120 | 121 | - [Some jQuery Functions And Their JavaScript Equivalents](http://callmenick.com/post/jquery-functions-javascript-equivalents) 122 | - [Plain JS](https://plainjs.com/javascript/) 123 | -------------------------------------------------------------------------------- /slides/17-error/img/error-oper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/17-error/img/error-oper.png -------------------------------------------------------------------------------- /slides/17-error/img/error-prog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/17-error/img/error-prog.png -------------------------------------------------------------------------------- /slides/17-error/img/geoloc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrienjoly/cours-javascript/f45439e6a08c0b55703b9130e5391e760f4cb456/slides/17-error/img/geoloc.gif -------------------------------------------------------------------------------- /slides/17-error/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TP Slides 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /slides/17-error/slides.md: -------------------------------------------------------------------------------- 1 | class: center, middle 2 | 3 | # JavaScript 4 | ## `Geolocation` et gestion d'erreurs 🌩 5 | 6 | --- 7 | class: center, middle, dbl-size 8 | # 🎯 Objectif: Localiser l'utilisateur 9 | 10 | ![composant animation](img/geoloc.gif) 11 | 12 | Ingrédients: APIs geoloc et geocoding, gestion d'erreurs 13 | 14 | ??? 15 | 16 | but: faire une app comme ça. 17 | 18 | problème: ici, on voit le cas où n'y a pas de problème. 19 | mais il faut aussi gérer les cas où ça ne fonctionne pas, 20 | pour informer et aider l'utilisateur. 21 | 22 | --- 23 | class: center, middle, dbl-size 24 | # 🗒 Plan du TP 25 | 26 | - Explication: Gestion d'erreurs 27 | - Pratique: créer app de localisation 28 | 29 | --- 30 | class: center, middle, dbl-size 31 | # 🌩 Types d'erreurs 32 | 33 | ![erreur de programmation](img/error-prog.png) 34 | 35 | ![erreur opérationnelle](img/error-oper.png) 36 | 37 | ??? 38 | 39 | Q: difference ? 40 | R: erreurs de prog VS erreurs opérationnelles 41 | 1. c'est votre faute, en tant que développeur => il faut corriger 42 | 2. c'est pas votre faute => il faut prévoir 43 | 44 | Q: autres exemples d'idées ? 45 | 46 | --- 47 | class: center, middle, dbl-size 48 | # 🌩 Erreurs de programmation 49 | 50 | - `SyntaxError`: accolades 51 | - `ReferenceError`: typo ou var. non définie 52 | - `TypeError`: valeur indéfinie ou type non respecté 53 | - ... 54 | 55 | ## => Corriger et tester 56 | 57 | ??? 58 | 59 | Attention, ces erreurs interrompent le programme ! 60 | Il faut corriger son code (ex: accolades) 61 | et tester un max de cas limites. (ex: bouton annuler) 62 | 63 | --- 64 | class: center, middle, dbl-size 65 | # 🌩 Erreurs opérationnelles 66 | 67 | - le serveur met trop de temps à répondre (AJAX) 68 | - `JSON.parse()` sur du JSON invalide 69 | - pop-up bloqué par navigateur 70 | - cookies ou géoloc désactivés 71 | - non connecté à internet 72 | - mémoire insuffisante 73 | 74 | ## => Détecter et gérer les imprévus 75 | 76 | ??? 77 | 78 | Certaines de ces erreurs peuvent interrompre le programme. 79 | Il faut les détecter, puis prévenir et/ou aider l'utilisateur. 80 | 81 | --- 82 | class: center, middle, dbl-size 83 | # 🌩 Intercepter une erreur Synchrone 84 | 85 | ```js 86 | try { 87 | var json = JSON.parse('{ JSON invalide }'); // 🌩 88 | console.log('résultat:', json); 89 | } catch (error) { 90 | console.log('une erreur est survenue:', error.message); 91 | } 92 | console.log('cette ligne s\'affichera dans tous les cas.'); 93 | ``` 94 | 95 | ??? 96 | 97 | JSON.parse cause une erreur interceptée par le catch() => console.log suivant non executé 98 | 99 | Expliquer "synchrone". 100 | 101 | --- 102 | class: center, middle 103 | # 🌩 Intercepter une erreur Asynchrone 1/2 104 | 105 | ```js 106 | uneFonctionAsynchrone(function(err, res) { 107 | if (error) { 108 | alert('une erreur est survenue: ' + err.message); 109 | } else { 110 | alert('resultat de la fonction: ' + res); 111 | } 112 | }); 113 | ``` 114 | 115 | --- 116 | class: center, middle 117 | # 🌩 Intercepter une erreur Asynchrone 2/2 118 | 119 | Parfois, il faut fournir deux fonctions: 120 | 121 | ```js 122 | function traiterPos(pos) { 123 | alert('GPS: ' + pos.coords.latitude + ', ' + pos.coords.longitude); 124 | } 125 | function traiterErr(err) { 126 | alert('une erreur est survenue: ' + err.message); 127 | } 128 | navigator.geolocation.getCurrentPosition(traiterPos, traiterErr); 129 | ``` 130 | 131 | ??? 132 | 133 | Q: exemple d'erreur opérationnelle dans ce code ? 134 | R: l'utilisateur n'a pas accepté de partager sa position 135 | 136 | --- 137 | class: center, middle, dbl-size 138 | # 🌩 Pratique: créer app de localisation 139 | 140 | 1. Informer l'utilisateur du besoin d'autorisation 141 | 2. Détecter coordonnées de l'utilisateur (ou erreurs) 142 | 3. Déterminer adresse postale correspondante (ou erreurs) 143 | 144 | ## 🔥 Simuler les cas d'erreurs, pour tester 145 | 146 | BONUS: Ajouter carte. 147 | -------------------------------------------------------------------------------- /slides/remark-styling.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic); 2 | @import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz); 3 | @import url(https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic); 4 | 5 | /* default styling and layouts */ 6 | 7 | body { 8 | font-family: 'Droid Serif'; 9 | } 10 | 11 | h1, h2, h3 { 12 | font-family: 'Yanone Kaffeesatz'; 13 | font-weight: normal; 14 | } 15 | 16 | li { 17 | clear: left; 18 | line-height: 2; 19 | } 20 | 21 | .remark-slide-number { 22 | display: none; 23 | } 24 | 25 | .footnote { 26 | position: absolute; 27 | bottom: 3em; 28 | } 29 | 30 | .remark-code, .remark-inline-code { 31 | font-family: 'Ubuntu Mono'; 32 | background-color: #ddd; 33 | padding: 2px 5px; 34 | } 35 | 36 | .inverse { 37 | background: #272822; 38 | color: #777872; 39 | text-shadow: 0 0 20px #333; 40 | } 41 | 42 | .inverse h1, .inverse h2 { 43 | color: #f3f3f3; 44 | line-height: 0.8em; 45 | } 46 | 47 | /* my customizations */ 48 | 49 | .h1-corner h1 { 50 | position: absolute; 51 | top: 0px; 52 | left: 40px; 53 | font-size: 28px; 54 | } 55 | 56 | .full-bg-image { 57 | background-size: cover !important; 58 | background-position: 50% 50% !important; 59 | } 60 | 61 | .fit-bg-image { 62 | background-size: contain !important; 63 | background-position: 50% 50% !important; 64 | } 65 | 66 | .left-bg-image { 67 | background-size: contain !important; 68 | background-position: left 50% !important; 69 | } 70 | 71 | .right-bg-image { 72 | background-size: contain !important; 73 | background-position: right 50% !important; 74 | } 75 | 76 | /* my layout helpers */ 77 | 78 | .absolute { 79 | position: absolute; 80 | } 81 | 82 | .col { 83 | display: table-cell; 84 | } 85 | 86 | .col-25pct { 87 | overflow: auto; 88 | float: left; 89 | width: 25%; 90 | } 91 | 92 | .col-33pct { 93 | position: relative; 94 | overflow: auto; 95 | float: left; 96 | width: 33%; 97 | } 98 | 99 | .col-33pct img { 100 | width: 100%; 101 | } 102 | 103 | .col-50pct { 104 | width: 50%; 105 | } 106 | 107 | .center { 108 | text-align: center; 109 | } 110 | 111 | .center table, 112 | .center ul, 113 | .center ol, 114 | .center pre { 115 | display: table; 116 | margin: 0 auto; 117 | line-height: 1.5em; 118 | } 119 | 120 | .center li, 121 | .center pre > code { 122 | float: left; 123 | clear: left; 124 | text-align: left; 125 | } 126 | 127 | .center-block { 128 | margin: 0 auto; 129 | } 130 | 131 | .clear { 132 | clear: both; 133 | } 134 | 135 | .clear-block { 136 | display: block; 137 | clear: both; 138 | } 139 | 140 | .pull-left { 141 | float: left; 142 | } 143 | 144 | .pull-right { 145 | float: right; 146 | } 147 | 148 | .column { 149 | color: #777; 150 | width: 49%; 151 | height: 92%; 152 | float: left; 153 | } 154 | 155 | .column img { 156 | display: inline; 157 | max-width: 100%; 158 | } 159 | 160 | .margin-20px { 161 | margin-top: 20px; 162 | } 163 | 164 | .highlight { 165 | padding: 5px 10px; 166 | border-radius: 15px; 167 | } 168 | 169 | .red-bg { 170 | background: rgba(255,0,0,0.25); 171 | } 172 | 173 | .yellow-bg { 174 | background: rgba(255,255,0,0.25); 175 | } 176 | 177 | /* my styling */ 178 | 179 | .bold { 180 | font-weight: bold; 181 | } 182 | 183 | .wide img { 184 | width: 100%; 185 | } 186 | 187 | .gray { 188 | color: gray; 189 | } 190 | 191 | .white-on-black { 192 | color: white; 193 | background-color: black; 194 | } 195 | 196 | .blurred-bg { 197 | background-color: rgba(255,255,255,0.5); 198 | } 199 | 200 | .dbl-size * { 201 | font-size: 2rem; 202 | } 203 | 204 | .dbl-line * { 205 | line-height: 1.5em; 206 | } 207 | 208 | .quote p { 209 | font-size: 2rem; 210 | font-style: italic; 211 | line-height: 1.5em; 212 | } 213 | 214 | .quote p::before { 215 | content: '« '; 216 | } 217 | 218 | .quote p::after { 219 | content: ' »'; 220 | } 221 | -------------------------------------------------------------------------------- /tp07.md: -------------------------------------------------------------------------------- 1 | ![Logo JavaScript](js-logo.png) 2 | 3 | # TP 7: Classes 4 | 5 | --- 6 | 7 | ## Bases de la POO: classes JavaScript 8 | 9 | ### Programmation Orientée Objet: classes, instances et `this` 10 | 11 | Une classe est un modèle d'objet. Elle peut être instanciée, c'est à dire qu'on crée un objet (appelé *instance*) selon ce modèle. 12 | 13 | La modèle d'une classe consiste à assurer que chaque objet instance de cette classe aura les mêmes: 14 | 15 | - propriétés; (*cf chapitre sur les types avancés*) 16 | - et méthodes: des fonctions qui s'appliquent à une instance donnée. 17 | 18 | À noter que: 19 | - chaque instance d'une classe aura les mêmes propriétés, mais la valeur de celles-ci pourra être différente pour chaque instance; 20 | - chaque instance d'une classe aura les mêmes méthodes, mais l'exécution de la fonction correspondante ne s'appliquera qu'à l'instance sur laquelle elle aura été appelée. 21 | 22 | Comme nous allons le voir dans la suite du cours, les classes sont très utilisées pour manipuler la structure de pages Web. Notamment pour intégrer plusieurs instances d'un même composant sur une même page. 23 | 24 | ### Comment instancier une classe en JavaScript/ES6 25 | 26 | En guise d'exemple, supposons qu'on veuille intégrer un composant permettant d'afficher une galerie d'images sur notre page Web. 27 | 28 | Supposons que ce composant soit défini par une classe nommée `Galerie`. 29 | 30 | Comme pour toute classe, on peut instancier une `Galerie` en appelant son constructeur avec le mot clé `new`. Le constructeur de cette classe prend un paramètre: `conteneur`, une portion de la page Web dans lequel la galerie s'intègrera. 31 | 32 | Enfin, supposons que la classe `Galerie` fournisse des méthodes qui seront rattachées à chaque instance de cette classe: 33 | 34 | - `ajouterImage()` permet de spécifier l'URL d'une image qui sera à afficher dans cette galerie, 35 | - et `regenerer()` permet de mettre à jour l'affichage de la galerie, après y avoir ajouté des images. 36 | 37 | Voici un exemple d'instanciation de cette classe: 38 | 39 | ```js 40 | // supposons que conteneur référence un
      de la page 41 | var maGalerie = new Galerie(conteneur); 42 | maGalerie.ajouterImage('img7.jpg'); 43 | maGalerie.regenerer(); 44 | ``` 45 | 46 | Le mot clé **new** permet d'instancier notre classe, et donc d'exécuter son constructeur en fournissant une valeur pour le paramètre `conteneur`. Comme pour une fonction, l'appel au constructeur retourne l'instance de `Galerie` fraichement créée. 47 | 48 | ### Comment définir une classe en JavaScript/ES6 49 | 50 | Afin de permettre l'instanciation de la classe `Galerie`, le créateur du composant a du la définir de la manière suivamte: 51 | 52 | ```js 53 | class Galerie { 54 | 55 | // définition du constructeur de la classe Galerie 56 | constructor(conteneur) { 57 | this.conteneur = conteneur; 58 | this.urlImages = []; 59 | } 60 | 61 | // cette méthode permet d'ajouter une image à cette galerie 62 | ajouterImage(url) { 63 | this.urlImages.push(url); 64 | } 65 | 66 | // cette méthode permet de générer et d'afficher cette galerie dans la page 67 | regenerer() { 68 | var html = ''; 69 | // génération des éléments dans le conteneur 70 | for (var i = 0; i < this.urlImages.length; i++) { 71 | html = html + ';'; 72 | } 73 | this.conteneur.innerHTML == html; 74 | } 75 | 76 | } 77 | ``` 78 | 79 | À noter: 80 | - le paramètre `conteneur` du constructeur de la classe a été affecté comme propriétés d'un certain objet `this`. (nous allons expliquer ça plus bas) 81 | 82 | ### Usage de `this` 83 | 84 | Quand on mentionne `this` dans la définition d'une méthode, ce mot clé représente l'instance depuis laquelle la méthode a été appelée. 85 | 86 | Par exemple: 87 | 88 | ```js 89 | class Article { 90 | constructor(titre) { 91 | this.titre = titre; 92 | } 93 | getTitre() { 94 | return this.titre; // this === article1 ou article2, dans notre exemple 95 | } 96 | } 97 | 98 | var article1 = new Article('Trump élu président'); 99 | var article2 = new Article('Macron se présente'); 100 | 101 | article1.getTitre(); // => retourne 'Trump élu président' 102 | article2.getTitre(); // => retourne 'Macron se présente' 103 | ``` 104 | 105 | À noter qu'en JavaScript, `this` est en fait utilisable depuis toute fonction, qu'elle soit ou pas définie dans une classe. Il faut retenir que l'usage de classes permet à l'interpréteur JavaScript d'affecter automatiquement à `this` l'instance sur laquelle s'exécute chaque méthode. 106 | 107 | ### Exercice: Création de classe 108 | 109 | --> http://marijnhaverbeke.nl/talks/es6_falsyvalues2015/exercises/#Point 110 | 111 | 114 | -------------------------------------------------------------------------------- /tp12.md: -------------------------------------------------------------------------------- 1 | ![Logo JavaScript](js-logo.png) 2 | 3 | # TP 12: Envoi de données avec AJAX 4 | 5 | Objectifs: 6 | 7 | - Envoyer des informations (ex: un tweet) à une API du Web 8 | - Effectuer une requête `POST` avec `XMLHttpRequest` 9 | 10 | Slides du TP 11 | 12 | --- 13 | 14 | ## Effectuer une requête `POST` avec `XMLHttpRequest` 15 | 16 | Dans la partie précédente, nous avons utilisé la classe `XMLHttpRequest` pour envoyer des requêtes de type `HTTP GET`. Pour rappel, ce type de requête permet de récupérer des informations depuis un serveur. 17 | 18 | Dans cette partie, nous allons voir comment utiliser cette même classe pour envoyer des requêtes de type `HTTP POST`. Même s'il permet aussi de recevoir une réponse du serveur à ces requêtes, ce type de requête permet d'**envoyer** des informations. 19 | 20 | ### Envoi d'une chaine de caractères 21 | 22 | Voici un exemple de requête `POST` effectuée en JavaScript/AJAX: 23 | 24 | ```javascript 25 | var xhr = new XMLHttpRequest(); 26 | xhr.open('POST', 'https://httpbin.org/post'); 27 | xhr.onreadystatechange = function() { 28 | if (xhr.readyState === 4) { 29 | alert(xhr.responseText); 30 | } 31 | }; 32 | // envoi d'une chaine de caractères: 33 | xhr.send('ceci est un exemple de données envoyées'); 34 | ``` 35 | 36 | Le principe de fonctionnement est exactement le même que celui d'une requête `GET`, sauf que nous avons cette fois-ci **envoyé une chaine de caractères** via notre requête à l'adresse serveur `https://httpbin.org/post`. 37 | 38 | Pour cela, nous avons: 39 | 40 | - remplacé le paramètre `GET` par `POST`, dans l'appel à la méthode `open()`, 41 | - et passé une chaine de caractères en paramètre de l'appel à la méthode `send()`. 42 | 43 | ### Envoi d'un objet JavaScript / JSON 44 | 45 | Pour envoyer un objet JavaScript / JSON dans une requête `POST`, il faut d'abord sérialiser l'objet (c'est à dire: le convertir) sous forme de chaine de caractères, à l'aide de la fonction `JSON.stringify()`. 46 | 47 | Il suffit donc de modifier le paramètre passé à la méthode `send()`, tel que dans l'exemple suivant: 48 | 49 | ```javascript 50 | // ... ou envoi d'un objet JSON: 51 | xhr.send(JSON.stringify({ message: 'bonjour!' })); 52 | ``` 53 | 54 | En effet, `JSON.stringify()` est la fonction inverse de `JSON.parse()`: 55 | 56 | - alors que `JSON.parse()` permet de convertir une chaine de caractères en objet, 57 | - `JSON.stringify()` permet de convertir un objet en chaine de caractères. 58 | 59 | > **Attention**: veillez à ne pas appeler la méthode `send()` d'une même instance (ex: `xhr`, dans notre exemple) plus d'une seule fois ! 60 | 61 | ### Conseils pratiques pour diagnostiquer le fonctionnement de vos requêtes 62 | 63 | - Comme d'habitude, n'oubliez pas de consulter la console de votre navigateur pour vérifier la présence éventuelle d'erreurs dans votre code et/ou dans vos requêtes AJAX. (ex: accès non autorisé à une API) 64 | - Utilisez l'onglet "Réseau" (ou *Network*, en anglais) de Chrome Dev Tools pour suivre l'exécution de vos requêtes, et consulter à la fois leur contenu et celui de la réponse du serveur. 65 | - Utilisez l'API `https://httpbin.org/post` pour tester le bon fonctionnement de vos requêtes POST. Cette API vous envoie en réponse le contenu que le serveur a reçu suite à votre requête. 66 | 67 | ### Exercice 4: *Tweeter* en AJAX 68 | 69 | Un serveur est mis à votre disposition à l'URL https://js-ajax-twitter.herokuapp.com. Comme Twitter, l'application Web exécutée sur ce serveur permet aux utilisateurs de publier des messages publics en temps réel. 70 | 71 | **Le but de cet exercice est de publier vos messages en utilisant une requête AJAX.** 72 | 73 | Sont fournis: 74 | 75 | - une [page web](https://js-ajax-twitter.herokuapp.com) affichant en temps réel le *flux* des derniers messages publiés sur le serveur; 76 | - une API HTTP permettant de publier des messages sur le serveur, accessible depuis l'adresse `/tweet`; 77 | - et un [client simple](https://js-ajax-twitter.herokuapp.com/client.html) permettant de publier des messages à l'aide d'un formulaire HTML. 78 | 79 | #### Documentation de l'API fournie 80 | 81 | Pour publier un message sur ce serveur, il faut envoyer une requête `HTTP POST` à l'adresse `/tweet` (accessible depuis la racine du serveur), en transmettant un objet JSON. 82 | 83 | L'objet JSON à envoyer comme contenu de la requête doit contenir deux propriétés: 84 | 85 | - `message`: le texte à publier. (type: `string`) 86 | - `token`: le jeton fourni après identification de l'utilisateur. (type: `string`) 87 | 88 | Note: La valeur de la propriété `token` de l'objet à envoyer est générée automatiquement par le *client simple* fourni, dans la variable globale `window.token`. 89 | 90 | À chaque requête HTTP valide reçue, le serveur répondra par un objet JSON ayant: 91 | 92 | - soit une propriété `error` contenant un message d'erreur (type: `string`); 93 | - soit une propriété `ok`, dans le cas où le message a été publié sans erreur. 94 | 95 | > Remarque importante: le bouton d'identification de Google n'a été activé que depuis les domaines `jsbin.com`, `codepen.io` et `js-ajax-twitter.herokuapp.com`. Vous ne pourrez donc pas exécuter le *client simple* fourni (ni une version dérivée) depuis un autre domaine, ni depuis le système de fichiers de votre machine (protocole `file://`). 96 | 97 | #### Étapes proposées 98 | 99 | 1. Tester le client fourni: https://js-ajax-twitter.herokuapp.com/client.html (après login) 100 | 2. Cloner/forker le client fourni: https://jsbin.com/bucilir/edit?html,js,output (ou codepen: https://codepen.io/anon/pen/GxBgYg) 101 | 3. Remplacer le formulaire par l'envoi d'une requête HTTP POST à chaque fois que l'utilisateur pressera ENTRÉE dans le champ de saisie (ou clic sur un bouton). 102 | 4. Dans le cas où la publication du message a fonctionné sans erreur, effacer le champ de saisie, afin de permettre la saisie immédiate d'un nouveau message. 103 | 5. Dans le cas contraire, afficher une description de l'erreur dans un `alert()`. 104 | 105 | > Conseil: Pensez à utiliser la console JavaScript et l'onglet "Réseau" de Chrome Dev Tools pour diagnostiquer. 106 | 107 | #### Bonus: améliorations 108 | 109 | Quand vous aurez terminé toutes les étapes proposées ci-dessus, vous pourrez apporter les améliorations suivantes à votre client: 110 | 111 | - intégrer le flux de tous les messages sur votre page, 112 | - améliorer le design et l'expérience utilisateur de votre client. 113 | 114 | 118 | -------------------------------------------------------------------------------- /tp16.md: -------------------------------------------------------------------------------- 1 | ![Logo JavaScript](js-logo.png) 2 | 3 | # TP 16: Identification avec Google et Facebook 4 | 5 | Objectifs: 6 | 7 | - Intégrer un bouton de connexion pour identifier l'utilisateur 8 | - Gérer l'état de l'application en fonction de l'identification 9 | 10 | > Slides du TP 11 | 12 | --- 13 | 14 | ## Introduction 15 | 16 | Identifier l'utilisateur d'une application consiste à connaitre l'identité de la personne qui utilise une application depuis son navigateur, afin de: 17 | 18 | - personnaliser son expérience d'usage de l'application; (ex: garder l'historique des derniers achats, sur un site e-commerce) 19 | - restreindre l'accès à certains utilisateurs. (ex: contrôles JavaScript seulement accessibles aux étudiants de l'EEMI) 20 | 21 | Sur la plupart des sites, cette identification est matérialisée par trois opérations: 22 | 23 | 1. la création d'un compte utilisateur, en fournissant par exemple un email et un mot de passe; (en anglais: `user sign-up` ou `user registration`) 24 | 2. la vérification de l'identité de l'utilisateur, en demandant par exemple à l'utilisateur de cliquer sur un lien envoyé à l'adresse email qu'il a fourni lors de la création de son compte (ou par SMS); (permet de s'assurer que l'adresse email est valide, et de réduire les risques d'usurpation d'identité) 25 | 3. puis l'identification à proprement parler de l'utilisateur sur son compte, en saisissant ses identifiants. (en anglais: `user log-in` ou `user sign-in`) 26 | 27 | ## Identification par plateforme tierce 28 | 29 | Plusieurs plateformes tierces (dont Google et Facebook) fournissent aux développeurs d'applications des moyens de rendre plus rapide l'identification des utilisateurs. Ces moyens consistent à donner accès à l'identité d'un utilisateur une fois que celui-ci accepte de partager ces informations avec l'application. 30 | 31 | ![boutons facebook connect et google signin](img/buttons.png) 32 | 33 | Le mécanisme le plus répandu est **OAuth**. Il standardise les échanges nécessaires entre la plateforme tierce d'identification et une application, afin que cette dernière puisse accéder aux informations de l'utilisateur, voire à certaines fonctionnalités supplémentaires. 34 | 35 | Dans ce cours, nous n'allons pas décrire le fonctionnement de OAuth, mais en récapituler les grandes lignes. 36 | 37 | ### Ce que voit l'utilisateur 38 | 39 | Voici ce qui est affiché à l'utilisateur, après qu'il ait cliqué sur un bouton "Se connecter avec Facebook" (en anglais: "Facebook Connect") depuis une application web: 40 | 41 | ![écran autorisation facebook connect](img/screenshot.jpg) 42 | 43 | Cette page web est générée par Facebook pour demander à l'utilisateur s'il accepte de partager ses données d'identification avec l'application depuis laquelle il a cliqué sur le bouton. 44 | 45 | Le plus souvent, ces données contiennent notamment le nom de l'utilisateur, son adresse email, et sa photo de profil. Parfois plus. 46 | 47 | Ces données sont envoyées à l'application seulement si l'utilisateur accepte. 48 | 49 | ### Échanges entre l'application et la plateforme tierce 50 | 51 | Du point de vue du développeur d'une application, l'identification des utilisateurs via une plateforme tierce se déroulle en six étapes: 52 | 53 | ![écran autorisation facebook connect](img/diagram.svg) 54 | 55 | 1. L'application s'identifie auprès de la plateforme, à l'aide d'un identifiant souvent appelé `APP_ID`, `CLIENT_ID` ou `API_KEY`. 56 | 2. La plateforme vérifie la validité de cet identifiant, et sa concordance avec le nom de domaine depuis lequel l'identification a été demandée. 57 | 3. La plateforme génère et affiche une page à l'utilisateur, pour lui demander sa permission avant de partager ses information personnelles avec l'application. 58 | 4. Après avoir éventuellement ajusté ses préférences, l'utilisateur donne sa permission. 59 | 5. La plateforme prend note des préférences de vie privée de l'utilisateur, pour cette application. 60 | 6. Enfin, elle contacte l'application pour l'informer de l'accord de l'utilisateur, et lui transmet un jeton (en anglais: `token`), une chaine de caractères que devra utiliser l'application pour communiquer désormais avec la plateforme. Par exemple: pour accéder aux informations personnelles de l'utilisateur. 61 | 62 | ## Mise en oeuvre 63 | 64 | Dans la plupart des cas, le développeur d'application peut gagner beaucoup de temps en utilisant un bibliothèque (en anglais: *library*) ou un SDK (*Software Development Kit*) fourni par la plateforme. 65 | 66 | Il existe de nombreux guides sur Internet comment utiliser ces outils, pour les applications Web et Mobile. 67 | 68 | Dans notre cas, nous allons utiliser le SDK [Google Platform Library](https://developers.google.com/identity/sign-in/web/sign-in) depuis notre application Web JavaScript. 69 | 70 | ### Pratique: Intégration Google Sign-in 71 | 72 | Nous allons développer: 73 | 74 | - une application qui affiche le nom de l'utilisateur quand il est connecté, 75 | - et lui permet de se déconnecter. 76 | 77 | Pour cela, cloner et compléter l'application suivante sur jsbin: [`https://jsbin.com/haxeqad/edit?html,js,output`](https://jsbin.com/haxeqad/edit?html,js,output) 78 | 79 | Pour vous aider: 80 | 81 | - [Integrating Google Sign-In into your web app](https://developers.google.com/identity/sign-in/web/sign-in) 82 | 83 | > Note importante: la clé `CLIENT_ID` fournie dans le code ne fonctionne que depuis le site `jsbin.com`. Vous ne pourrez donc pas utiliser ce code pour identifier des utilisateurs depuis un autre domaine, ni depuis votre propre machine. 84 | 85 | 88 | 89 | ### Exercice: Login en production 90 | 91 | Maintenant que nous savons intégrer un bouton Google Signin à une application, nous allons créer notre propre clé `CLIENT_ID`, de manière à ce que notre application puisse fonctionner depuis un autre domaine que `jsbin.com`. 92 | 93 | Pour cela, vous allez devoir déclarer votre propre application auprès de Google et configurer votre propre clé `CLIENT_ID`. 94 | 95 | Étapes proposées: 96 | 97 | 1. Héberger le code précédent sur votre espace étudiant, observer l'erreur obtenue 98 | 2. Se connecter à la [Console Google Developers](https://console.developers.google.com/project/_/apiui/apis/library) avec son compte EEMI 99 | 3. Créer un projet, et moyen de s'identifier à l'application Web avec "OAuth" depuis votre domaine 100 | 4. Intégrer la clé `CLIENT_ID` fournie dans votre page, puis tester la connexion et déconnexion. 101 | 5. BONUS: restreindre l'accès qu'à certaines personnes. 102 | 6. BONUS: Refaire l'exercice avec Facebook Connect au lieu de Google Signin. 103 | 104 | Pour vous aider: 105 | 106 | - [ 107 | Creating a Google API Console project and client ID](https://developers.google.com/identity/sign-in/web/devconsole-project) 108 | 109 | autres références: 110 | - [Registering OAuth clients for Google Sign-In 111 | ](http://android-developers.blogspot.fr/2016/03/registering-oauth-clients-for-google.html) 112 | - [Facebook Login for the Web with the JavaScript SDK](https://developers.facebook.com/docs/facebook-login/web) 113 | --------------------------------------------------------------------------------