Repository with sources and generator of https://larlet.fr/david/ https://larlet.fr/david/
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang=fr>
  4. <!-- Has to be within the first 1024 bytes, hence before the <title>
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset=utf-8>
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name=viewport content="width=device-width,minimum-scale=1,initial-scale=1,shrink-to-fit=no">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>Un Web orienté composants — David Larlet</title>
  13. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  14. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons/apple-touch-icon.png">
  15. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons/favicon-32x32.png">
  16. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons/favicon-16x16.png">
  17. <link rel="manifest" href="/manifest.json">
  18. <link rel="mask-icon" href="/static/david/icons/safari-pinned-tab.svg" color="#5bbad5">
  19. <link rel="shortcut icon" href="/static/david/icons/favicon.ico">
  20. <meta name="apple-mobile-web-app-title" content="David Larlet">
  21. <meta name="application-name" content="David Larlet">
  22. <meta name="msapplication-TileColor" content="#da532c">
  23. <meta name="msapplication-config" content="/static/david/icons/browserconfig.xml">
  24. <meta name="theme-color" content="#f0f0ea">
  25. <!-- That good ol' feed, subscribe :p. -->
  26. <link rel=alternate type="application/atom+xml" title=Feed href="/david/log/">
  27. <!-- Canonical URL for SEO purposes -->
  28. <link rel="canonical" href="https://larlet.fr/david/blog/2013/web-oriente-composants/">
  29. <!-- SEO/Semantic metadata -->
  30. <meta name="description" content="Les Web Components ont certainement leur carte à jouer dans l’avenir du Web et de ses interactions." />
  31. <meta name="twitter:description" property="og:description" itemprop="description" content="Les Web Components ont certainement leur carte à jouer dans l’avenir du Web et de ses interactions." />
  32. <meta name="twitter:title" property="og:title" itemprop="name" content="Un Web orienté composants" />
  33. <meta name="twitter:card" content="summary" />
  34. <meta name="twitter:creator" content="@davidbgk" />
  35. <meta name="twitter:url" property="og:url" content="https://larlet.fr/david/blog/2013/web-oriente-composants/" />
  36. <meta property="og:type" content="article" />
  37. <meta property="og:site_name" content="David Larlet (@davidbgk)" />
  38. <meta name="twitter:image" property="og:image" itemprop="image" content="https://larlet.fr/static/david/david-larlet-avatar-thumbnail.jpg" />
  39. <style>
  40. /* http://meyerweb.com/eric/tools/css/reset/ */
  41. html, body, div, span,
  42. h1, h2, h3, h4, h5, h6, p, blockquote, pre,
  43. a, abbr, address, big, cite, code,
  44. del, dfn, em, img, ins,
  45. small, strike, strong, tt, var,
  46. dl, dt, dd, ol, ul, li,
  47. fieldset, form, label, legend,
  48. table, caption, tbody, tfoot, thead, tr, th, td,
  49. article, aside, canvas, details, embed,
  50. figure, figcaption, footer, header, hgroup,
  51. menu, nav, output, ruby, section, summary,
  52. time, mark, audio, video {
  53. margin: 0;
  54. padding: 0;
  55. border: 0;
  56. font-size: 100%;
  57. font: inherit;
  58. vertical-align: baseline;
  59. }
  60. /* HTML5 display-role reset for older browsers */
  61. article, aside, details, figcaption, figure,
  62. footer, header, hgroup, menu, nav, section { display: block; }
  63. body { line-height: 1; }
  64. blockquote, q { quotes: none; }
  65. blockquote:before, blockquote:after,
  66. q:before, q:after {
  67. content: '';
  68. content: none;
  69. }
  70. table {
  71. border-collapse: collapse;
  72. border-spacing: 0;
  73. }
  74. /* http://practicaltypography.com/equity.html */
  75. /* https://calendar.perfplanet.com/2016/no-font-face-bulletproof-syntax/ */
  76. /* https://www.filamentgroup.com/lab/js-web-fonts.html */
  77. @font-face {
  78. font-family: 'EquityTextB';
  79. src: url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff2') format('woff2'),
  80. url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff') format('woff');
  81. font-weight: 300;
  82. font-style: normal;
  83. font-display: swap;
  84. }
  85. @font-face {
  86. font-family: 'EquityTextB';
  87. src: url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff2') format('woff2'),
  88. url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff') format('woff');
  89. font-weight: 300;
  90. font-style: italic;
  91. font-display: swap;
  92. }
  93. @font-face {
  94. font-family: 'EquityTextB';
  95. src: url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff2') format('woff2'),
  96. url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff') format('woff');
  97. font-weight: 700;
  98. font-style: normal;
  99. font-display: swap;
  100. }
  101. @font-face {
  102. font-family: 'ConcourseT3';
  103. src: url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff2') format('woff2'),
  104. url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff') format('woff');
  105. font-weight: 300;
  106. font-style: normal;
  107. font-display: swap;
  108. }
  109. /* http://practice.typekit.com/lesson/caring-about-opentype-features/ */
  110. body {
  111. /* http://www.cssfontstack.com/ Palatino 99% Win 86% Mac */
  112. font-family: "EquityTextB", Palatino, serif;
  113. background-color: #f0f0ea;
  114. color: #07486c;
  115. font-kerning: normal;
  116. -moz-osx-font-smoothing: grayscale;
  117. -webkit-font-smoothing: subpixel-antialiased;
  118. text-rendering: optimizeLegibility;
  119. font-variant-ligatures: common-ligatures contextual;
  120. font-feature-settings: "kern", "liga", "clig", "calt";
  121. }
  122. pre, code, kbd, samp, var, tt {
  123. font-family: 'TriplicateT4c', monospace;
  124. }
  125. em {
  126. font-style: italic;
  127. color: #323a45;
  128. }
  129. strong {
  130. font-weight: bold;
  131. color: black;
  132. }
  133. nav {
  134. background-color: #323a45;
  135. color: #f0f0ea;
  136. display: flex;
  137. justify-content: space-around;
  138. padding: 1rem .5rem;
  139. }
  140. nav:last-child {
  141. border-bottom: 1vh solid #2d7474;
  142. }
  143. nav a {
  144. color: #f0f0ea;
  145. }
  146. nav abbr {
  147. border-bottom: 1px dotted white;
  148. }
  149. h1 {
  150. border-top: 1vh solid #2d7474;
  151. border-bottom: .2vh dotted #2d7474;
  152. background-color: #e3e1e1;
  153. color: #323a45;
  154. text-align: center;
  155. padding: 5rem 0 4rem 0;
  156. width: 100%;
  157. font-family: 'ConcourseT3';
  158. display: flex;
  159. flex-direction: column;
  160. }
  161. h1.single {
  162. padding-bottom: 10rem;
  163. }
  164. h1 span {
  165. position: absolute;
  166. top: 1vh;
  167. left: 20%;
  168. line-height: 0;
  169. }
  170. h1 span a {
  171. line-height: 1.7;
  172. padding: 1rem 1.2rem .6rem 1.2rem;
  173. border-radius: 0 0 6% 6%;
  174. background: #2d7474;
  175. font-size: 1.3rem;
  176. color: white;
  177. text-decoration: none;
  178. }
  179. h2 {
  180. margin: 4rem 0 1rem;
  181. border-top: .2vh solid #2d7474;
  182. padding-top: 1vh;
  183. }
  184. h3 {
  185. text-align: center;
  186. margin: 3rem 0 .75em;
  187. }
  188. hr {
  189. height: .4rem;
  190. width: .4rem;
  191. border-radius: .4rem;
  192. background: #07486c;
  193. margin: 2.5rem auto;
  194. }
  195. time {
  196. display: bloc;
  197. margin-left: 0 !important;
  198. }
  199. ul, ol {
  200. margin: 2rem;
  201. }
  202. ul {
  203. list-style-type: square;
  204. }
  205. a {
  206. text-decoration-skip-ink: auto;
  207. text-decoration-thickness: 0.05em;
  208. text-underline-offset: 0.09em;
  209. }
  210. article {
  211. max-width: 50rem;
  212. display: flex;
  213. flex-direction: column;
  214. margin: 2rem auto;
  215. }
  216. article.single {
  217. border-top: .2vh dotted #2d7474;
  218. margin: -6rem auto 1rem auto;
  219. background: #f0f0ea;
  220. padding: 2rem;
  221. }
  222. article p:last-child {
  223. margin-bottom: 1rem;
  224. }
  225. p {
  226. padding: 0 .5rem;
  227. margin-left: 3rem;
  228. }
  229. p + p,
  230. figure + p {
  231. margin-top: 2rem;
  232. }
  233. blockquote {
  234. background-color: #e3e1e1;
  235. border-left: .5vw solid #2d7474;
  236. display: flex;
  237. flex-direction: column;
  238. align-items: center;
  239. padding: 1rem;
  240. margin: 1.5rem;
  241. }
  242. blockquote cite {
  243. font-style: italic;
  244. }
  245. blockquote p {
  246. margin-left: 0;
  247. }
  248. figure {
  249. border-top: .2vh solid #2d7474;
  250. background-color: #e3e1e1;
  251. text-align: center;
  252. padding: 1.5rem 0;
  253. margin: 1rem 0 0;
  254. font-size: 1.5rem;
  255. width: 100%;
  256. }
  257. figure img {
  258. max-width: 250px;
  259. max-height: 250px;
  260. border: .5vw solid #323a45;
  261. padding: 1px;
  262. }
  263. figcaption {
  264. padding: 1rem;
  265. line-height: 1.4;
  266. }
  267. aside {
  268. display: flex;
  269. flex-direction: column;
  270. background-color: #e3e1e1;
  271. padding: 1rem 0;
  272. border-bottom: .2vh solid #07486c;
  273. }
  274. aside p {
  275. max-width: 50rem;
  276. margin: 0 auto;
  277. }
  278. /* https://fvsch.com/code/css-locks/ */
  279. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  280. font-size: 1rem;
  281. line-height: calc( 1.5em + 0.2 * 1rem );
  282. }
  283. h1 {
  284. font-size: 1.9rem;
  285. line-height: calc( 1.2em + 0.2 * 1rem );
  286. }
  287. h2 {
  288. font-size: 1.6rem;
  289. line-height: calc( 1.3em + 0.2 * 1rem );
  290. }
  291. h3 {
  292. font-size: 1.35rem;
  293. line-height: calc( 1.4em + 0.2 * 1rem );
  294. }
  295. @media (min-width: 20em) {
  296. /* The (100vw - 20rem) / (50 - 20) part
  297. resolves to 0-1rem, depending on the
  298. viewport width (between 20em and 50em). */
  299. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  300. font-size: calc( 1rem + .6 * (100vw - 20rem) / (50 - 20) );
  301. line-height: calc( 1.5em + 0.2 * (100vw - 50rem) / (20 - 50) );
  302. margin-left: 0;
  303. }
  304. h1 {
  305. font-size: calc( 1.9rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  306. line-height: calc( 1.2em + 0.2 * (100vw - 50rem) / (20 - 50) );
  307. }
  308. h2 {
  309. font-size: calc( 1.5rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  310. line-height: calc( 1.3em + 0.2 * (100vw - 50rem) / (20 - 50) );
  311. }
  312. h3 {
  313. font-size: calc( 1.35rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  314. line-height: calc( 1.4em + 0.2 * (100vw - 50rem) / (20 - 50) );
  315. }
  316. }
  317. @media (min-width: 50em) {
  318. /* The right part of the addition *must* be a
  319. rem value. In this example we *could* change
  320. the whole declaration to font-size:2.5rem,
  321. but if our baseline value was not expressed
  322. in rem we would have to use calc. */
  323. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  324. font-size: calc( 1rem + .6 * 1rem );
  325. line-height: 1.5em;
  326. }
  327. p, li, pre, details {
  328. margin-left: 3rem;
  329. }
  330. h1 {
  331. font-size: calc( 1.9rem + 1.5 * 1rem );
  332. line-height: 1.2em;
  333. }
  334. h2 {
  335. font-size: calc( 1.5rem + 1.5 * 1rem );
  336. line-height: 1.3em;
  337. }
  338. h3 {
  339. font-size: calc( 1.35rem + 1.5 * 1rem );
  340. line-height: 1.4em;
  341. }
  342. figure img {
  343. max-width: 500px;
  344. max-height: 500px;
  345. }
  346. }
  347. figure.unsquared {
  348. margin-bottom: 1.5rem;
  349. }
  350. figure.unsquared img {
  351. height: inherit;
  352. }
  353. @media print {
  354. body { font-size: 100%; }
  355. a:after { content: " (" attr(href) ")"; }
  356. a, a:link, a:visited, a:after {
  357. text-decoration: underline;
  358. text-shadow: none !important;
  359. background-image: none !important;
  360. background: white;
  361. color: black;
  362. }
  363. abbr[title] { border-bottom: 0; }
  364. abbr[title]:after { content: " (" attr(title) ")"; }
  365. img { page-break-inside: avoid; }
  366. @page { margin: 2cm .5cm; }
  367. h1, h2, h3 { page-break-after: avoid; }
  368. p3 { orphans: 3; widows: 3; }
  369. img {
  370. max-width: 250px !important;
  371. max-height: 250px !important;
  372. }
  373. nav, aside { display: none; }
  374. }
  375. ul.with_columns {
  376. column-count: 1;
  377. }
  378. @media (min-width: 20em) {
  379. ul.with_columns {
  380. column-count: 2;
  381. }
  382. }
  383. @media (min-width: 50em) {
  384. ul.with_columns {
  385. column-count: 3;
  386. }
  387. }
  388. ul.with_two_columns {
  389. column-count: 1;
  390. }
  391. @media (min-width: 20em) {
  392. ul.with_two_columns {
  393. column-count: 1;
  394. }
  395. }
  396. @media (min-width: 50em) {
  397. ul.with_two_columns {
  398. column-count: 2;
  399. }
  400. }
  401. .gallery {
  402. display: flex;
  403. flex-wrap: wrap;
  404. justify-content: space-around;
  405. }
  406. .gallery figure img {
  407. margin-left: 1rem;
  408. margin-right: 1rem;
  409. }
  410. .gallery figure figcaption {
  411. font-family: 'ConcourseT3'
  412. }
  413. footer {
  414. font-family: 'ConcourseT3';
  415. display: flex;
  416. flex-direction: column;
  417. border-top: 3px solid white;
  418. padding: 4rem 0;
  419. background-color: #07486c;
  420. color: white;
  421. }
  422. footer > * {
  423. max-width: 50rem;
  424. margin: 0 auto;
  425. }
  426. footer a {
  427. color: #f1c40f;
  428. }
  429. footer .avatar {
  430. width: 200px;
  431. height: 200px;
  432. border-radius: 50%;
  433. float: left;
  434. -webkit-shape-outside: circle();
  435. shape-outside: circle();
  436. margin-right: 2rem;
  437. padding: 2px 5px 5px 2px;
  438. background: white;
  439. border-left: 1px solid #f1c40f;
  440. border-top: 1px solid #f1c40f;
  441. border-right: 5px solid #f1c40f;
  442. border-bottom: 5px solid #f1c40f;
  443. }
  444. </style>
  445. <h1 class="single">
  446. <span><a id="jumper" href="#jumpto" title="Un peu perdu ?">?</a></span>
  447. Un Web orienté composants
  448. <time>Publié le 8 octobre 2013</time>
  449. </h1>
  450. <article class="single">
  451. <p><em>Article initialement publié pour <a href="http://letrainde13h37.fr/">le magazine le train de 13h37</a> avec pour titre <a href="http://letrainde13h37.fr/45/web-oriente-composants/">Un Web orienté composants</a> sous <a href="https://creativecommons.org/licenses/by-nc-sa/2.0/fr/legalcode">licence CC BY-NC-SA</a> et <a href="/david/blog/2014/rapatriement-articles/">rapatrié depuis sur cet espace</a>.</em></p>
  452. <p>Si vous avez eu l’occasion dans votre carrière d’utiliser Flash ou — soyons fous — des <a href="https://fr.wikipedia.org/wiki/Applet_Java">applets Java</a>, vous êtes déjà familier avec la notion de composant. Il s’agit d’un élément de base pouvant être réutilisé, assemblé, combiné, étendu dans le but de faciliter un développement. Dans le cadre des <em>Web Components</em>, il s’agit d’éléments <code>HTML</code> embarquant leurs propres <code>CSS</code> et <code>JavaScript</code> afin d’avoir <strong>nativement</strong> un rendu et un comportement uniformes lors de leurs utilisations dans une page ou une application web. Un composant peut aller d’un simple bouton à un <em>widget</em> complet en passant par un élément non-visuel (comme une connexion <em>AJAX</em>) mais nous allons détailler tout cela par la suite.</p>
  453. <p><strong>Attention :</strong> les <em>Web Components</em> sont encore en cours de spécification et les <em>polyfills</em> comme <em>X-Tag</em> ou <em>Polymer</em> dont il est question dans la suite de l’article évoluent très vite. Il est pour l’instant déconseillé d’utiliser ces technologies en production car elles sont relativement instables, on vous aura prévenu(e)s !</p>
  454. <h2>Des concepts en cours de standardisation…</h2>
  455. <p>Poussés par l’équipe Chrome de Google, les <em>Web Components</em> sont <a href="https://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html">en cours de standardisation</a> via le processus classique du W3C, à l’état de brouillon. Le modèle de composant se découpe en 5 parties :</p>
  456. <ul>
  457. <li><strong>Les templates</strong> : permettent de définir des fragments de <code>HTML</code> pour une utilisation future sans qu’ils soient interprétés ;</li>
  458. <li><strong>Les décorateurs</strong> : pour styler les <em>templates</em> sans que les styles <code>CSS</code> s’appliquent aux autres éléments de la page ;</li>
  459. <li><strong>Les custom elements</strong> : pour permettre aux développeurs de définir leurs propres éléments avec leurs propres tags <code>HTML</code> ;</li>
  460. <li><strong>Le Shadow DOM</strong> : qui encapsule un élément complet <a href="http://glazkov.com/2011/01/14/what-the-heck-is-shadow-dom/">à la manière des widgets natifs des navigateurs</a> ;</li>
  461. <li><strong>Les imports</strong> : afin de pouvoir charger des <em>composants</em> depuis une adresse distante.</li>
  462. </ul>
  463. <p>Note : d’autres innovations sont en cours d’exploration comme les <em>Pointers Events</em>, les <em>Web Animations</em> ou les <em>Model Driven View</em> mais ça commence à faire beaucoup pour un seul article !</p>
  464. <p>À ces spécifications s’ajoute le fait de pouvoir <a href="http://weblog.bocoup.com/javascript-object-observe/">observer un objet</a> <code>JavaScript</code> grâce à <code>Object.observe</code> (ou <em>Mutation Observers</em> si vous voulez briller en société) et modifier le DOM à la volée.</p>
  465. <h2>…mais des fonctionnalités déjà utilisables !</h2>
  466. <p>Ces spécifications ne sont bien évidement pas encore implémentées dans les navigateurs — même très récents — c’est pourquoi des équipes de développeurs courageux codent en <code>JavaScript</code> des compléments appelés <em>polyfills</em> qui miment le comportement que devrait avoir chaque navigateur s’il implémentait les spécifications des <em>Web Components</em>. Ces ajouts deviendront inutiles lorsque les différents moteurs de rendus auront travaillé sur ces spécifications.</p>
  467. <p>Il existe 2 projets pour utiliser dès maintenant les <em>Web Components</em> : <a href="http://x-tags.org/">X-Tag</a> par Mozilla et <a href="http://www.polymer-project.org/">Polymer</a> par Google. Une compatibilité partielle est prévue entre ces deux projets et nous allons nous concentrer sur Polymer dans la suite de cet article.</p>
  468. <h2>Une nouvelle façon de penser ses pages</h2>
  469. <p>Si vous connaissez <a href="http://fr.slideshare.net/stubbornella/styleguide-jsconf">les concepts sous-jacents</a> des <a href="http://oocss.org/">CSS Orientées Objets</a>, sachez que les <em>Web Components</em> vont encore plus loin en proposant de véritables composants indépendants, réutilisables et pleinement fonctionnels. Ils ne se limitent pas au style mais intègrent aussi le comportement, autrement dit la logique qui régit le cycle de vie du composant et ses interactions avec l’utilisateur.</p>
  470. <p>Si ces dernières années ont fait la part belle aux <em>frameworks</em> <code>CSS</code> comme <a href="http://twitter.github.io/bootstrap/">Bootstrap</a>, <a href="http://foundation.zurb.com/">Foundation</a> ou <a href="http://purecss.io/">Pure</a>, <strong>ces prochains mois vont voir l’émergence de <em>toolkits</em> proposant des briques de composants aux styles unifiés et aux comportement extensibles.</strong> Certains projets comme <a href="http://mozilla.github.io/brick/">Brick</a> ou <a href="http://janmiksovsky.github.io/quetzal/">Quetzal</a> ont d’ailleurs vu le jour dans ce sens. Mais assez de théorie et voyons voir ce à quoi ressemble concrètement un composant web.</p>
  471. <h2>Un exemple d’application</h2>
  472. <p>Nous allons créer un composant permettant d’afficher de manière synthétique les informations relatives à un dépôt Github sur ces propres pages. C’est ce que fait déjà plus ou moins le plugin <a href="https://github.com/JoelSutherland/GitHub-jQuery-Repo-Widget">GitHub jQuery Repo Widget</a> dont nous allons nous inspirer.</p>
  473. <p>Notre objectif est de pouvoir intégrer facilement le composant dans nos pages de la manière suivante :</p>
  474. <div class="wp_syntax"><table><tr><td class="code"><pre class="html5" style="font-family:monospace;"><span style="color: #009900;">&lt;github-repository repository<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;scopyleft/web-components&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span>github-repository&gt;</span></pre></td></tr></table></div>
  475. <p>Cette simple ligne devant afficher le composant relatif au dépôt passé en paramètre avec les styles dédiés et un chargement dynamique des informations en JavaScript. La première étape est de créer notre page <code>HTML 5</code>, appelons-la dans un excès d’originalité <code>index.html</code> :</p>
  476. <div class="wp_syntax"><table><tr><td class="code"><pre class="html5" style="font-family:monospace;"><span style="color: #00bbdd;">&lt;!DOCTYPE html&gt;</span>
  477. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">html</span>&gt;</span>
  478. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">head</span>&gt;</span>
  479. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;polymer.min.js&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;</span>
  480. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">link</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;import&quot;</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;github-repository.html&quot;</span>&gt;</span>
  481. <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">head</span>&gt;</span>
  482. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">body</span>&gt;</span>
  483. <span style="color: #009900;">&lt;github-repository repository<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;scopyleft/web-components&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span>github-repository&gt;</span>
  484. <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">body</span>&gt;</span>
  485. <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">html</span>&gt;</span></pre></td></tr></table></div>
  486. <p>On commence par charger la bibliothèque <code>polymer.min.js</code> (ce fichier s’appelle actuellement <code>polymer-v0.0.20130912.min.js</code> si vous téléchargez l’archive directement sur le site) et on importe l’élément <code>github-repository</code> depuis une autre page web au nom éponyme (cela n’est pas obligatoire mais c’est une bonne pratique pour avoir des composants réutilisables). On peut maintenant lancer un serveur local, si vous avez Python il suffit de taper cette commande dans le dossier contenant le fichier <code>index.html</code> nouvellement créé :</p>
  487. <div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666;">$ </span>python <span style="color: #660033;">-m</span> SimpleHTTPServer <span style="color: #000000;">8765</span></pre></td></tr></table></div>
  488. <p>Si vous n’avez pas python, vous pouvez configurer un serveur Apache ou n’importe quelle solution permettant de servir des pages web depuis le dossier courant.</p>
  489. <p>En accédant à <code>http://localhost:8765</code> vous devriez avoir une page blanche et la console devrait vous indiquer que l’URL <code>github-repository.html</code> vous renvoie une 404. Normal, nous ne l’avons pas encore créée ! Créons ce fichier localement en commençant notre composant avec un attribut <code>repository</code> puisque l’on souhaite le rendre dynamique :</p>
  490. <div class="wp_syntax"><table><tr><td class="code"><pre class="html5" style="font-family:monospace;"><span style="color: #009900;">&lt;polymer-element <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;github-repository&quot;</span> attributes<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;repository&quot;</span>&gt;</span></pre></td></tr></table></div>
  491. <p>Il est ensuite composé de 2 parties, la première contenant les styles et le html sous la balise <code>template</code> :</p>
  492. <div class="wp_syntax"><table><tr><td class="code"><pre class="html5" style="font-family:monospace;"><span style="color: #009900;">&lt;template&gt;</span>
  493. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">style</span>&gt;</span>
  494. @host {
  495. :scope {font-family:helvetica,arial,sans-serif;font-size:13px;line-height:18px;background:#fafafa;border:1px solid #ddd;color:#666;border-radius:3px}
  496. :scope a{color:#4183c4;border:0;text-decoration:none}
  497. :scope.github-box-title{position:relative;border-bottom:1px solid #ddd;border-radius:3px 3px 0 0;background:#fcfcfc;background:-moz-linear-gradient(#fcfcfc,#ebebeb);background:-webkit-linear-gradient(#fcfcfc,#ebebeb);}
  498. :scope.github-box-title h3{font-family:helvetica,arial,sans-serif;font-weight:normal;font-size:16px;color:gray;margin:0;padding:10px 10px 10px 30px;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAXCAMAAAAx3e/WAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIE1hY2ludG9zaCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpEQjIyNkJERkM0NjYxMUUxOEFDQzk3ODcxRDkzRjhCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpEQjIyNkJFMEM0NjYxMUUxOEFDQzk3ODcxRDkzRjhCRSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkRCMjI2QkREQzQ2NjExRTE4QUNDOTc4NzFEOTNGOEJFIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkRCMjI2QkRFQzQ2NjExRTE4QUNDOTc4NzFEOTNGOEJFIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+dka2KgAAAEVQTFRFxMTEyMjI0tLSvb29vr6+zc3Ny8vLxcXFz8/P6enp3t7ex8fH0dHR1NTUw8PDwMDAzs7OvLy8wcHBu7u7v7+/zMzM////budQFwAAABd0Uk5T/////////////////////////////wDmQOZeAAAAcklEQVR42tSQSQ7DMAwD6chOukWs5eX/Ty2coo0T9wOdEzEgdRBuzNmnDofgja52JDyz5TCqUp0O6kfrb4bzSXkRiTviEZZ6JKLMJ5VQ2v8iGbtbfEwXmjFMG0VwdQo10hQNxYqtLMv9O6xvpZ/QeAkwAKjwHiJLaJc3AAAAAElFTkSuQmCC') 7px center no-repeat}
  499. :scope.github-box-title h3.repo{font-weight:bold}
  500. :scope.github-box-title.github-stats{position:absolute;top:8px;right:10px;background:white;border:1px solid #ddd;border-radius:3px;font-size:11px;font-weight:bold;line-height:21px;height:21px}
  501. :scope.github-box-title.github-stats a{display:inline-block;height:21px;color:#666;padding:0 5px 0 18px;background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAqCAMAAACEJ4viAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIE1hY2ludG9zaCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpEQjIyNkJEQkM0NjYxMUUxOEFDQzk3ODcxRDkzRjhCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpEQjIyNkJEQ0M0NjYxMUUxOEFDQzk3ODcxRDkzRjhCRSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkRCMjI2QkQ5QzQ2NjExRTE4QUNDOTc4NzFEOTNGOEJFIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkRCMjI2QkRBQzQ2NjExRTE4QUNDOTc4NzFEOTNGOEJFIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+h1kA9gAAAK5QTFRF+fn5sbGx8fHx09PTmpqa2dnZ/f3919fX9PT00NDQ1dXVpKSk+vr6+/v7vb298vLyycnJ8/PztLS0zc3N6enp/v7+q6ur2NjY9/f3srKy/Pz8p6en7u7uoaGhnJyc4eHhtbW1pqam6Ojo9fX17e3toqKirKys1NTUzs7Ox8fHwcHBwMDA5eXlnZ2dpaWl0dHR9vb25ubm4uLi3d3dqqqqwsLCv7+/oKCgmZmZ////8yEsbwAAAMBJREFUeNrE0tcOgjAUBuDSliUoMhTEvfdef9//xUQjgaLX0Ium/ZLT/+SkRPxZpGykvuf5VMJogy5jY9yjDHcWFhqlcRuHc4o6B1QK0BDg+hcZgNDh3NWTwzItH/bRrhvT+g3zSxZkNGCZpoWGIbU0a3Y6zV5VA6keyeDxiw62P0gUqEW0FbDim4nVikFJbU2zZXybUEaxhCqOQqyh5/G0wpWICUwthyqwD4InOMuXJ7/gs7WkoPdVg1vykF8CDACEFanKO3aSYwAAAABJRU5ErkJggg==') no-repeat}
  502. :scope.github-box-title.github-stats.watchers{border-right:1px solid #ddd}
  503. :scope.github-box-title.github-stats.forks{background-position:-4px -21px;padding-left:15px}
  504. :scope.github-box-content{padding:10px;font-weight:300}
  505. :scope.github-box-content p{margin:0}
  506. :scope.github-box-content.link{font-weight:bold}
  507. :scope.github-box-download{position:relative;border-top:1px solid #ddd;background:white;border-radius:0 0 3px 3px;padding:10px;height:24px}
  508. :scope.github-box-download.updated{margin:0;font-size:11px;color:#666;line-height:24px;font-weight:300}
  509. :scope.github-box-download.updated strong{font-weight:bold;color:#000}
  510. :scope.github-box-download.download{position:absolute;display:block;top:10px;right:10px;height:24px;line-height:24px;font-size:12px;color:#666;font-weight:bold;text-shadow:0 1px 0 rgba(255,255,255,0.9);padding:0 10px;border:1px solid #ddd;border-bottom-color:#bbb;border-radius:3px;background:#f5f5f5;background:-moz-linear-gradient(#f5f5f5,#e5e5e5);background:-webkit-linear-gradient(#f5f5f5,#e5e5e5);}
  511. :scope.github-box-download.download:hover{color:#527894;border-color:#cfe3ed;border-bottom-color:#9fc7db;background:#f1f7fa;background:-moz-linear-gradient(#f1f7fa,#dbeaf1);background:-webkit-linear-gradient(#f1f7fa,#dbeaf1);}
  512. }
  513. <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">style</span>&gt;</span>
  514. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;repo&quot;</span> <span style="color: #000066;">style</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;width: {{ width }}&quot;</span>&gt;</span>
  515. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;github-box-title&quot;</span>&gt;</span>
  516. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h3</span>&gt;</span>
  517. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;owner&quot;</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;{{ ownerUrl }}&quot;</span>&gt;</span>{{ login }}<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span>
  518. /
  519. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;repo&quot;</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;{{ repoUrl }}&quot;</span>&gt;</span>{{ name }}<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span>
  520. <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h3</span>&gt;</span>
  521. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;github-stats&quot;</span>&gt;</span>
  522. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;watchers&quot;</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;{{ watchersUrl }}&quot;</span>&gt;</span>{{ watchers }}<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span>
  523. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;forks&quot;</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;{{ forksUrl }}&quot;</span>&gt;</span>{{ forks }}<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span>
  524. <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span>
  525. <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span>
  526. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;github-box-content&quot;</span>&gt;</span>
  527. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">p</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;description&quot;</span>&gt;</span>{{ description }} <span style="color: #ddbb00;">&amp;mdash;</span> <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;{{ readmeUrl }}&quot;</span>&gt;</span>Read More<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">p</span>&gt;</span>
  528. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">p</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;link&quot;</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;{{ homepage }}&quot;</span>&gt;</span>{{ homepage }}<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">p</span>&gt;</span>
  529. <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span>
  530. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;github-box-download&quot;</span>&gt;</span>
  531. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">p</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;updated&quot;</span>&gt;</span>Latest commit to the <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">strong</span>&gt;</span>master<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">strong</span>&gt;</span> branch on {{ pushedAt }}<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">p</span>&gt;</span>
  532. <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;download&quot;</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;{{ downloadUrl }}&quot;</span>&gt;</span>Download as zip<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span>
  533. <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span>
  534. <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span>
  535. <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span>template&gt;</span></pre></td></tr></table></div>
  536. <p>Cela fait beaucoup d’information mais il ne faut pas s’affoler, les <code>CSS</code> sont assez verbeuses car elles intègrent les images mais sont juste là pour définir les styles propres à Github. Il s’agit de déclaration classiques qui peuvent être <em>inline</em> comme ici ou plus aérées. La seule particularité est relative à la combinaison du <code>@host</code> et du <code>:scope</code> qui permettent de restreindre les styles au composant, pratique lorsque l’on souhaite intégrer des composants de plusieurs provenances ! Il est possible de remplacer le <code>:scope</code> par un <code>id</code> sur la <code>div</code> principale mais cela est moins élégant (notez que <a href="https://www.w3.org/Bugs/Public/show_bug.cgi?id=22390">la syntaxe pourrait changer prochainement</a>).</p>
  537. <p>La partie <code>HTML</code> est plus intéressante avec l’utilisation de variables écrites entre <code>{{ }}</code>, syntaxe avec laquelle vous êtes peut-être déjà familier. Celles-ci seront complétées directement avec le <code>JavaScript</code> qui est inséré à la suite du fichier dans une balise <code>&lt;script&gt;</code> :</p>
  538. <div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #339933;">&lt;</span>script<span style="color: #339933;">&gt;</span>
  539. Polymer<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'github-repository'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span>
  540. width<span style="color: #339933;">:</span> <span style="color: #3366CC;">'500px'</span><span style="color: #339933;">,</span>
  541. created<span style="color: #339933;">:</span> <span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  542. <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">vendorName</span> <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">repository</span>.<span style="color: #660066;">split</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'/'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
  543. <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">repoName</span> <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">repository</span>.<span style="color: #660066;">split</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'/'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
  544. <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
  545. enteredView<span style="color: #339933;">:</span> <span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  546. <span style="color: #000066; font-weight: bold;">var</span> url <span style="color: #339933;">=</span> <span style="color: #3366CC;">'https://api.github.com/repos/'</span> <span style="color: #339933;">+</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">repository</span><span style="color: #339933;">,</span>
  547. httpRequest <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">new</span> XMLHttpRequest<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
  548. self <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">this</span><span style="color: #339933;">;</span>
  549. httpRequest.<span style="color: #660066;">open</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'GET'</span><span style="color: #339933;">,</span> url<span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  550. httpRequest.<span style="color: #660066;">send</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  551. httpRequest.<span style="color: #660066;">onreadystatechange</span> <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  552. <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">status</span> <span style="color: #339933;">!==</span> <span style="color: #CC0000;">200</span> <span style="color: #339933;">||</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">readyState</span> <span style="color: #339933;">!==</span> <span style="color: #CC0000;">4</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  553. <span style="color: #000066; font-weight: bold;">return</span><span style="color: #339933;">;</span>
  554. <span style="color: #009900;">&#125;</span>
  555. <span style="color: #000066; font-weight: bold;">var</span> repo <span style="color: #339933;">=</span> JSON.<span style="color: #660066;">parse</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">responseText</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  556. self.<span style="color: #660066;">login</span> <span style="color: #339933;">=</span> repo.<span style="color: #660066;">owner</span>.<span style="color: #660066;">login</span><span style="color: #339933;">;</span>
  557. self.<span style="color: #660066;">ownerUrl</span> <span style="color: #339933;">=</span> repo.<span style="color: #660066;">owner</span>.<span style="color: #660066;">html_url</span><span style="color: #339933;">;</span>
  558. self.<span style="color: #660066;">name</span> <span style="color: #339933;">=</span> repo.<span style="color: #660066;">name</span><span style="color: #339933;">;</span>
  559. self.<span style="color: #660066;">repoUrl</span> <span style="color: #339933;">=</span> repo.<span style="color: #660066;">html_url</span>
  560. self.<span style="color: #660066;">watchers</span> <span style="color: #339933;">=</span> repo.<span style="color: #660066;">watchers</span><span style="color: #339933;">;</span>
  561. self.<span style="color: #660066;">watchersUrl</span> <span style="color: #339933;">=</span> self.<span style="color: #660066;">repoUrl</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;/watchers&quot;</span><span style="color: #339933;">;</span>
  562. self.<span style="color: #660066;">forks</span> <span style="color: #339933;">=</span> repo.<span style="color: #660066;">forks</span><span style="color: #339933;">;</span>
  563. self.<span style="color: #660066;">forksUrl</span> <span style="color: #339933;">=</span> self.<span style="color: #660066;">repoUrl</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;/forks&quot;</span><span style="color: #339933;">;</span>
  564. self.<span style="color: #660066;">description</span> <span style="color: #339933;">=</span> repo.<span style="color: #660066;">description</span><span style="color: #339933;">;</span>
  565. self.<span style="color: #660066;">homepage</span> <span style="color: #339933;">=</span> repo.<span style="color: #660066;">homepage</span><span style="color: #339933;">;</span>
  566. <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>repo.<span style="color: #660066;">has_wiki</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  567. self.<span style="color: #660066;">readmeUrl</span> <span style="color: #339933;">=</span> self.<span style="color: #660066;">repoUrl</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;#readme&quot;</span><span style="color: #339933;">;</span>
  568. <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
  569. <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>repo.<span style="color: #660066;">pushed_at</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  570. date <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">new</span> <span style="">Date</span><span style="color: #009900;">&#40;</span>repo.<span style="color: #660066;">pushed_at</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  571. <span style="color: #000066; font-weight: bold;">function</span> pad<span style="color: #009900;">&#40;</span>n<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> n<span style="color: #339933;">&lt;</span><span style="color: #CC0000;">10</span> <span style="color: #339933;">?</span> <span style="color: #3366CC;">'0'</span><span style="color: #339933;">+</span>n <span style="color: #339933;">:</span> n <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
  572. self.<span style="color: #660066;">pushedAt</span> <span style="color: #339933;">=</span> date.<span style="color: #660066;">getFullYear</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">'-'</span> <span style="color: #339933;">+</span> pad<span style="color: #009900;">&#40;</span>date.<span style="color: #660066;">getMonth</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">'-'</span> <span style="color: #339933;">+</span> pad<span style="color: #009900;">&#40;</span>date.<span style="color: #660066;">getDate</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  573. <span style="color: #009900;">&#125;</span>
  574. self.<span style="color: #660066;">downloadUrl</span> <span style="color: #339933;">=</span> self.<span style="color: #660066;">repoUrl</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;/zipball/master&quot;</span><span style="color: #339933;">;</span>
  575. <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
  576. <span style="color: #009900;">&#125;</span>
  577. <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  578. <span style="color: #339933;">&lt;/</span>script<span style="color: #339933;">&gt;</span></pre></td></tr></table></div>
  579. <p>On commence par définir la largeur par défaut du composant, avec une valeur par défaut de 500 pixels (le lecteur bidouilleur pourra tenter de rendre cette valeur dynamique en la passant en attribut). La fonction <code>created</code> est appelée à l’instanciation et permet de définir le nom d’utilisateur et le dépôt concernés.</p>
  580. <p>La fonction <code>enteredView</code> est la plus intéressante car elle permet d’effectuer la requête <code>AJAX</code> récupérant les informations du dépôt et de remplacer <em>automagiquement</em> celles-ci dans le <code>template</code> précédemment défini.</p>
  581. <p>On n’oublie bien évidemment pas de refermer la balise <code>&lt;/polymer-element&gt;</code> à la fin de notre fichier. En rafraichissant la page, vous devriez apercevoir votre composant apparaître avec les informations relatives au dépôt que vous avez renseigné en attribut du composant (ici <code>scopyleft/web-components</code>).</p>
  582. <h2>Et la suite ?</h2>
  583. <p>Deux vidéos en anglais d’interventions réalisées dans le cadre de Google I/O font référence à ce jour et permettent de voir les exemples en pratique si vous n’êtes pas encore prêt(e) à mettre les mains dans le code :</p>
  584. <ul>
  585. <li><a href="https://www.youtube.com/watch?v=fqULJBBEVQE">Web Components: A Tectonic Shift for Web Development</a></li>
  586. <li><a href="https://www.youtube.com/watch?v=0g0oOOT86NY">Web Components in Action</a></li>
  587. </ul>
  588. <p>Miško Hevery, l’un des co-créateurs d’<a href="http://angularjs.org/">AngularJS</a>, s’est déjà prononcé en faveur d’une intégration partielle et d’une compatibilité avec les <em>Web Components</em> développé avec Polymer pour la version 2.0 du framework <a href="https://groups.google.com/forum/#!msg/polymer-dev/4RSYaKmbtEk/uYnY3900wpIJ">sur la liste de diffusion du développement de Polymer</a>.</p>
  589. <p>En ce qui concerne <a href="http://emberjs.com/">EmberJS</a>, c’est plus compliqué en raison des problématiques de performances que cela entraîne mais <a href="https://gist.github.com/wycats/9144666b0c606d1838be">l’objectif à long terme</a> est d’être compatible également.</p>
  590. <p>Autant d’encouragements pour développer (et <a href="http://customelements.io/">partager</a>) dès à présent votre <em>toolkit</em> de composants web afin de passer <a href="http://bradfrostweb.com/blog/post/atomic-web-design/">d’un développement atomique</a> à un développement moléculaire ! Les <em>Web Components</em> ont certainement <a href="http://insideintercom.io/why-cards-are-the-future-of-the-web/">leur carte à jouer</a> dans l’avenir du Web et de ses interactions.</p>
  591. </article>
  592. <nav id="jumpto">
  593. <p>
  594. <a rel=prev href="/david/blog/2013/donnees-intimes/">← Données intimes</a> | <a href="/david/blog/" title="Retour à la liste des expériences">↑</a> | <a rel=next href="/david/blog/2013/confort-convivialite/">Confort et convivialité →</a>
  595. </p>
  596. </nav>
  597. <footer>
  598. <div>
  599. <img src="/static/david/david-larlet-avatar.jpg" loading="lazy" class="avatar" width="200" height="200">
  600. <p>
  601. Bonjour/Hi!
  602. Je suis <a href="/david/" title="Profil public">David&nbsp;Larlet</a>, je vis actuellement à Montréal et j’alimente cet espace depuis 15 ans. <br>
  603. Si tu as apprécié cette lecture, n’hésite pas à poursuivre ton exploration. Par exemple via les <a href="/david/blog/" title="Expériences bienveillantes">réflexions bimestrielles</a>, la <a href="/david/stream/2019/" title="Pensées (dés)articulées">veille hebdomadaire</a> ou en t’abonnant au <a href="/david/log/" title="S’abonner aux publications via RSS">flux RSS</a> (<a href="/david/blog/2019/flux-rss/" title="Tiens c’est quoi un flux RSS ?">so 2005</a>).
  604. </p>
  605. <p>
  606. Je m’intéresse à la place que je peux avoir dans ce monde. En tant qu’humain, en tant que membre d’une famille et en tant qu’associé d’une coopérative. De temps en temps, je fais aussi des <a href="https://github.com/davidbgk" title="Principalement sur Github mais aussi ailleurs">trucs techniques</a>. Et encore plus rarement, <a href="/david/talks/" title="En ce moment je laisse plutôt la place aux autres">j’en parle</a>.
  607. </p>
  608. <p>
  609. Les dernières publications hebdomadaires sont :
  610. </p>
  611. <ul class="with_columns">
  612. <li>
  613. <a href="/david/stream/2019/12/31/">Merci</a>
  614. </li>
  615. <li>
  616. <a href="/david/stream/2019/12/27/">Intemporels</a>
  617. </li>
  618. <li>
  619. <a href="/david/stream/2019/12/24/">Outils</a>
  620. </li>
  621. <li>
  622. <a href="/david/stream/2019/12/17/">Origines</a>
  623. </li>
  624. <li>
  625. <a href="/david/stream/2019/12/10/">Publier</a>
  626. </li>
  627. <li>
  628. <a href="/david/stream/2019/12/03/">En forêt</a>
  629. </li>
  630. <li>
  631. <a href="/david/stream/2019/11/26/">Ecocentric</a>
  632. </li>
  633. <li>
  634. <a href="/david/stream/2019/11/19/">Se livrer</a>
  635. </li>
  636. <li>
  637. <a href="/david/stream/2019/11/12/">Dépendances</a>
  638. </li>
  639. <li>
  640. <a href="/david/stream/2019/11/05/">Positif</a>
  641. </li>
  642. <li>
  643. <a href="/david/stream/2019/10/29/">Dettes</a>
  644. </li>
  645. <li>
  646. <a href="/david/stream/2019/10/22/">Privilèges</a>
  647. </li>
  648. <li>
  649. <a href="/david/stream/2019/10/15/">Discrétion</a>
  650. </li>
  651. <li>
  652. <a href="/david/stream/2019/10/08/">Désespérance</a>
  653. </li>
  654. <li>
  655. <a href="/david/stream/2019/10/01/">Présent</a>
  656. </li>
  657. <li>
  658. <a href="/david/stream/2019/09/24/">Manifester</a>
  659. </li>
  660. <li>
  661. <a href="/david/stream/2019/09/17/">Arpenter</a>
  662. </li>
  663. <li>
  664. <a href="/david/stream/2019/09/10/">Nostalgie</a>
  665. </li>
  666. <li>
  667. <a href="/david/stream/2019/09/03/">Déconstruire</a>
  668. </li>
  669. <li>
  670. <a href="/david/stream/2019/08/27/">Documenter</a>
  671. </li>
  672. <li>
  673. <a href="/david/stream/2019/08/20/">Frustration</a>
  674. </li>
  675. <li>
  676. <a href="/david/stream/2019/08/13/">Holisme</a>
  677. </li>
  678. <li>
  679. <a href="/david/stream/2019/08/06/">1%</a>
  680. </li>
  681. <li>
  682. <a href="/david/stream/2019/07/30/">Exemplarité</a>
  683. </li>
  684. <li>
  685. <a href="/david/stream/2019/07/23/">Timelines</a>
  686. </li>
  687. <li>
  688. <a href="/david/stream/2019/07/16/">Écoute</a>
  689. </li>
  690. <li>
  691. <a href="/david/stream/2019/07/02/">Anxiété</a>
  692. </li>
  693. <li>
  694. <a href="/david/stream/2019/06/21/">À lier</a>
  695. </li>
  696. <li>
  697. <a href="/david/stream/2019/06/14/">Pauvreté</a>
  698. </li>
  699. <li>
  700. <a href="/david/stream/2019/06/07/">Amateur</a>
  701. </li>
  702. <li>
  703. <a href="/david/stream/2019/05/31/">Pollution</a>
  704. </li>
  705. <li>
  706. <a href="/david/stream/2019/05/24/">Apaisement</a>
  707. </li>
  708. <li>
  709. <a href="/david/stream/2019/05/10/">Folie</a>
  710. </li>
  711. <li>
  712. <a href="/david/stream/2019/05/03/">Sympathie</a>
  713. </li>
  714. <li>
  715. <a href="/david/stream/2019/04/12/">Péremption</a>
  716. </li>
  717. <li>
  718. <a href="/david/stream/2019/04/05/">Définitions</a>
  719. </li>
  720. <li>
  721. <a href="/david/stream/2019/03/29/">Acceptation</a>
  722. </li>
  723. <li>
  724. <a href="/david/stream/2019/03/22/">Dissonance</a>
  725. </li>
  726. <li>
  727. <a href="/david/stream/2019/03/15/">Reconnaissance</a>
  728. </li>
  729. <li>
  730. <a href="/david/stream/2019/03/08/">Lecture</a>
  731. </li>
  732. <li>
  733. <a href="/david/stream/2019/03/01/">Journaux</a>
  734. </li>
  735. <li>
  736. <a href="/david/stream/2019/02/22/">Écriture</a>
  737. </li>
  738. <li>
  739. <a href="/david/stream/2019/02/15/">Kyriarchie</a>
  740. </li>
  741. <li>
  742. <a href="/david/stream/2019/02/08/">Mots-serrures</a>
  743. </li>
  744. <li>
  745. <a href="/david/stream/2019/02/01/">Sans voie</a>
  746. </li>
  747. <li>
  748. <a href="/david/stream/2019/01/25/">Auto-diagnostic</a>
  749. </li>
  750. <li>
  751. <a href="/david/stream/2019/01/18/">Agilité</a>
  752. </li>
  753. <li>
  754. <a href="/david/stream/2019/01/11/">Métaphores</a>
  755. </li>
  756. <li>
  757. <a href="/david/stream/2019/01/04/">Balbutiements</a>
  758. </li>
  759. </ul>
  760. <p>
  761. Voici quelques articles choisis :
  762. <a href="/david/blog/2019/faire-equipe/" title="Accéder à l’article complet">Faire équipe</a>,
  763. <a href="/david/blog/2018/bivouac-automnal/" title="Accéder à l’article complet">Bivouac automnal</a>,
  764. <a href="/david/blog/2018/commodite-effondrement/" title="Accéder à l’article complet">Commodité et effondrement</a>,
  765. <a href="/david/blog/2017/donnees-communs/" title="Accéder à l’article complet">Des données aux communs</a>,
  766. <a href="/david/blog/2016/accompagner-enfant/" title="Accéder à l’article complet">Accompagner un enfant</a>,
  767. <a href="/david/blog/2016/senior-developer/" title="Accéder à l’article complet">Senior developer</a>,
  768. <a href="/david/blog/2016/illusion-sociale/" title="Accéder à l’article complet">L’illusion sociale</a>,
  769. <a href="/david/blog/2016/instantane-scopyleft/" title="Accéder à l’article complet">Instantané Scopyleft</a>,
  770. <a href="/david/blog/2016/enseigner-web/" title="Accéder à l’article complet">Enseigner le Web</a>,
  771. <a href="/david/blog/2016/simplicite-defaut/" title="Accéder à l’article complet">Simplicité par défaut</a>,
  772. <a href="/david/blog/2016/minimalisme-esthetique/" title="Accéder à l’article complet">Minimalisme et esthétique</a>,
  773. <a href="/david/blog/2014/un-web-omni-present/" title="Accéder à l’article complet">Un web omni-présent</a>,
  774. <a href="/david/blog/2014/manifeste-developpeur/" title="Accéder à l’article complet">Manifeste de développeur</a>,
  775. <a href="/david/blog/2013/confort-convivialite/" title="Accéder à l’article complet">Confort et convivialité</a>,
  776. <a href="/david/blog/2013/testament-numerique/" title="Accéder à l’article complet">Testament numérique</a>,
  777. et <a href="/david/blog/" title="Accéder aux archives">bien d’autres…</a>
  778. </p>
  779. <p>
  780. On peut <a href="mailto:david%40larlet.fr" title="Envoyer un courriel">échanger par courriel</a>. Si éventuellement tu souhaites que l’on travaille ensemble, tu devrais commencer par consulter le <a href="http://larlet.com">profil dédié à mon activité professionnelle</a> et/ou contacter directement <a href="http://scopyleft.fr/">scopyleft</a>, la <abbr title="Société coopérative et participative">SCOP</abbr> dont je fais partie depuis six ans. Je recommande au préalable de lire <a href="/david/blog/2018/cout-site/" title="Attention ce qui va suivre peut vous choquer">combien coûte un site</a> et pourquoi je suis plutôt favorable à une <a href="/david/pro/devis/" title="Discutons-en !">non-demande de devis</a>.
  781. </p>
  782. <p>
  783. Je ne traque pas ta navigation mais mon
  784. <abbr title="Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33.184162340">hébergeur</abbr>
  785. conserve des logs d’accès.
  786. </p>
  787. </div>
  788. </footer>
  789. <script type="text/javascript">
  790. ;(_ => {
  791. const jumper = document.getElementById('jumper')
  792. jumper.addEventListener('click', e => {
  793. e.preventDefault()
  794. const anchor = e.target.getAttribute('href')
  795. const targetEl = document.getElementById(anchor.substring(1))
  796. targetEl.scrollIntoView({behavior: 'smooth'})
  797. })
  798. })()
  799. </script>
  800. <script>
  801. /* Service workers */
  802. if (navigator.serviceWorker) {
  803. window.addEventListener('load', function () {
  804. var selector = 'a[href^="/david/cache/"], a[rel=prev], a[rel=next]'
  805. function sendLinks (selector) {
  806. var links = [].slice.call(document.querySelectorAll(selector)).map(function (link) {
  807. return link.getAttribute('href')
  808. })
  809. links.push(location.pathname) // Put the current page in cache too.
  810. navigator.serviceWorker.controller.postMessage({ links: links })
  811. }
  812. navigator.serviceWorker.getRegistration()
  813. .then(function (registration) {
  814. if (!registration || !navigator.serviceWorker.controller) {
  815. return navigator.serviceWorker.register('/serviceworker.js')
  816. .then(navigator.serviceWorker.ready)
  817. .then(function () {
  818. console.log('[ServiceWorker] Ready to go!')
  819. })
  820. .catch(console.error.bind(console))
  821. } else {
  822. console.log('[ServiceWorker] Send links via registration')
  823. sendLinks(selector)
  824. }
  825. })
  826. navigator.serviceWorker.addEventListener('controllerchange', function () {
  827. console.log('[ServiceWorker] Send links via controller change')
  828. sendLinks(selector)
  829. })
  830. navigator.serviceWorker.addEventListener('message', function (event) {
  831. var link = document.querySelector('a[href="' + event.data.link + '"]')
  832. if (event.data.status && link) {
  833. link.style.backgroundColor = '#2d7474'
  834. link.style.color = '#f0f0ea'
  835. link.setAttribute('title', 'En cache pour consultation sans connexion')
  836. }
  837. })
  838. })
  839. } else {
  840. console.warn('[ServiceWorker] No cache for old browsers.')
  841. }
  842. </script>