@brightspace-ui/core 2.29.4 → 2.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -27,33 +27,33 @@
27
27
  `];
28
28
  }
29
29
  render() {
30
- const classes = { 'd2l-code': true, 'd2l-code-dark': this.dark };
30
+ const classes = { 'd2l-code': true, 'd2l-code-dark': this.dark, 'line-numbers': true };
31
31
  return html`
32
- <pre class="${classMap(classes)}"><code class="language-javascript line-numbers">function helloGrumpy(name) {
32
+ <pre class="${classMap(classes)}"><code class="language-javascript">function helloGrumpy(name) {
33
33
  console.log(\`Hi there \${name}. Here's some really long text to test overflowing the bounding container.\`);
34
34
  }
35
35
  helloGrumpy('Wizard');
36
36
  </code></pre>
37
37
 
38
- <pre class="${classMap(classes)}"><code class="language-bash line-numbers">#!/bin/bash
38
+ <pre class="${classMap(classes)}"><code class="language-bash">#!/bin/bash
39
39
  if [ -d $directory ]; then
40
40
  echo "Directory exists"
41
41
  else
42
42
  echo "Directory does not exists"
43
43
  fi</code></pre>
44
44
 
45
- <pre class="${classMap(classes)}"><code class="language-css line-numbers">.grumpy > img {
45
+ <pre class="${classMap(classes)}"><code class="language-css">.grumpy > img {
46
46
  height: 100%;
47
47
  width: 100%;
48
48
  }</code></pre>
49
49
 
50
- <pre class="${classMap(classes)}"><code class="language-json line-numbers">{
50
+ <pre class="${classMap(classes)}"><code class="language-json">{
51
51
  "jinxed": "gnomes",
52
52
  "grumpy": [ "wizards" ]
53
53
  }
54
54
  </code></pre>
55
55
 
56
- <pre class="${classMap(classes)}"><code class="language-sql line-numbers">DECLARE @MyCounter INT; /* keyword, variable, punctuation */
56
+ <pre class="${classMap(classes)}"><code class="language-sql">DECLARE @MyCounter INT; /* keyword, variable, punctuation */
57
57
 
58
58
  SELECT AVG(Calories) AS AverageCalories FROM Desserts; /* keyword, function */
59
59
 
@@ -76,6 +76,7 @@ SET @Donuts = 'Yummy'; /* keyword, variable, string */
76
76
  </script>
77
77
  <style>
78
78
  html {
79
+ background-color: white;
79
80
  font-size: 20px;
80
81
  }
81
82
  body {
@@ -101,6 +102,10 @@ SET @Donuts = 'Yummy'; /* keyword, variable, string */
101
102
  tr > td:first-child {
102
103
  width: 300px;
103
104
  }
105
+ pre {
106
+ max-height: 600px;
107
+ overflow: auto;
108
+ }
104
109
  </style>
105
110
  </head>
106
111
  <body class="d2l-typography">
@@ -309,86 +314,2162 @@ helloGrumpy('Wizard');</code></pre>
309
314
  <pre class="d2l-code d2l-code-dark"><code class="language-json">{ "fritter": null }</code></pre>
310
315
  </td>
311
316
  </tr>
317
+ <tr>
318
+ <td>color</td>
319
+ <td>
320
+ <pre class="d2l-code d2l-code-dark"><code class="language-css">background-color: rgba(0, 0, 0, 0.4);
321
+ border: 1px solid #cd2026;
322
+ </code></pre>
323
+ </td>
324
+ </tr>
312
325
  </tbody>
313
326
  </table>
314
327
 
315
- <h2 class="d2l-heading-3">More Samples (Global Scope)</h2>
328
+ <h2 class="d2l-heading-3">Large Samples</h2>
329
+
330
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-markup">&lt;!DOCTYPE html&gt;
331
+ &lt;html lang="en"&gt;
332
+ &lt;head&gt;
333
+ &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
334
+ &lt;meta charset="UTF-8"&gt;
335
+ &lt;link rel="stylesheet" href="../../demo/styles.css" type="text/css"&gt;
336
+ &lt;script type="module"&gt;
337
+ import '../../demo/demo-page.js';
338
+ import '../../button/button.js';
339
+ import '../../button/button-icon.js';
340
+ import '../../dropdown/dropdown-more.js';
341
+ import '../../dropdown/dropdown-content.js';
342
+ import '../../status-indicator/status-indicator.js';
343
+ import '../../tooltip/tooltip.js';
344
+ import '../card.js';
345
+ import '../card-loading-shimmer.js';
346
+ import '../card-content-meta.js';
347
+ import '../card-content-title.js';
348
+ import '../card-footer-link.js';
349
+ &lt;/script&gt;
350
+ &lt;style&gt;
351
+ d2l-card {
352
+ vertical-align: top;
353
+ }
354
+ .subtle-demo {
355
+ background-color: #f6f7f8;
356
+ padding: 20px;
357
+ }
358
+ .badge {
359
+ text-align: center;
360
+ }
361
+ .badge &gt; img {
362
+ background-color: white;
363
+ border: 1px solid #202122; /* ferrite */
364
+ border-radius: 6px;
365
+ height: 70px;
366
+ object-fit: cover;
367
+ object-position: center;
368
+ }
369
+ .badge-status {
370
+ background-color: white;
371
+ border: 1px solid white;
372
+ border-radius: 0.6rem;
373
+ display: inline-block;
374
+ }
375
+ div[slot="footer"] {
376
+ display: inline-block;
377
+ }
378
+ #toggleLoading {
379
+ margin-top: 20px;
380
+ }
381
+ &lt;/style&gt;
382
+ &lt;/head&gt;
383
+ &lt;body unresolved&gt;
384
+
385
+ &lt;d2l-demo-page page-title="d2l-card"&gt;
386
+
387
+ &lt;h2&gt;Subtle Card (badges, no-link)&lt;/h2&gt;
388
+
389
+ &lt;d2l-demo-snippet&gt;
390
+ &lt;template&gt;
391
+ &lt;div class="subtle-demo"&gt;
392
+
393
+ &lt;d2l-card subtle align-center text="Image Badge" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 280px; width: 245px;"&gt;
394
+ &lt;img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg"&gt;
395
+ &lt;div slot="badge" class="badge"&gt;
396
+ &lt;img alt="" src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/94/Stick_Figure.svg/340px-Stick_Figure.svg.png"&gt;
397
+ &lt;/div&gt;
398
+ &lt;div slot="content"&gt;Image Badge&lt;/div&gt;
399
+ &lt;/d2l-card&gt;
400
+
401
+ &lt;d2l-card subtle align-center text="Status Badge" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 280px; width: 245px;"&gt;
402
+ &lt;img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg"&gt;
403
+ &lt;div class="badge-status" slot="badge"&gt;
404
+ &lt;d2l-status-indicator text="Success" state="success"&gt;&lt;/d2l-status-indicator&gt;
405
+ &lt;/div&gt;
406
+ &lt;div slot="content"&gt;Status Badge&lt;/div&gt;
407
+ &lt;/d2l-card&gt;
408
+
409
+ &lt;d2l-card subtle align-center text="No Link" style="height: 280px; width: 245px;"&gt;
410
+ &lt;img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg"&gt;
411
+ &lt;div slot="content"&gt;No Link&lt;/div&gt;
412
+ &lt;/d2l-card&gt;
413
+
414
+ &lt;/div&gt;
415
+ &lt;/template&gt;
416
+ &lt;/d2l-demo-snippet&gt;
417
+
418
+ &lt;h2&gt;Subtle Card (header actions, meta-content, footer links)&lt;/h2&gt;
419
+
420
+ &lt;d2l-demo-snippet&gt;
421
+ &lt;template&gt;
422
+ &lt;div class="subtle-demo"&gt;
423
+
424
+ &lt;d2l-card subtle align-center text="Hydrology" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 300px; width: 245px;"&gt;
425
+ &lt;img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg"&gt;
426
+ &lt;d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!"&gt;
427
+ &lt;d2l-dropdown-content&gt;
428
+ &lt;div&gt;This is where you could put the super cool features for your card!&lt;/div&gt;&lt;br&gt;&lt;div&gt;As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.&lt;/div&gt;
429
+ &lt;div&gt;This is where you could put the super cool features for your card!&lt;/div&gt;&lt;br&gt;&lt;div&gt;As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.&lt;/div&gt;
430
+ &lt;div&gt;This is where you could put the super cool features for your card!&lt;/div&gt;&lt;br&gt;&lt;div&gt;As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.&lt;/div&gt;
431
+ &lt;/d2l-dropdown-content&gt;
432
+ &lt;/d2l-dropdown-more&gt;
433
+ &lt;d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"&gt;&lt;/d2l-button-icon&gt;
434
+ &lt;div slot="content"&gt;&lt;div&gt;Hydrology&lt;/div&gt;&lt;d2l-card-content-meta&gt;This is some extra meta data that will fill the content slot of the card.&lt;/d2l-card-content-meta&gt;&lt;/div&gt;
435
+ &lt;div slot="footer"&gt;
436
+ &lt;d2l-card-footer-link id="googleDriveLink1" icon="tier1:google-drive" text="Google Drive" secondary-count="100" href="https://www.google.ca/drive/"&gt;
437
+ &lt;d2l-tooltip slot="tooltip" for="googleDriveLink1"&gt;Go to Google Drive&lt;/d2l-tooltip&gt;
438
+ &lt;/d2l-card-footer-link&gt;
439
+ &lt;d2l-card-footer-link id="rssFeedLink1" icon="tier1:rss" text="RSS Feed" secondary-count="1"&gt;
440
+ &lt;d2l-tooltip slot="tooltip" for="rssFeedLink1"&gt;RSS Feed&lt;/d2l-tooltip&gt;
441
+ &lt;/d2l-card-footer-link&gt;
442
+ &lt;d2l-card-footer-link id="outcomesLink1" icon="tier1:outcomes" text="Outcomes" secondary-count="5"&gt;
443
+ &lt;d2l-tooltip slot="tooltip" for="outcomesLink1"&gt;Outcomes&lt;/d2l-tooltip&gt;
444
+ &lt;/d2l-card-footer-link&gt;
445
+ &lt;d2l-card-footer-link id="assignmentsLink1" icon="tier1:assignments" text="Assignments" secondary-count="3"&gt;
446
+ &lt;d2l-tooltip slot="tooltip" position="top" style="width: 100%;" for="assignmentsLink1"&gt;You have 3 assignments due tomorrow.&lt;/d2l-tooltip&gt;
447
+ &lt;/d2l-card-footer-link&gt;
448
+ &lt;/div&gt;
449
+ &lt;/d2l-card&gt;
450
+
451
+ &lt;d2l-card subtle align-center text="Grade 2" href="https://en.wikipedia.org/wiki/Second_grade" style="height: 300px; width: 245px;"&gt;
452
+ &lt;img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/e5fd575a-bc14-4a80-89e1-46f349a76178/tile-low-density-max-size.jpg"&gt;
453
+ &lt;d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!"&gt;
454
+ &lt;d2l-dropdown-content&gt;&lt;div&gt;This is where you could put the super cool features for your card!&lt;/div&gt;&lt;br&gt;&lt;div&gt;As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.&lt;/div&gt;&lt;/d2l-dropdown-content&gt;
455
+ &lt;/d2l-dropdown-more&gt;
456
+ &lt;d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"&gt;&lt;/d2l-button-icon&gt;
457
+ &lt;div slot="content"&gt;Grade 2&lt;/div&gt;
458
+ &lt;div slot="footer"&gt;
459
+ &lt;d2l-card-footer-link id="googleDriveLink2" icon="tier1:google-drive" text="Google Drive" secondary-count="100" href="https://www.google.ca/drive/"&gt;
460
+ &lt;d2l-tooltip slot="tooltip" for="googleDriveLink2"&gt;Go to Google Drive&lt;/d2l-tooltip&gt;
461
+ &lt;/d2l-card-footer-link&gt;
462
+ &lt;d2l-card-footer-link id="rssFeedLink2" icon="tier1:rss" text="RSS Feed" secondary-count="1"&gt;
463
+ &lt;d2l-tooltip slot="tooltip" for="rssFeedLink2"&gt;RSS Feed&lt;/d2l-tooltip&gt;
464
+ &lt;/d2l-card-footer-link&gt;
465
+ &lt;d2l-card-footer-link id="outcomesLink2" icon="tier1:outcomes" text="Outcomes" secondary-count="5"&gt;
466
+ &lt;d2l-tooltip slot="tooltip" for="outcomesLink2"&gt;Outcomes&lt;/d2l-tooltip&gt;
467
+ &lt;/d2l-card-footer-link&gt;
468
+ &lt;/div&gt;
469
+ &lt;/d2l-card&gt;
470
+
471
+ &lt;d2l-card subtle align-center text="Painting" href="https://en.wikipedia.org/wiki/Painting" style="height: 300px; width: 245px;"&gt;
472
+ &lt;img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/63b162ab-b582-4bf9-8c1d-1dad04714121/tile-low-density-max-size.jpg"&gt;
473
+ &lt;d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!"&gt;
474
+ &lt;d2l-dropdown-content&gt;&lt;div&gt;This is where you could put the super cool features for your card!&lt;/div&gt;&lt;br&gt;&lt;div&gt;As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.&lt;/div&gt;&lt;/d2l-dropdown-content&gt;
475
+ &lt;/d2l-dropdown-more&gt;
476
+ &lt;d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"&gt;&lt;/d2l-button-icon&gt;
477
+ &lt;div slot="content"&gt;Painting&lt;/div&gt;
478
+ &lt;d2l-button slot="footer" style="width: 100%;"&gt;Shiny Button&lt;/d2l-button&gt;
479
+ &lt;/d2l-card&gt;
480
+
481
+ &lt;/div&gt;
482
+ &lt;/template&gt;
483
+ &lt;/d2l-demo-snippet&gt;
484
+
485
+ &lt;h2&gt;Card (badges, no-link)&lt;/h2&gt;
486
+
487
+ &lt;d2l-demo-snippet&gt;
488
+ &lt;template&gt;
489
+
490
+ &lt;d2l-card align-center text="Image Badge" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 280px; width: 245px;"&gt;
491
+ &lt;img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg"&gt;
492
+ &lt;div slot="badge" class="badge"&gt;
493
+ &lt;img alt="" src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/94/Stick_Figure.svg/340px-Stick_Figure.svg.png"&gt;
494
+ &lt;/div&gt;
495
+ &lt;div slot="content"&gt;Image Badge&lt;/div&gt;
496
+ &lt;/d2l-card&gt;
497
+
498
+ &lt;d2l-card align-center text="Status Badge" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 280px; width: 245px;"&gt;
499
+ &lt;img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg"&gt;
500
+ &lt;div class="badge-status" slot="badge"&gt;
501
+ &lt;d2l-status-indicator text="Success" state="success"&gt;&lt;/d2l-status-indicator&gt;
502
+ &lt;/div&gt;
503
+ &lt;div slot="content"&gt;Status Badge&lt;/div&gt;
504
+ &lt;/d2l-card&gt;
505
+
506
+ &lt;d2l-card align-center text="No Link" style="height: 280px; width: 245px;"&gt;
507
+ &lt;img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg"&gt;
508
+ &lt;div slot="content"&gt;No Link&lt;/div&gt;
509
+ &lt;/d2l-card&gt;
510
+
511
+ &lt;/template&gt;
512
+ &lt;/d2l-demo-snippet&gt;
513
+
514
+ &lt;h2&gt;Card (header actions, meta-content, footer links)&lt;/h2&gt;
515
+
516
+ &lt;d2l-demo-snippet&gt;
517
+ &lt;template&gt;
518
+
519
+ &lt;d2l-card align-center text="Hydrology" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 300px; width: 245px;"&gt;
520
+ &lt;img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg"&gt;
521
+ &lt;d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!"&gt;
522
+ &lt;d2l-dropdown-content&gt;
523
+ &lt;div&gt;This is where you could put the super cool features for your card!&lt;/div&gt;&lt;br&gt;&lt;div&gt;As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.&lt;/div&gt;
524
+ &lt;div&gt;This is where you could put the super cool features for your card!&lt;/div&gt;&lt;br&gt;&lt;div&gt;As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.&lt;/div&gt;
525
+ &lt;div&gt;This is where you could put the super cool features for your card!&lt;/div&gt;&lt;br&gt;&lt;div&gt;As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.&lt;/div&gt;
526
+ &lt;/d2l-dropdown-content&gt;
527
+ &lt;/d2l-dropdown-more&gt;
528
+ &lt;d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"&gt;&lt;/d2l-button-icon&gt;
529
+ &lt;div slot="content"&gt;&lt;div&gt;Hydrology&lt;/div&gt;&lt;d2l-card-content-meta&gt;This is some extra meta data that will fill the content slot of the card.&lt;/d2l-card-content-meta&gt;&lt;/div&gt;
530
+ &lt;div slot="footer"&gt;
531
+ &lt;d2l-card-footer-link id="googleDriveLink3" icon="tier1:google-drive" text="Google Drive" secondary-count="100" href="https://www.google.ca/drive/"&gt;
532
+ &lt;d2l-tooltip slot="tooltip" for="googleDriveLink3"&gt;Go to Google Drive&lt;/d2l-tooltip&gt;
533
+ &lt;/d2l-card-footer-link&gt;
534
+ &lt;d2l-card-footer-link id="rssFeedLink3" icon="tier1:rss" text="RSS Feed" secondary-count="1"&gt;
535
+ &lt;d2l-tooltip slot="tooltip" for="rssFeedLink3"&gt;RSS Feed&lt;/d2l-tooltip&gt;
536
+ &lt;/d2l-card-footer-link&gt;
537
+ &lt;d2l-card-footer-link id="outcomesLink3" icon="tier1:outcomes" text="Outcomes" secondary-count="5"&gt;
538
+ &lt;d2l-tooltip slot="tooltip" for="outcomesLink3"&gt;Outcomes&lt;/d2l-tooltip&gt;
539
+ &lt;/d2l-card-footer-link&gt;
540
+ &lt;d2l-card-footer-link id="assignmentsLink3" icon="tier1:assignments" text="Assignments" secondary-count="3"&gt;
541
+ &lt;d2l-tooltip slot="tooltip" position="top" style="width: 100%;" for="assignmentsLink3"&gt;You have 3 assignments due tomorrow.&lt;/d2l-tooltip&gt;
542
+ &lt;/d2l-card-footer-link&gt;
543
+ &lt;/div&gt;
544
+ &lt;/d2l-card&gt;
545
+
546
+ &lt;d2l-card align-center text="Painting" href="https://en.wikipedia.org/wiki/Painting" style="height: 300px; width: 245px;"&gt;
547
+ &lt;img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/63b162ab-b582-4bf9-8c1d-1dad04714121/tile-low-density-max-size.jpg"&gt;
548
+ &lt;d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!"&gt;
549
+ &lt;d2l-dropdown-content&gt;&lt;div&gt;This is where you could put the super cool features for your card!&lt;/div&gt;&lt;br&gt;&lt;div&gt;As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.&lt;/div&gt;&lt;/d2l-dropdown-content&gt;
550
+ &lt;/d2l-dropdown-more&gt;
551
+ &lt;d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"&gt;&lt;/d2l-button-icon&gt;
552
+ &lt;div slot="content"&gt;Painting&lt;/div&gt;
553
+ &lt;d2l-button slot="footer" style="width: 100%;"&gt;Shiny Button&lt;/d2l-button&gt;
554
+ &lt;/d2l-card&gt;
555
+
556
+ &lt;d2l-card align-center text="Grade 2" href="https://en.wikipedia.org/wiki/Second_grade" style="height: 300px; width: 245px;"&gt;
557
+ &lt;img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/e5fd575a-bc14-4a80-89e1-46f349a76178/tile-low-density-max-size.jpg"&gt;
558
+ &lt;d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!"&gt;
559
+ &lt;d2l-dropdown-content&gt;&lt;div&gt;This is where you could put the super cool features for your card!&lt;/div&gt;&lt;br&gt;&lt;div&gt;As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.&lt;/div&gt;&lt;/d2l-dropdown-content&gt;
560
+ &lt;/d2l-dropdown-more&gt;
561
+ &lt;d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"&gt;&lt;/d2l-button-icon&gt;
562
+ &lt;div slot="content"&gt;Grade 2&lt;/div&gt;
563
+ &lt;div slot="footer"&gt;
564
+ &lt;d2l-card-footer-link id="googleDriveLink4" icon="tier1:google-drive" text="Google Drive" secondary-count-type="count" secondary-count="100" href="https://www.google.ca/drive/"&gt;
565
+ &lt;d2l-tooltip slot="tooltip" for="googleDriveLink4"&gt;Go to Google Drive&lt;/d2l-tooltip&gt;
566
+ &lt;/d2l-card-footer-link&gt;
567
+ &lt;d2l-card-footer-link id="rssFeedLink4" icon="tier1:rss" text="RSS Feed" secondary-count-type="count" secondary-count="1"&gt;
568
+ &lt;d2l-tooltip slot="tooltip" for="rssFeedLink4"&gt;RSS Feed&lt;/d2l-tooltip&gt;
569
+ &lt;/d2l-card-footer-link&gt;
570
+ &lt;d2l-card-footer-link id="outcomesLink4" icon="tier1:outcomes" text="Outcomes" secondary-count-type="count" secondary-count="5"&gt;
571
+ &lt;d2l-tooltip slot="tooltip" for="outcomesLink4"&gt;Outcomes&lt;/d2l-tooltip&gt;
572
+ &lt;/d2l-card-footer-link&gt;
573
+ &lt;/div&gt;
574
+ &lt;/d2l-card&gt;
575
+
576
+ &lt;/template&gt;
577
+ &lt;/d2l-demo-snippet&gt;
578
+
579
+ &lt;h2&gt;Card (with header loading)&lt;/h2&gt;
580
+
581
+ &lt;d2l-demo-snippet&gt;
582
+ &lt;template&gt;
583
+
584
+ &lt;d2l-card align-center text="Hydrology" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 300px; width: 245px;"&gt;
585
+ &lt;d2l-card-loading-shimmer slot="header" loading style="display: block; height: 103.5px; width: 100%;"&gt;
586
+ &lt;img alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg"&gt;
587
+ &lt;/d2l-card-loading-shimmer&gt;
588
+ &lt;div slot="content"&gt;&lt;div&gt;Hydrology&lt;/div&gt;&lt;d2l-card-content-meta&gt;This is some extra meta data that will fill the content slot of the card.&lt;/d2l-card-content-meta&gt;&lt;/div&gt;
589
+ &lt;/d2l-card&gt;
590
+
591
+ &lt;div&gt;
592
+ &lt;d2l-button id="toggleLoading"&gt;Toggle Loading State&lt;/d2l-button&gt;
593
+ &lt;/div&gt;
594
+
595
+ &lt;script&gt;
596
+ document.querySelector('#toggleLoading').addEventListener('click', () =&gt; {
597
+ const loadingContainer = document.querySelector('d2l-card-loading-shimmer');
598
+ loadingContainer.loading = !loadingContainer.loading;
599
+ });
600
+ &lt;/script&gt;
601
+ &lt;/template&gt;
602
+ &lt;/d2l-demo-snippet&gt;
603
+
604
+ &lt;/d2l-demo-page&gt;
605
+ &lt;/body&gt;
606
+ &lt;/html&gt;
607
+ </code></pre>
608
+
609
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-javascript">import '../backdrop/backdrop.js';
610
+ import '../button/button.js';
611
+ import '../focus-trap/focus-trap.js';
612
+ import { clearDismissible, setDismissible } from '../../helpers/dismissible.js';
613
+ import { findComposedAncestor, getBoundingAncestor, isComposedAncestor, isVisible } from '../../helpers/dom.js';
614
+ import { getComposedActiveElement, getFirstFocusableDescendant, getPreviousFocusableAncestor } from '../../helpers/focus.js';
615
+ import { classMap } from 'lit/directives/class-map.js';
616
+ import { html } from 'lit';
617
+ import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
618
+ import { RtlMixin } from '../../mixins/rtl-mixin.js';
619
+ import { styleMap } from 'lit/directives/style-map.js';
620
+ import { tryGetIfrauBackdropService } from '../../helpers/ifrauBackdropService.js';
621
+
622
+ const reduceMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;
623
+ const minBackdropHeightMobile = 42;
624
+ const minBackdropWidthMobile = 30;
625
+ const outerMarginTopBottom = 18;
626
+ const defaultVerticalOffset = 16;
627
+
628
+ export const DropdownContentMixin = superclass =&gt; class extends LocalizeCoreElement(RtlMixin(superclass)) {
629
+
630
+ static get properties() {
631
+ return {
632
+ /**
633
+ * Optionally align dropdown to either start or end. If not set, the dropdown will attempt be centred.
634
+ * @type {'start'|'end'}
635
+ */
636
+ align: {
637
+ type: String,
638
+ reflect: true
639
+ },
640
+ /**
641
+ * Optionally provide boundaries to where the dropdown will appear. Valid properties are "above", "below", "left", and "right".
642
+ * @type {object}
643
+ */
644
+ boundary: {
645
+ type: Object,
646
+ },
647
+ /**
648
+ * Override default max-width (undefined). Specify a number that would be the px value.
649
+ * @type {number}
650
+ */
651
+ maxWidth: {
652
+ type: Number,
653
+ reflect: true,
654
+ attribute: 'max-width'
655
+ },
656
+ /**
657
+ * Override default min-width (undefined). Specify a number that would be the px value.
658
+ * @type {number}
659
+ */
660
+ minWidth: {
661
+ type: Number,
662
+ reflect: true,
663
+ attribute: 'min-width'
664
+ },
665
+ /**
666
+ * Override max-height. Note that the default behaviour is to be as tall as necessary within the viewport, so this property is usually not needed.
667
+ * @type {number}
668
+ */
669
+ maxHeight: {
670
+ type: Number,
671
+ attribute: 'max-height'
672
+ },
673
+ /**
674
+ * Override the breakpoint at which mobile styling is used. Defaults to 616px.
675
+ * @type {number}
676
+ */
677
+ mobileBreakpointOverride: {
678
+ type: Number,
679
+ attribute: 'mobile-breakpoint'
680
+ },
681
+ /**
682
+ * Override default height used for required space when `no-auto-fit` is true. Specify a number that would be the px value. Note that the default behaviour is to be as tall as necessary within the viewport, so this property is usually not needed.
683
+ * @type {number}
684
+ */
685
+ minHeight: {
686
+ type: Number,
687
+ reflect: true,
688
+ attribute: 'min-height'
689
+ },
690
+ /**
691
+ * Opt-out of showing a close button in the footer of tray-style mobile dropdowns.
692
+ * @type {boolean}
693
+ */
694
+ noMobileCloseButton: {
695
+ type: Boolean,
696
+ reflect: true,
697
+ attribute: 'no-mobile-close-button'
698
+ },
699
+ /**
700
+ * Mobile dropdown style.
701
+ * @type {'left'|'right'|'bottom'}
702
+ */
703
+ mobileTray: {
704
+ type: String,
705
+ reflect: true,
706
+ attribute: 'mobile-tray'
707
+ },
708
+ /**
709
+ * Opt out of automatically closing on focus or click outside of the dropdown content
710
+ * @type {boolean}
711
+ */
712
+ noAutoClose: {
713
+ type: Boolean,
714
+ reflect: true,
715
+ attribute: 'no-auto-close'
716
+ },
717
+ /**
718
+ * Opt out of auto-sizing
719
+ * @type {boolean}
720
+ */
721
+ noAutoFit: {
722
+ type: Boolean,
723
+ reflect: true,
724
+ attribute: 'no-auto-fit'
725
+ },
726
+ /**
727
+ * Opt out of focus being automatically moved to the first focusable element in the dropdown when opened
728
+ * @type {boolean}
729
+ */
730
+ noAutoFocus: {
731
+ type: Boolean,
732
+ reflect: true,
733
+ attribute: 'no-auto-focus'
734
+ },
735
+ /**
736
+ * Render with no padding
737
+ * @type {boolean}
738
+ */
739
+ noPadding: {
740
+ type: Boolean,
741
+ reflect: true,
742
+ attribute: 'no-padding'
743
+ },
744
+ /**
745
+ * Render the footer with no padding (if it has content)
746
+ * @type {boolean}
747
+ */
748
+ noPaddingFooter: {
749
+ type: Boolean,
750
+ reflect: true,
751
+ attribute: 'no-padding-footer'
752
+ },
753
+ /**
754
+ * Render the header with no padding (if it has content)
755
+ * @type {boolean}
756
+ */
757
+ noPaddingHeader: {
758
+ type: Boolean,
759
+ reflect: true,
760
+ attribute: 'no-padding-header'
761
+ },
762
+ /**
763
+ * Render without a pointer
764
+ * @type {boolean}
765
+ */
766
+ noPointer: {
767
+ type: Boolean,
768
+ reflect: true,
769
+ attribute: 'no-pointer'
770
+ },
771
+ /**
772
+ * Whether the dropdown is open or not
773
+ * @type {boolean}
774
+ */
775
+ opened: {
776
+ type: Boolean,
777
+ reflect: true
778
+ },
779
+ /**
780
+ * Private.
781
+ * @ignore
782
+ */
783
+ openedAbove: {
784
+ type: Boolean,
785
+ reflect: true,
786
+ attribute: 'opened-above'
787
+ },
788
+ /**
789
+ * Optionally render a d2l-focus-trap around the dropdown content
790
+ * @type {boolean}
791
+ */
792
+ trapFocus: {
793
+ type: Boolean,
794
+ reflect: true,
795
+ attribute: 'trap-focus'
796
+ },
797
+ /**
798
+ * Provide custom offset, positive or negative
799
+ * @type {string}
800
+ */
801
+ verticalOffset: {
802
+ type: String,
803
+ attribute: 'vertical-offset'
804
+ },
805
+ _bottomOverflow: {
806
+ type: Boolean
807
+ },
808
+ _closing: {
809
+ type: Boolean
810
+ },
811
+ _contentOverflow: {
812
+ type: Boolean
813
+ },
814
+ _dropdownContent: {
815
+ type: Boolean,
816
+ attribute: 'dropdown-content',
817
+ reflect: true
818
+ },
819
+ _useMobileStyling: {
820
+ type: Boolean,
821
+ attribute: 'data-mobile',
822
+ reflect: true
823
+ },
824
+ _hasHeader: {
825
+ type: Boolean
826
+ },
827
+ _hasFooter: {
828
+ type: Boolean
829
+ },
830
+ _contentHeight: {
831
+ type: Number
832
+ },
833
+ _position: {
834
+ type: Number
835
+ },
836
+ _showBackdrop: {
837
+ type: Boolean
838
+ },
839
+ _topOverflow: {
840
+ type: Boolean
841
+ },
842
+ _width: {
843
+ type: Number
844
+ }
845
+ };
846
+ }
847
+
848
+ constructor() {
849
+ super();
850
+
851
+ this.noAutoClose = false;
852
+ this.noAutoFit = false;
853
+ this.noAutoFocus = false;
854
+ this.noMobileCloseButton = false;
855
+ this.noPadding = false;
856
+ this.noPaddingFooter = false;
857
+ this.noPaddingHeader = false;
858
+ this.noPointer = false;
859
+ this.mobileBreakpointOverride = 616;
860
+ this.trapFocus = false;
861
+ this._useMobileStyling = false;
862
+
863
+ this.__opened = false;
864
+ this.__content = null;
865
+ this.__previousFocusableAncestor = null;
866
+ this.__applyFocus = true;
867
+ this.__dismissibleId = null;
868
+
869
+ this._dropdownContent = true;
870
+ this._bottomOverflow = false;
871
+ this._topOverflow = false;
872
+ this._closing = false;
873
+ this._contentOverflow = false;
874
+ this._hasHeader = false;
875
+ this._hasFooter = false;
876
+ this._showBackdrop = false;
877
+ this._verticalOffset = defaultVerticalOffset;
878
+
879
+ this.__onResize = this.__onResize.bind(this);
880
+ this.__onAutoCloseFocus = this.__onAutoCloseFocus.bind(this);
881
+ this.__onAutoCloseClick = this.__onAutoCloseClick.bind(this);
882
+ this.__toggleScrollStyles = this.__toggleScrollStyles.bind(this);
883
+ this._handleMobileResize = this._handleMobileResize.bind(this);
884
+ this.__disconnectResizeObserver = this.__disconnectResizeObserver.bind(this);
885
+ }
886
+
887
+ get opened() {
888
+ return this.__opened;
889
+ }
890
+
891
+ set opened(val) {
892
+ const oldVal = this.__opened;
893
+ if (oldVal !== val) {
894
+ this.__opened = val;
895
+ this.requestUpdate('opened', oldVal);
896
+ this.__openedChanged(val);
897
+ }
898
+ }
899
+
900
+ connectedCallback() {
901
+ super.connectedCallback();
902
+
903
+ window.addEventListener('resize', this.__onResize);
904
+ this.addEventListener('blur', this.__onAutoCloseFocus, true);
905
+ document.body.addEventListener('focus', this.__onAutoCloseFocus, true);
906
+ document.body.addEventListener('click', this.__onAutoCloseClick, true);
907
+ this.mediaQueryList = window.matchMedia(`(max-width: ${this.mobileBreakpointOverride - 1}px)`);
908
+ this._useMobileStyling = this.mediaQueryList.matches;
909
+ if (this.mediaQueryList.addEventListener) this.mediaQueryList.addEventListener('change', this._handleMobileResize);
910
+ }
911
+
912
+ disconnectedCallback() {
913
+ super.disconnectedCallback();
914
+ if (this.mediaQueryList.removeEventListener) this.mediaQueryList.removeEventListener('change', this._handleMobileResize);
915
+ this.removeEventListener('blur', this.__onAutoCloseFocus);
916
+ window.removeEventListener('resize', this.__onResize);
917
+ if (document.body) {
918
+ // DE41322: document.body can be null in some scenarios
919
+ document.body.removeEventListener('focus', this.__onAutoCloseFocus, true);
920
+ document.body.removeEventListener('click', this.__onAutoCloseClick, true);
921
+ }
922
+ clearDismissible(this.__dismissibleId);
923
+ this.__dismissibleId = null;
924
+
925
+ if (this.__resizeObserver) this.__resizeObserver.disconnect();
926
+ }
927
+
928
+ firstUpdated(changedProperties) {
929
+ super.firstUpdated(changedProperties);
930
+
931
+ this.__content = this.__getContentContainer();
932
+ this.addEventListener('d2l-dropdown-close', this.__onClose);
933
+ this.addEventListener('d2l-dropdown-position', this.__toggleScrollStyles);
934
+ }
935
+
936
+ updated(changedProperties) {
937
+ changedProperties.forEach((_, propName) =&gt; {
938
+ if (propName === 'verticalOffset') {
939
+ let newVerticalOffset = parseInt(this.verticalOffset);
940
+ if (isNaN(newVerticalOffset)) {
941
+ newVerticalOffset = defaultVerticalOffset;
942
+ }
943
+ this.style.setProperty('--d2l-dropdown-verticaloffset', `${newVerticalOffset}px`);
944
+ this._verticalOffset = newVerticalOffset;
945
+ }
946
+ });
947
+ }
948
+
949
+ close() {
950
+ const hide = () =&gt; {
951
+ this._closing = false;
952
+ this._showBackdrop = false;
953
+ this.opened = false;
954
+ };
955
+
956
+ if (!reduceMotion && this._useMobileStyling && this.mobileTray && isVisible(this)) {
957
+ if (this.shadowRoot) this.shadowRoot.querySelector('.d2l-dropdown-content-width')
958
+ .addEventListener('animationend', hide, { once: true });
959
+ this._closing = true;
960
+ this._showBackdrop = false;
961
+ } else {
962
+ hide();
963
+ }
964
+ }
965
+
966
+ /**
967
+ * forceRender is no longer necessary, this is left as a stub so that
968
+ * places calling it will not break. It will be removed once the Polymer
969
+ * dropdown is swapped over to use this and all instances of
970
+ * forceRender are removed.
971
+ */
972
+ forceRender() {}
973
+
974
+ /**
975
+ * Private.
976
+ */
977
+ height() {
978
+ return this.__content && this.__content.offsetHeight;
979
+ }
980
+
981
+ async open(applyFocus) {
982
+ this.__applyFocus = applyFocus !== undefined ? applyFocus : true;
983
+ this.opened = true;
984
+ await this.updateComplete;
985
+ this._showBackdrop = this._useMobileStyling && this.mobileTray;
986
+ }
987
+
988
+ /**
989
+ * Waits for the next resize when elem has a height &gt; 0px,
990
+ * then calls the __position function.
991
+ */
992
+ requestRepositionNextResize(elem) {
993
+ if (!elem) return;
994
+ if (this.__resizeObserver) this.__resizeObserver.disconnect();
995
+ this.__resizeObserver = new ResizeObserver(this.__disconnectResizeObserver);
996
+ this.__resizeObserver.observe(elem);
997
+ }
998
+
999
+ async resize() {
1000
+ if (!this.opened) {
1001
+ return;
1002
+ }
1003
+ this._showBackdrop = this._useMobileStyling && this.mobileTray;
1004
+ await this.__position();
1005
+ }
1006
+
1007
+ /**
1008
+ * Private.
1009
+ */
1010
+ scrollTo(scrollTop) {
1011
+ const content = this.__content;
1012
+ if (content) {
1013
+ if (typeof scrollTop === 'number') {
1014
+ content.scrollTop = scrollTop;
1015
+ }
1016
+ return content.scrollTop;
1017
+ }
1018
+ }
1019
+
1020
+ toggleOpen(applyFocus) {
1021
+ if (this.opened) {
1022
+ this.close();
1023
+ } else {
1024
+ this.open(!this.noAutoFocus && applyFocus);
1025
+ }
1026
+ }
1027
+
1028
+ __disconnectResizeObserver(entries) {
1029
+ for (let i = 0; i &lt; entries.length; i++) {
1030
+ const entry = entries[i];
1031
+ if (this.__resizeObserver && entry.contentRect.height !== 0) {
1032
+ this.__resizeObserver.disconnect();
1033
+ // wrap in rAF for Firefox
1034
+ requestAnimationFrame(() =&gt; {
1035
+ if (this.opened) this.__position();
1036
+ });
1037
+ break;
1038
+ }
1039
+ }
1040
+ }
1041
+
1042
+ __getContentBottom() {
1043
+ return this.shadowRoot && this.shadowRoot.querySelector('.d2l-dropdown-content-bottom');
1044
+ }
1045
+
1046
+ __getContentContainer() {
1047
+ return this.shadowRoot && this.shadowRoot.querySelector('.d2l-dropdown-content-container');
1048
+ }
1049
+
1050
+ __getContentTop() {
1051
+ return this.shadowRoot && this.shadowRoot.querySelector('.d2l-dropdown-content-top');
1052
+ }
1053
+
1054
+ __getOpener() {
1055
+ const opener = findComposedAncestor(this, (elem) =&gt; {
1056
+ if (elem.dropdownOpener) {
1057
+ return true;
1058
+ }
1059
+ });
1060
+ return opener;
1061
+ }
1062
+
1063
+ __getPositionContainer() {
1064
+ return this.shadowRoot && this.shadowRoot.querySelector('.d2l-dropdown-content-position');
1065
+ }
1066
+
1067
+ __getWidthContainer() {
1068
+ return this.shadowRoot && this.shadowRoot.querySelector('.d2l-dropdown-content-width');
1069
+ }
1070
+
1071
+ __handleFooterSlotChange(e) {
1072
+ this._hasFooter = e.target.assignedNodes().length !== 0;
1073
+ }
1074
+
1075
+ __handleHeaderSlotChange(e) {
1076
+ this._hasHeader = e.target.assignedNodes().length !== 0;
1077
+ }
1078
+
1079
+ __onAutoCloseClick(e) {
1080
+ if (!this.opened || this.noAutoClose) {
1081
+ return;
1082
+ }
1083
+ const rootTarget = e.composedPath()[0];
1084
+ const clickInside = isComposedAncestor(this.__getContentContainer(), rootTarget) ||
1085
+ isComposedAncestor(this.__getContentTop(), rootTarget) ||
1086
+ isComposedAncestor(this.__getContentBottom(), rootTarget);
1087
+ if (clickInside) {
1088
+ return;
1089
+ }
1090
+ const opener = this.__getOpener();
1091
+ if (isComposedAncestor(opener.getOpenerElement(), rootTarget)) {
1092
+ return;
1093
+ }
1094
+
1095
+ this.close();
1096
+ }
1097
+
1098
+ __onAutoCloseFocus() {
1099
+
1100
+ /* timeout needed to work around lack of support for relatedTarget */
1101
+ setTimeout(() =&gt; {
1102
+ if (!this.opened
1103
+ || this.noAutoClose
1104
+ || !document.activeElement
1105
+ || document.activeElement === this.__previousFocusableAncestor
1106
+ || document.activeElement === document.body) {
1107
+ return;
1108
+ }
1109
+
1110
+ const activeElement = getComposedActiveElement();
1111
+
1112
+ if (isComposedAncestor(this, activeElement)
1113
+ || isComposedAncestor(this.__getOpener(), activeElement)) {
1114
+ return;
1115
+ }
1116
+ this.close();
1117
+ }, 0);
1118
+ }
1119
+
1120
+ __onClose(e) {
1121
+
1122
+ if (e.target !== this || !document.activeElement) {
1123
+ return;
1124
+ }
1125
+
1126
+ const activeElement = getComposedActiveElement();
1127
+
1128
+ if (!isComposedAncestor(this, activeElement)) {
1129
+ return;
1130
+ }
1131
+
1132
+ const opener = this.__getOpener();
1133
+ opener.getOpenerElement().focus();
1134
+
1135
+ }
1136
+
1137
+ __onResize() {
1138
+ this.resize();
1139
+ }
1140
+
1141
+ async __openedChanged(newValue) {
1142
+
1143
+ // DE44538: wait for dropdown content to fully render,
1144
+ // otherwise this.__getContentContainer() can return null.
1145
+ await this.updateComplete;
1146
+
1147
+ this.__previousFocusableAncestor =
1148
+ newValue === true
1149
+ ? getPreviousFocusableAncestor(this, false, false)
1150
+ : null;
1151
+
1152
+ const doOpen = async() =&gt; {
1153
+
1154
+ const content = this.__getContentContainer();
1155
+
1156
+ if (!this.noAutoFit) {
1157
+ content.scrollTop = 0;
1158
+ }
1159
+
1160
+ await this.__position();
1161
+ this._showBackdrop = this._useMobileStyling && this.mobileTray;
1162
+ if (!this.noAutoFocus && this.__applyFocus) {
1163
+ const focusable = getFirstFocusableDescendant(this);
1164
+ if (focusable) {
1165
+ // Removing the rAF call can allow infinite focus looping to happen in content using a focus trap
1166
+ requestAnimationFrame(() =&gt; focusable.focus());
1167
+ } else {
1168
+ content.setAttribute('tabindex', '-1');
1169
+ content.focus();
1170
+ }
1171
+ }
1172
+
1173
+ setTimeout(() =&gt;
1174
+ this.dispatchEvent(new CustomEvent('d2l-dropdown-open', { bubbles: true, composed: true })), 0
1175
+ );
1176
+
1177
+ this.__dismissibleId = setDismissible(() =&gt; {
1178
+ this.close();
1179
+ });
1180
+ };
1181
+
1182
+ const ifrauBackdropService = await tryGetIfrauBackdropService();
1183
+
1184
+ if (newValue) {
1185
+
1186
+ if (ifrauBackdropService && this.mobileTray && this._useMobileStyling) {
1187
+ this._ifrauContextInfo = await ifrauBackdropService.showBackdrop();
1188
+ }
1189
+
1190
+ await doOpen();
1191
+
1192
+ } else {
1193
+
1194
+ if (this.__dismissibleId) {
1195
+ clearDismissible(this.__dismissibleId);
1196
+ this.__dismissibleId = null;
1197
+ }
1198
+ if (ifrauBackdropService && this.mobileTray && this._useMobileStyling) {
1199
+ ifrauBackdropService.hideBackdrop();
1200
+ this._ifrauContextInfo = null;
1201
+ }
1202
+ this._showBackdrop = false;
1203
+ await this.updateComplete;
1204
+
1205
+ /** Dispatched when the dropdown is closed */
1206
+ this.dispatchEvent(new CustomEvent('d2l-dropdown-close', { bubbles: true, composed: true }));
1207
+
1208
+ }
1209
+ }
1210
+
1211
+ async __position(ignoreVertical, contentRect) {
1212
+
1213
+ const opener = this.__getOpener();
1214
+ if (!opener) {
1215
+ return;
1216
+ }
1217
+ const target = opener.getOpenerElement();
1218
+ if (!target) {
1219
+ return;
1220
+ }
1221
+
1222
+ const content = this.__getContentContainer();
1223
+ const header = this.__getContentTop();
1224
+ const footer = this.__getContentBottom();
1225
+
1226
+ if (!this.noAutoFit) {
1227
+ this._contentHeight = null;
1228
+ }
1229
+
1230
+ /* don't let dropdown content horizontally overflow viewport */
1231
+ this._width = null;
1232
+
1233
+ const openerPosition = window.getComputedStyle(opener, null).getPropertyValue('position');
1234
+ const boundingContainer = getBoundingAncestor(target.parentNode);
1235
+ const boundingContainerRect = boundingContainer.getBoundingClientRect();
1236
+ const scrollHeight = boundingContainer.scrollHeight;
1237
+
1238
+ await this.updateComplete;
1239
+
1240
+ // position check in case consuming app (LMS) has overriden position to make content absolute wrt document
1241
+ const bounded = (openerPosition === 'relative' && boundingContainer !== document.documentElement);
1242
+
1243
+ const adjustPosition = async() =&gt; {
1244
+
1245
+ const targetRect = target.getBoundingClientRect();
1246
+ contentRect = contentRect ? contentRect : content.getBoundingClientRect();
1247
+ const headerFooterHeight = header.getBoundingClientRect().height + footer.getBoundingClientRect().height;
1248
+
1249
+ const height = this.minHeight ? this.minHeight : Math.min(this.maxHeight ? this.maxHeight : Number.MAX_VALUE, contentRect.height + headerFooterHeight);
1250
+ const spaceRequired = {
1251
+ height: height + 10,
1252
+ width: contentRect.width
1253
+ };
1254
+ let spaceAround;
1255
+ let spaceAroundScroll;
1256
+ if (bounded) {
1257
+ spaceAround = this._constrainSpaceAround({
1258
+ // allow for target offset + outer margin
1259
+ above: targetRect.top - boundingContainerRect.top - this._verticalOffset - outerMarginTopBottom,
1260
+ // allow for target offset + outer margin
1261
+ below: boundingContainerRect.bottom - targetRect.bottom - this._verticalOffset - outerMarginTopBottom,
1262
+ // allow for outer margin
1263
+ left: targetRect.left - boundingContainerRect.left - 20,
1264
+ // allow for outer margin
1265
+ right: boundingContainerRect.right - targetRect.right - 20
1266
+ }, spaceRequired, targetRect);
1267
+ spaceAroundScroll = this._constrainSpaceAround({
1268
+ above: targetRect.top - boundingContainerRect.top + boundingContainer.scrollTop,
1269
+ below: scrollHeight - targetRect.bottom + boundingContainerRect.top - boundingContainer.scrollTop
1270
+ }, spaceRequired, targetRect);
1271
+ } else {
1272
+ spaceAround = this._constrainSpaceAround({
1273
+ // allow for target offset + outer margin
1274
+ above: targetRect.top - this._verticalOffset - outerMarginTopBottom,
1275
+ // allow for target offset + outer margin
1276
+ below: window.innerHeight - targetRect.bottom - this._verticalOffset - outerMarginTopBottom,
1277
+ // allow for outer margin
1278
+ left: targetRect.left - 20,
1279
+ // allow for outer margin
1280
+ right: document.documentElement.clientWidth - targetRect.right - 15
1281
+ }, spaceRequired, targetRect);
1282
+ spaceAroundScroll = this._constrainSpaceAround({
1283
+ above: targetRect.top + document.documentElement.scrollTop,
1284
+ below: scrollHeight - targetRect.bottom - document.documentElement.scrollTop
1285
+ }, spaceRequired, targetRect);
1286
+ }
1287
+
1288
+ if (!ignoreVertical) {
1289
+ this.openedAbove = this._getOpenedAbove(spaceAround, spaceAroundScroll, spaceRequired);
1290
+ }
1291
+
1292
+ const centerDelta = contentRect.width - targetRect.width;
1293
+ const position = this._getPosition(spaceAround, centerDelta);
1294
+ if (position !== null) {
1295
+ this._position = position;
1296
+ }
1297
+
1298
+ //Calculate height available to the dropdown contents for overflow because that is the only area capable of scrolling
1299
+ const availableHeight = this.openedAbove ? spaceAround.above : spaceAround.below;
1300
+ if (!this.noAutoFit && availableHeight && availableHeight &gt; 0) {
1301
+ //Only apply maximum if it's less than space available and the header/footer alone won't exceed it (content must be visible)
1302
+ this._contentHeight = this.maxHeight !== null
1303
+ && availableHeight &gt; this.maxHeight
1304
+ && headerFooterHeight &lt; this.maxHeight
1305
+ ? this.maxHeight - headerFooterHeight - 2
1306
+ : availableHeight - headerFooterHeight;
1307
+ this.__toggleOverflowY(contentRect.height + headerFooterHeight &gt; availableHeight);
1308
+
1309
+ // ensure the content height has updated when the __toggleScrollStyles event handler runs
1310
+ await this.updateComplete;
1311
+ }
1312
+
1313
+ /** Dispatched when the dropdown position finishes adjusting */
1314
+ this.dispatchEvent(new CustomEvent('d2l-dropdown-position', { bubbles: true, composed: true }));
1315
+ };
1316
+
1317
+ const scrollWidth = Math.max(header.scrollWidth, content.scrollWidth, footer.scrollWidth);
1318
+ const availableWidth = (bounded ? boundingContainerRect.width - 60 : window.innerWidth - 40);
1319
+ this._width = (availableWidth &gt; scrollWidth ? scrollWidth : availableWidth) ;
1320
+
1321
+ await this.updateComplete;
1322
+
1323
+ await adjustPosition();
1324
+ }
1325
+
1326
+ __toggleOverflowY(isOverflowing) {
1327
+ if (!this.__content) {
1328
+ return;
1329
+ }
1330
+ if (!this._contentHeight) {
1331
+ return;
1332
+ }
1333
+ this._contentOverflow = isOverflowing || this.__content.scrollHeight &gt; this._contentHeight;
1334
+ }
1335
+
1336
+ __toggleScrollStyles() {
1337
+ /* scrollHeight incorrect in IE by 4px second time opened */
1338
+ this._bottomOverflow = this.__content.scrollHeight - (this.__content.scrollTop + this.__content.clientHeight) &gt;= 5;
1339
+ this._topOverflow = this.__content.scrollTop !== 0;
1340
+ }
1341
+
1342
+ _constrainSpaceAround(spaceAround, spaceRequired, targetRect) {
1343
+ const constrained = { ...spaceAround };
1344
+ if (this.boundary) {
1345
+ constrained.above = this.boundary.above &gt;= 0 ? Math.min(spaceAround.above, this.boundary.above) : spaceAround.above;
1346
+ constrained.below = this.boundary.below &gt;= 0 ? Math.min(spaceAround.below, this.boundary.below) : spaceAround.below;
1347
+ constrained.left = this.boundary.left &gt;= 0 ? Math.min(spaceAround.left, this.boundary.left) : spaceAround.left;
1348
+ constrained.right = this.boundary.right &gt;= 0 ? Math.min(spaceAround.right, this.boundary.right) : spaceAround.right;
1349
+ }
1350
+ const isRTL = this.getAttribute('dir') === 'rtl';
1351
+ if ((this.align === 'start' && !isRTL) || (this.align === 'end' && isRTL)) {
1352
+ constrained.left = Math.max(0, spaceRequired.width - (targetRect.width + spaceAround.right));
1353
+ } else if ((this.align === 'start' && isRTL) || (this.align === 'end' && !isRTL)) {
1354
+ constrained.right = Math.max(0, spaceRequired.width - (targetRect.width + spaceAround.left));
1355
+ }
1356
+ return constrained;
1357
+ }
1358
+
1359
+ _getBottomTrayStyling() {
1360
+
1361
+ let maxHeightOverride;
1362
+ let availableHeight = Math.min(window.innerHeight, window.screen.height);
1363
+ if (this._ifrauContextInfo) availableHeight = this._ifrauContextInfo.availableHeight;
1364
+ // default maximum height for bottom tray (42px margin)
1365
+ const mobileTrayMaxHeightDefault = availableHeight - minBackdropHeightMobile;
1366
+ if (this.maxHeight) {
1367
+ // if maxWidth provided is smaller, use the maxWidth
1368
+ maxHeightOverride = Math.min(mobileTrayMaxHeightDefault, this.maxHeight);
1369
+ } else {
1370
+ maxHeightOverride = mobileTrayMaxHeightDefault;
1371
+ }
1372
+ maxHeightOverride = `${maxHeightOverride}px`;
1373
+
1374
+ let bottomOverride;
1375
+ if (this._ifrauContextInfo) {
1376
+ // Bottom override is measured as
1377
+ // the distance from the bottom of the screen
1378
+ const screenHeight =
1379
+ window.innerHeight
1380
+ - this._ifrauContextInfo.availableHeight
1381
+ + Math.min(this._ifrauContextInfo.top, 0);
1382
+ bottomOverride = `${screenHeight}px`;
1383
+ }
1384
+
1385
+ const widthOverride = '100vw';
1386
+
1387
+ const widthStyle = {
1388
+ minWidth: widthOverride,
1389
+ width: widthOverride,
1390
+ maxHeight: maxHeightOverride,
1391
+ bottom: bottomOverride
1392
+ };
1393
+
1394
+ const contentWidthStyle = {
1395
+ /* set width of content in addition to width container so header and footer borders are full width */
1396
+ width: widthOverride
1397
+ };
1398
+
1399
+ const headerStyle = {
1400
+ ...contentWidthStyle,
1401
+ minHeight: this._hasHeader ? 'auto' : '5px'
1402
+ };
1403
+
1404
+ const footerStyle = {
1405
+ ...contentWidthStyle,
1406
+ minHeight: this._hasFooter || !this.noMobileCloseButton ? 'auto' : '5px'
1407
+ };
1408
+
1409
+ const contentStyle = {
1410
+ ...contentWidthStyle,
1411
+ maxHeight: maxHeightOverride,
1412
+ overflowY: this._contentOverflow ? 'auto' : 'hidden'
1413
+ };
1414
+
1415
+ const closeButtonStyles = {
1416
+ display: !this.noMobileCloseButton ? 'inline-block' : 'none',
1417
+ width: this._getTrayFooterWidth(),
1418
+ padding: this._hasFooter && !this.noPaddingFooter ? '12px 0 0 0' : '12px',
1419
+ margin: this._getTrayFooterMargin()
1420
+ };
1421
+
1422
+ return {
1423
+ 'width' : widthStyle,
1424
+ 'header' : headerStyle,
1425
+ 'footer' : footerStyle,
1426
+ 'content' : contentStyle,
1427
+ 'close' : closeButtonStyles
1428
+ };
1429
+ }
1430
+
1431
+ _getDropdownStyling() {
1432
+ const widthStyle = {
1433
+ maxWidth: this.maxWidth ? `${this.maxWidth}px` : '',
1434
+ minWidth: this.minWidth ? `${this.minWidth}px` : '',
1435
+ /* add 2 to content width since scrollWidth does not include border */
1436
+ width: this._width ? `${this._width + 20}px` : ''
1437
+ };
1438
+
1439
+ const contentWidthStyle = {
1440
+ minWidth: this.minWidth ? `${this.minWidth}px` : '',
1441
+ /* set width of content in addition to width container so header and footer borders are full width */
1442
+ width: this._width ? `${this._width + 18}px` : '',
1443
+ };
1444
+
1445
+ const contentStyle = {
1446
+ ...contentWidthStyle,
1447
+ maxHeight: this._contentHeight ? `${this._contentHeight}px` : '',
1448
+ overflowY: this._contentOverflow ? 'auto' : 'hidden'
1449
+ };
1450
+
1451
+ const closeButtonStyle = {
1452
+ display: 'none',
1453
+ };
1454
+
1455
+ return {
1456
+ 'width' : widthStyle,
1457
+ 'content' : contentStyle,
1458
+ 'close' : closeButtonStyle,
1459
+ 'header' : contentWidthStyle,
1460
+ 'footer' : contentWidthStyle
1461
+ };
1462
+ }
1463
+
1464
+ _getLeftRightTrayStyling() {
1465
+
1466
+ let maxWidthOverride = this.maxWidth;
1467
+ let availableWidth = Math.min(window.innerWidth, window.screen.width);
1468
+ if (this._ifrauContextInfo) availableWidth = this._ifrauContextInfo.availableWidth;
1469
+ // default maximum width for tray (30px margin)
1470
+ const mobileTrayMaxWidthDefault = Math.min(availableWidth - minBackdropWidthMobile, 420);
1471
+ if (maxWidthOverride) {
1472
+ // if maxWidth provided is smaller, use the maxWidth
1473
+ maxWidthOverride = Math.min(mobileTrayMaxWidthDefault, maxWidthOverride);
1474
+ } else {
1475
+ maxWidthOverride = mobileTrayMaxWidthDefault;
1476
+ }
1477
+
1478
+ let minWidthOverride = this.minWidth;
1479
+ // minimum size - 285px
1480
+ const mobileTrayMinWidthDefault = 285;
1481
+ if (minWidthOverride) {
1482
+ // if minWidth provided is smaller, use the minumum width for tray
1483
+ minWidthOverride = Math.max(mobileTrayMinWidthDefault, minWidthOverride);
1484
+ } else {
1485
+ minWidthOverride = mobileTrayMinWidthDefault;
1486
+ }
1487
+
1488
+ // if no width property set, automatically size to maximum width
1489
+ let widthOverride = this._width ? this._width : maxWidthOverride;
1490
+ // ensure width is between minWidth and maxWidth
1491
+ if (widthOverride && maxWidthOverride && widthOverride &gt; (maxWidthOverride - 20)) widthOverride = maxWidthOverride - 20;
1492
+ if (widthOverride && minWidthOverride && widthOverride &lt; (minWidthOverride - 20)) widthOverride = minWidthOverride - 20;
1493
+
1494
+ maxWidthOverride = `${maxWidthOverride}px`;
1495
+ minWidthOverride = `${minWidthOverride}px`;
1496
+ const contentWidth = `${widthOverride + 18}px`;
1497
+ /* add 2 to content width since scrollWidth does not include border */
1498
+ const containerWidth = `${widthOverride + 20}px`;
1499
+
1500
+ let maxHeightOverride = '';
1501
+ if (this._ifrauContextInfo) maxHeightOverride = `${this._ifrauContextInfo.availableHeight}px`;
1502
+
1503
+ let topOverride;
1504
+ if (this._ifrauContextInfo) {
1505
+ // if inside iframe, use ifrauContext top as top of screen
1506
+ topOverride = `${this._ifrauContextInfo.top &lt; 0 ? -this._ifrauContextInfo.top : 0}px`;
1507
+ } else if (window.innerHeight &gt; window.screen.height) {
1508
+ // non-responsive page, manually override top to scroll distance
1509
+ topOverride = window.pageYOffset;
1510
+ }
1511
+
1512
+ let rightOverride;
1513
+ let leftOverride;
1514
+ if (this.mobileTray === 'right') {
1515
+ // On non-responsive pages, the innerWidth may be wider than the screen,
1516
+ // override right to stick to right of viewport
1517
+ rightOverride = `${Math.max(window.innerWidth - window.screen.width, 0)}px`;
1518
+ }
1519
+ if (this.mobileTray === 'left') {
1520
+ // On non-responsive pages, the innerWidth may be wider than the screen,
1521
+ // override left to stick to left of viewport
1522
+ leftOverride = `${Math.max(window.innerWidth - window.screen.width, 0)}px`;
1523
+ }
1524
+
1525
+ const widthStyle = {
1526
+ maxWidth: maxWidthOverride,
1527
+ minWidth: minWidthOverride,
1528
+ width: containerWidth,
1529
+ maxHeight: maxHeightOverride,
1530
+ top: topOverride,
1531
+ right: rightOverride,
1532
+ left: leftOverride,
1533
+ };
1534
+
1535
+ const contentWidthStyle = {
1536
+ minWidth: minWidthOverride,
1537
+ /* set width of content in addition to width container so header and footer borders are full width */
1538
+ width: contentWidth,
1539
+ };
1540
+
1541
+ const headerStyle = {
1542
+ ...contentWidthStyle,
1543
+ minHeight: this._hasHeader ? 'auto' : '5px'
1544
+ };
1545
+
1546
+ const footerStyle = {
1547
+ ...contentWidthStyle,
1548
+ minHeight: this._hasFooter || !this.noMobileCloseButton ? 'auto' : '5px'
1549
+ };
1550
+
1551
+ const contentStyle = {
1552
+ ...contentWidthStyle,
1553
+ maxHeight: maxHeightOverride,
1554
+ overflowY: this._contentOverflow ? 'auto' : 'hidden'
1555
+ };
316
1556
 
317
- <pre class="d2l-code"><code class="language-javascript line-numbers">// comment
318
- /* comment */
1557
+ const closeButtonStyles = {
1558
+ display: !this.noMobileCloseButton ? 'inline-block' : 'none',
1559
+ width: this._getTrayFooterWidth(),
1560
+ padding: this._hasFooter && !this.noPaddingFooter ? '12px 0 0 0' : '12px',
1561
+ margin: this._getTrayFooterMargin()
1562
+ };
319
1563
 
320
- import { stuff } from 'some/where.js'; // keyword, punctuation, string
1564
+ return {
1565
+ 'width' : widthStyle,
1566
+ 'header' : headerStyle,
1567
+ 'footer' : footerStyle,
1568
+ 'content' : contentStyle,
1569
+ 'close' : closeButtonStyles
1570
+ };
1571
+ }
1572
+
1573
+ _getOpenedAbove(spaceAround, spaceAroundScroll, spaceRequired) {
1574
+ if (spaceAround.below &gt;= spaceRequired.height) {
1575
+ return false;
1576
+ }
1577
+ if (spaceAround.above &gt;= spaceRequired.height) {
1578
+ return true;
1579
+ }
1580
+ if (!this.noAutoFit) {
1581
+ // if auto-fit is enabled, scroll will be enabled for the
1582
+ // inner content so it will always fit in the available space
1583
+ // so pick the largest space it can be displayed in
1584
+ return spaceAround.above &gt; spaceAround.below;
1585
+ }
1586
+ if (spaceAroundScroll.below &gt;= spaceRequired.height) {
1587
+ return false;
1588
+ }
1589
+ if (spaceAroundScroll.above &gt;= spaceRequired.height) {
1590
+ return true;
1591
+ }
1592
+ // if auto-fit is disabled and it doesn't fit in the scrollable space
1593
+ // above or below, always open down because it can add scrollable space
1594
+ return false;
1595
+ }
1596
+
1597
+ _getPosition(spaceAround, centerDelta) {
1598
+
1599
+ const contentXAdjustment = centerDelta / 2;
1600
+ if (centerDelta &lt;= 0) {
1601
+ return contentXAdjustment * -1;
1602
+ }
1603
+ if (spaceAround.left &gt; contentXAdjustment && spaceAround.right &gt; contentXAdjustment) {
1604
+ // center with target
1605
+ return contentXAdjustment * -1;
1606
+ }
1607
+ const isRTL = this.getAttribute('dir') === 'rtl';
1608
+ if (!isRTL) {
1609
+ if (spaceAround.left &lt; contentXAdjustment) {
1610
+ // slide content right (not enough space to center)
1611
+ return spaceAround.left * -1;
1612
+ } else if (spaceAround.right &lt; contentXAdjustment) {
1613
+ // slide content left (not enough space to center)
1614
+ return (centerDelta * -1) + spaceAround.right;
1615
+ }
1616
+ } else {
1617
+ if (spaceAround.left &lt; contentXAdjustment) {
1618
+ // slide content right (not enough space to center)
1619
+ return (centerDelta * -1) + spaceAround.left;
1620
+ } else if (spaceAround.right &lt; contentXAdjustment) {
1621
+ // slide content left (not enough space to center)
1622
+ return spaceAround.right * -1;
1623
+ }
1624
+ }
1625
+ return null;
1626
+ }
1627
+
1628
+ _getTrayFooterMargin() {
1629
+ let footerMargin;
1630
+ if (this._hasFooter) {
1631
+ footerMargin = '0';
1632
+ } else if (this.getAttribute('dir') === 'rtl') {
1633
+ footerMargin = '-20px -20px -20px 0px';
1634
+ } else {
1635
+ footerMargin = '-20px 0 -20px -20px';
1636
+ }
1637
+ return footerMargin;
1638
+ }
1639
+
1640
+ _getTrayFooterWidth() {
1641
+ let footerWidth;
1642
+ if (this.noPaddingFooter) {
1643
+ footerWidth = 'calc(100% - 24px)';
1644
+ } else if (this._hasFooter) {
1645
+ footerWidth = '100%';
1646
+ } else {
1647
+ footerWidth = 'calc(100% + 16px)';
1648
+ }
1649
+ return footerWidth;
1650
+ }
1651
+
1652
+ _handleFocusTrapEnter() {
1653
+ if (this.__applyFocus && !this.noAutoFocus) {
1654
+ const content = this.__getContentContainer();
1655
+ const focusable = getFirstFocusableDescendant(content);
1656
+ if (focusable) {
1657
+ // Removing the rAF call can allow infinite focus looping to happen in content using a focus trap
1658
+ requestAnimationFrame(() =&gt; focusable.focus());
1659
+ } else {
1660
+ content.setAttribute('tabindex', '-1');
1661
+ content.focus();
1662
+ }
1663
+ }
1664
+ /** Dispatched when user focus enters the dropdown content (trap-focus option only) */
1665
+ this.dispatchEvent(new CustomEvent('d2l-dropdown-focus-enter', { detail:{ applyFocus: this.__applyFocus } }));
1666
+ }
1667
+
1668
+ async _handleMobileResize() {
1669
+ this._useMobileStyling = this.mediaQueryList.matches;
1670
+ if (this.opened) this._showBackdrop = this._useMobileStyling && this.mobileTray;
1671
+ if (this.opened) await this.__position();
1672
+ }
1673
+
1674
+ _renderContent() {
1675
+ const positionStyle = {};
1676
+ const isRTL = this.getAttribute('dir') === 'rtl';
1677
+ if (this._position) {
1678
+ if (!isRTL) {
1679
+ positionStyle.left = `${this._position}px`;
1680
+ } else {
1681
+ positionStyle.right = `${this._position}px`;
1682
+ }
1683
+ }
1684
+
1685
+ const mobileTrayRightLeft = this._useMobileStyling && (this.mobileTray === 'right' || this.mobileTray === 'left');
1686
+ const mobileTrayBottom = this._useMobileStyling && (this.mobileTray === 'bottom');
1687
+
1688
+ let stylesMap;
1689
+ if (mobileTrayBottom) {
1690
+ stylesMap = this._getBottomTrayStyling();
1691
+ } else if (mobileTrayRightLeft) {
1692
+ stylesMap = this._getLeftRightTrayStyling();
1693
+ } else {
1694
+ stylesMap = this._getDropdownStyling();
1695
+ }
1696
+ const widthStyle = stylesMap['width'];
1697
+ const headerStyle = stylesMap['header'];
1698
+ const footerStyle = stylesMap['footer'];
1699
+ const contentStyle = stylesMap['content'];
1700
+ const closeButtonStyles = stylesMap['close'];
1701
+
1702
+ const topClasses = {
1703
+ 'd2l-dropdown-content-top': true,
1704
+ 'd2l-dropdown-content-top-scroll': this._topOverflow,
1705
+ 'd2l-dropdown-content-header': this._hasHeader
1706
+ };
1707
+ const bottomClasses = {
1708
+ 'd2l-dropdown-content-bottom': true,
1709
+ 'd2l-dropdown-content-bottom-scroll': this._bottomOverflow,
1710
+ 'd2l-dropdown-content-footer': this._hasFooter || (this._useMobileStyling && this.mobileTray && !this.noMobileCloseButton)
1711
+ };
1712
+
1713
+ let dropdownContentSlots = html`
1714
+ &lt;div
1715
+ id="d2l-dropdown-wrapper"
1716
+ class="d2l-dropdown-content-width"
1717
+ style=${styleMap(widthStyle)}
1718
+ ?data-closing="${this._closing}"&gt;
1719
+ &lt;div class=${classMap(topClasses)} style=${styleMap(headerStyle)}&gt;
1720
+ &lt;slot name="header" @slotchange="${this.__handleHeaderSlotChange}"&gt;&lt;/slot&gt;
1721
+ &lt;/div&gt;
1722
+ &lt;div
1723
+ class="d2l-dropdown-content-container"
1724
+ style=${styleMap(contentStyle)}
1725
+ @scroll=${this.__toggleScrollStyles}&gt;
1726
+ &lt;slot class="d2l-dropdown-content-slot"&gt;&lt;/slot&gt;
1727
+ &lt;/div&gt;
1728
+ &lt;div class=${classMap(bottomClasses)} style=${styleMap(footerStyle)}&gt;
1729
+ &lt;slot name="footer" @slotchange="${this.__handleFooterSlotChange}"&gt;&lt;/slot&gt;
1730
+ &lt;d2l-button
1731
+ class="dropdown-close-btn"
1732
+ style=${styleMap(closeButtonStyles)}
1733
+ @click=${this.close}&gt;
1734
+ ${this.localize('components.dropdown.close')}
1735
+ &lt;/d2l-button&gt;
1736
+ &lt;/div&gt;
1737
+ &lt;/div&gt;
1738
+ `;
1739
+
1740
+ if (this.trapFocus) {
1741
+ dropdownContentSlots = html`
1742
+ &lt;d2l-focus-trap
1743
+ @d2l-focus-trap-enter="${this._handleFocusTrapEnter}"
1744
+ ?trap="${this.opened}"&gt;
1745
+ ${dropdownContentSlots}
1746
+ &lt;/d2l-focus-trap&gt;`;
1747
+ }
1748
+
1749
+ const dropdown = html`
1750
+ &lt;div class="d2l-dropdown-content-position" style=${styleMap(positionStyle)}&gt;
1751
+ ${dropdownContentSlots}
1752
+ &lt;/div&gt;
1753
+ `;
1754
+
1755
+ return (this.mobileTray) ? html`
1756
+ ${dropdown}
1757
+ &lt;d2l-backdrop
1758
+ for-target="d2l-dropdown-wrapper"
1759
+ ?shown="${this._showBackdrop}" &gt;
1760
+ &lt;/d2l-backdrop&gt;`
1761
+ : html`${dropdown}`;
1762
+ }
1763
+
1764
+ };
1765
+ </code></pre>
1766
+
1767
+
1768
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-javascript">import '../colors/colors.js';
1769
+ import { css, html, LitElement } from 'lit';
1770
+ import { classMap } from 'lit/directives/class-map.js';
1771
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
1772
+ import { ifDefined } from 'lit/directives/if-defined.js';
1773
+ import { offscreenStyles } from '../offscreen/offscreen.js';
1774
+ import ResizeObserver from 'resize-observer-polyfill/dist/ResizeObserver.es.js';
1775
+ import { RtlMixin } from '../../mixins/rtl-mixin.js';
1776
+ import { styleMap } from 'lit/directives/style-map.js';
1777
+
1778
+ /**
1779
+ * A container element that provides specific layout using several slots.
1780
+ * @slot content - Slot for primary content such as title and supplementary info (no actionable elements)
1781
+ * @slot actions - Slot for buttons and dropdown openers to be placed in top right corner of header
1782
+ * @slot badge - Slot for badge content, such as a profile image or status indicator
1783
+ * @slot footer - Slot for footer content, such secondary actions
1784
+ * @slot header - Slot for header content, such as course image (no actionable elements)
1785
+ */
1786
+ class Card extends FocusMixin(RtlMixin(LitElement)) {
1787
+
1788
+ static get properties() {
1789
+ return {
1790
+ /**
1791
+ * Style the card's content and footer as centered horizontally
1792
+ * @type {boolean}
1793
+ */
1794
+ alignCenter: { type: Boolean, attribute: 'align-center', reflect: true },
1795
+ /**
1796
+ * Download a URL instead of navigating to it
1797
+ * @type {boolean}
1798
+ */
1799
+ download: { type: Boolean, reflect: true },
1800
+ /**
1801
+ * Location for the primary action/navigation
1802
+ * @type {string}
1803
+ */
1804
+ href: { type: String, reflect: true },
1805
+ /**
1806
+ * Indicates the human language of the linked resource; purely advisory, with no built-in functionality
1807
+ * @type {string}
1808
+ */
1809
+ hreflang: { type: String, reflect: true },
1810
+ /**
1811
+ * Specifies the relationship of the target object to the link object
1812
+ * @type {string}
1813
+ */
1814
+ rel: { type: String, reflect: true },
1815
+ /**
1816
+ * Subtle aesthetic on non-white backgrounds
1817
+ * @type {boolean}
1818
+ */
1819
+ subtle: { type: Boolean, reflect: true },
1820
+ /**
1821
+ * Where to display the linked URL
1822
+ * @type {string}
1823
+ */
1824
+ target: { type: String, reflect: true },
1825
+ /**
1826
+ * Accessible text for the card (will be announced when AT user focuses)
1827
+ * @type {string}
1828
+ */
1829
+ text: { type: String, reflect: true },
1830
+ /**
1831
+ * Specifies the media type in the form of a MIME type for the linked URL; purely advisory, with no built-in functionality
1832
+ * @type {string}
1833
+ */
1834
+ type: { type: String, reflect: true },
1835
+ _active: { type: Boolean, reflect: true },
1836
+ _dropdownActionOpen: { type: Boolean, attribute: '_dropdown-action-open', reflect: true },
1837
+ _hover: { type: Boolean },
1838
+ _badgeMarginTop: { type: String },
1839
+ _footerHidden: { type: Boolean },
1840
+ _tooltipShowing: { type: Boolean, attribute: '_tooltip_showing', reflect: true }
1841
+ };
1842
+ }
1843
+
1844
+ static get styles() {
1845
+ return [offscreenStyles, css`
1846
+ :host {
1847
+ background-color: #ffffff;
1848
+ border: 1px solid var(--d2l-color-gypsum);
1849
+ border-radius: 6px;
1850
+ box-sizing: border-box;
1851
+ display: inline-block;
1852
+ position: relative;
1853
+ z-index: 0;
1854
+ }
1855
+ .d2l-card-container {
1856
+ align-items: flex-start; /* required so that footer will not stretch to 100% width */
1857
+ display: flex;
1858
+ flex-direction: column;
1859
+ height: 100%;
1860
+ position: relative;
1861
+ }
1862
+ .d2l-card-link-container {
1863
+ border-radius: 6px;
1864
+ flex-basis: auto;
1865
+ flex-grow: 1;
1866
+ flex-shrink: 1;
1867
+ overflow: hidden;
1868
+ width: 100%; /* required for Legacy-Edge and FF when align-items: flex-start is specified */
1869
+ }
1870
+ .d2l-card-link-text {
1871
+ display: inline-block;
1872
+ }
1873
+
1874
+ a {
1875
+ bottom: -1px;
1876
+ display: block;
1877
+ left: -1px;
1878
+ outline: none;
1879
+ position: absolute;
1880
+ right: -1px;
1881
+ top: -1px;
1882
+ z-index: 1;
1883
+ }
1884
+ :host([subtle]) a {
1885
+ bottom: 0;
1886
+ left: 0;
1887
+ right: 0;
1888
+ top: 0;
1889
+ }
1890
+
1891
+ :host(:hover) a {
1892
+ bottom: -5px;
1893
+ }
1894
+ :host([subtle]:hover) a {
1895
+ bottom: -4px;
1896
+ }
1897
+
1898
+ .d2l-card-content {
1899
+ padding: 1.2rem 0.8rem 0 0.8rem;
1900
+ }
1901
+ :host([align-center]) .d2l-card-content {
1902
+ text-align: center;
1903
+ }
1904
+
1905
+ .d2l-card-footer-hidden .d2l-card-content {
1906
+ padding-bottom: 1.2rem;
1907
+ }
1908
+ .d2l-card-actions {
1909
+ position: absolute;
1910
+ right: 0.6rem;
1911
+ top: 0.6rem;
1912
+ /* this must be higher than footer z-index so dropdowns will be on top */
1913
+ z-index: 3;
1914
+ }
1915
+ :host([dir="rtl"]) .d2l-card-actions {
1916
+ left: 0.6rem;
1917
+ right: auto;
1918
+ }
1919
+ .d2l-card-actions ::slotted(*) {
1920
+ margin-left: 0.3rem;
1921
+ }
1922
+ :host([dir="rtl"]) .d2l-card-actions ::slotted(*) {
1923
+ margin-left: 0;
1924
+ margin-right: 0.3rem;
1925
+ }
1926
+ .d2l-card-badge {
1927
+ line-height: 0;
1928
+ padding: 0 0.8rem;
1929
+ }
1930
+ .d2l-card-footer {
1931
+ box-sizing: border-box;
1932
+ flex: none;
1933
+ padding: 1.2rem 0.8rem 0.6rem 0.8rem;
1934
+ pointer-events: none;
1935
+ width: 100%;
1936
+ z-index: 2;
1937
+ }
1938
+ :host([align-center]) .d2l-card-footer {
1939
+ text-align: center;
1940
+ }
1941
+
1942
+ .d2l-card-footer ::slotted([slot="footer"]) {
1943
+ pointer-events: all;
1944
+ }
1945
+
1946
+ .d2l-card-footer-hidden .d2l-card-footer {
1947
+ box-sizing: content-box;
1948
+ height: auto;
1949
+ }
1950
+
1951
+ :host([subtle]) {
1952
+ border: none;
1953
+ box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.03);
1954
+ }
1955
+ :host(:hover) {
1956
+ box-shadow: 0 2px 14px 1px rgba(0, 0, 0, 0.06);
1957
+ }
1958
+ :host([subtle]:hover) {
1959
+ box-shadow: 0 4px 18px 2px rgba(0, 0, 0, 0.06);
1960
+ }
1961
+ :host([_active]) {
1962
+ border-color: transparent;
1963
+ box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px var(--d2l-color-celestine);
1964
+ }
1965
+ :host([_active]:hover),
1966
+ :host([subtle][_active]:hover) {
1967
+ border-color: transparent;
1968
+ box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px var(--d2l-color-celestine);
1969
+ }
1970
+ /* .d2l-card-link-container-hover is used to only color/underline when
1971
+ hovering the anchor; these styles are not applied when hovering actions */
1972
+ :host([href]) .d2l-card-link-container-hover,
1973
+ :host([href][_active]) .d2l-card-content {
1974
+ color: var(--d2l-color-celestine);
1975
+ text-decoration: underline;
1976
+ }
1977
+ /* this is needed to ensure tooltip is not be clipped by adjacent cards */
1978
+ :host([_tooltip_showing]) {
1979
+ z-index: 1;
1980
+ }
1981
+ /* this is needed to ensure open menu will be ontop of adjacent cards */
1982
+ :host([_dropdown-action-open]) {
1983
+ z-index: 2;
1984
+ }
1985
+ :host(:not([href])),
1986
+ :host([subtle]:not([href])) {
1987
+ box-shadow: none;
1988
+ transform: none;
1989
+ }
1990
+ @media (prefers-reduced-motion: no-preference) {
1991
+ :host {
1992
+ transition: transform 300ms ease-out 50ms, box-shadow 0.2s;
1993
+ }
1994
+
1995
+ :host(:hover),
1996
+ :host([subtle]:hover),
1997
+ :host([_active]:hover),
1998
+ :host([subtle][_active]:hover) {
1999
+ transform: translateY(-4px);
2000
+ }
2001
+ }
2002
+ `];
2003
+ }
2004
+
2005
+ constructor() {
2006
+ super();
2007
+ this.alignCenter = false;
2008
+ this.download = false;
2009
+ this.subtle = false;
2010
+ this._active = false;
2011
+ this._dropdownActionOpen = false;
2012
+ this._footerHidden = true;
2013
+ this._hover = false;
2014
+ this._tooltipShowing = false;
2015
+ this._onBadgeResize = this._onBadgeResize.bind(this);
2016
+ this._onFooterResize = this._onFooterResize.bind(this);
2017
+ }
2018
+
2019
+ static get focusElementSelector() {
2020
+ return 'a';
2021
+ }
2022
+
2023
+ firstUpdated(changedProperties) {
2024
+ super.firstUpdated(changedProperties);
2025
+ const badgeObserver = new ResizeObserver(this._onBadgeResize);
2026
+ badgeObserver.observe(this.shadowRoot.querySelector('.d2l-card-badge'));
2027
+ const footerObserver = new ResizeObserver(this._onFooterResize);
2028
+ footerObserver.observe(this.shadowRoot.querySelector('.d2l-card-footer'));
2029
+ }
2030
+
2031
+ render() {
2032
+
2033
+ const containerClass = {
2034
+ 'd2l-card-container': true,
2035
+ 'd2l-visible-on-ancestor-target': true,
2036
+ 'd2l-card-footer-hidden': this._footerHidden
2037
+ };
2038
+
2039
+ const linkContainerClass = {
2040
+ 'd2l-card-link-container': true,
2041
+ 'd2l-card-link-container-hover': this._hover
2042
+ };
2043
+
2044
+ const badgeStyle = {};
2045
+ if (this._badgeMarginTop) badgeStyle.marginTop = this._badgeMarginTop;
2046
+
2047
+ const footerClass = {
2048
+ 'd2l-card-footer': true,
2049
+ 'd2l-offscreen': this._footerHidden
2050
+ };
2051
+
2052
+ return html`
2053
+ &lt;div class="${classMap(containerClass)}"
2054
+ @d2l-dropdown-open="${this._onDropdownOpen}"
2055
+ @d2l-dropdown-close="${this._onDropdownClose}"
2056
+ @d2l-tooltip-show="${this._onTooltipShow}"
2057
+ @d2l-tooltip-hide="${this._onTooltipHide}"&gt;
2058
+ &lt;a @blur="${this._onLinkBlur}"
2059
+ ?download="${this.download}"
2060
+ @focus="${this._onLinkFocus}"
2061
+ href="${ifDefined(this.href ? this.href : undefined)}"
2062
+ hreflang="${ifDefined(this.hreflang)}"
2063
+ @mouseenter="${this._onLinkMouseEnter}"
2064
+ @mouseleave="${this._onLinkMouseLeave}"
2065
+ rel="${ifDefined(this.rel)}"
2066
+ target="${ifDefined(this.target)}"
2067
+ type="${ifDefined(this.type)}"&gt;
2068
+ &lt;span class="d2l-card-link-text d2l-offscreen"&gt;${this.text}&lt;/span&gt;
2069
+ &lt;/a&gt;
2070
+ &lt;div class="${classMap(linkContainerClass)}"&gt;
2071
+ &lt;div class="d2l-card-header"&gt;&lt;slot name="header"&gt;&lt;/slot&gt;&lt;/div&gt;
2072
+ &lt;div class="d2l-card-badge" style="${styleMap(badgeStyle)}"&gt;&lt;slot name="badge"&gt;&lt;/slot&gt;&lt;/div&gt;
2073
+ &lt;div class="d2l-card-content"&gt;&lt;slot name="content"&gt;&lt;/slot&gt;&lt;/div&gt;
2074
+ &lt;/div&gt;
2075
+ &lt;div class="d2l-card-actions"&gt;&lt;slot name="actions"&gt;&lt;/slot&gt;&lt;/div&gt;
2076
+ &lt;div class="${classMap(footerClass)}"&gt;&lt;slot name="footer"&gt;&lt;/slot&gt;&lt;/div&gt;
2077
+ &lt;/div&gt;
2078
+ `;
2079
+ }
2080
+
2081
+ _onBadgeResize(entries) {
2082
+ if (!entries || entries.length === 0) return;
2083
+ const entry = entries[0];
2084
+ this._badgeMarginTop = `${-0.5 * entry.contentRect.height}px`;
2085
+ }
2086
+
2087
+ _onDropdownClose() {
2088
+ this._dropdownActionOpen = false;
2089
+ }
2090
+
2091
+ _onDropdownOpen() {
2092
+ this._dropdownActionOpen = true;
2093
+ }
2094
+
2095
+ _onFooterResize(entries) {
2096
+ if (!entries || entries.length === 0) return;
2097
+ const entry = entries[0];
2098
+ // firefox has a rounding error when calculating the height of the contentRect
2099
+ // with `box-sizing: border-box;` so check for numbers which are close to 0 as well
2100
+ this._footerHidden = (entry.contentRect.height &lt; 1);
2101
+ }
2102
+
2103
+ _onLinkBlur() {
2104
+ this._active = false;
2105
+ }
2106
+
2107
+ _onLinkFocus() {
2108
+ this._active = true;
2109
+ }
2110
+
2111
+ _onLinkMouseEnter() {
2112
+ this._hover = true;
2113
+ }
2114
+
2115
+ _onLinkMouseLeave() {
2116
+ this._hover = false;
2117
+ }
2118
+
2119
+ _onTooltipHide() {
2120
+ this._tooltipShowing = false;
2121
+ }
2122
+
2123
+ _onTooltipShow() {
2124
+ this._tooltipShowing = true;
2125
+ }
321
2126
 
322
- function helloGrumpy(name) { // keyword, function, parameter
323
- console.log(`Hi there ${name}.`); // template-string, template-punctuation, interpolation, interpolation-punctuation
324
2127
  }
325
2128
 
326
- class Wizard extends Human { } // keyword, class-name
2129
+ customElements.define('d2l-card', Card);
2130
+ </code></pre>
2131
+
2132
+ <h2 class="d2l-heading-3">Language Samples</h2>
2133
+
2134
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-arduino">// digital pin 2 has a pushbutton attached to it. Give it a name:
2135
+ int pushButton = 2;
2136
+
2137
+ // the setup routine runs once when you press reset:
2138
+ void setup() {
2139
+ // initialize serial communication at 9600 bits per second:
2140
+ Serial.begin(9600);
2141
+ // make the pushbutton's pin an input:
2142
+ pinMode(pushButton, INPUT);
2143
+ }
327
2144
 
328
- const grumpy = new Wizard(); // keyword, operator, class-name
2145
+ // the loop routine runs over and over again forever:
2146
+ void loop() {
2147
+ // read the input pin:
2148
+ int buttonState = digitalRead(pushButton);
2149
+ // print out the state of the button:
2150
+ Serial.println(buttonState);
2151
+ delay(1); // delay in between reads for stability
2152
+ }
2153
+ </code></pre>
329
2154
 
330
- let wizardFoods = [...donuts, ... cakes, ...pies]; // keyword, operator
2155
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-armasm">
2156
+ AREA ARMex, CODE, READONLY
2157
+ ; Name this block of code ARMex
2158
+ ENTRY ; Mark first instruction to execute
2159
+ start
2160
+ MOV r0, #10 ; Set up parameters
2161
+ MOV r1, #3
2162
+ ADD r0, r0, r1 ; r0 = r0 + r1
2163
+ stop
2164
+ MOV r0, #0x18 ; angel_SWIreason_ReportException
2165
+ LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
2166
+ SVC #0x123456 ; ARM semihosting (formerly SWI)
2167
+ END ; Mark end of file
2168
+ </code></pre>
331
2169
 
332
- const wizardsLikeBeer = false; // keyword, operator, boolean
2170
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-bash">#!/bin/bash
2171
+ if [ -d $directory ]; then
2172
+ echo "Directory exists"
2173
+ else
2174
+ echo "Directory does not exists"
2175
+ fi</code></pre>
333
2176
 
334
- const favouriteNumber = 3.14159; // keyword, operator, number
2177
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-c">#include &lt;stdio.h&gt;
2178
+ int main() {
2179
+ char c;
2180
+ printf("Enter a character: ");
2181
+ scanf("%c", &c);
335
2182
 
336
- const PI = 3.14159; // keyword, operator, constant
2183
+ // %d displays the integer value of a character
2184
+ // %c displays the actual character
2185
+ printf("ASCII value of %c = %d", c, c);
337
2186
 
338
- const regex = /[^\w\s]/g; // keyword, operator, regex, regex-delimiter, regex-source, regex-flags
2187
+ return 0;
2188
+ }
339
2189
  </code></pre>
340
2190
 
341
- <pre class="d2l-code"><code class="language-css line-numbers">.grumpy > img { /* selector */
342
- background-image: url("smile.png"); /* property, url, string */
343
- height: 100%; /* property, punctuation */
344
- width: var(--some-var); /* property, punctuation, function */
2191
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-cpp">#include &lt;iostream&gt;
2192
+ using namespace std;
2193
+
2194
+ int main()
2195
+ {
2196
+ int divisor, dividend, quotient, remainder;
2197
+
2198
+ cout << "Enter dividend: ";
2199
+ cin >> dividend;
2200
+
2201
+ cout << "Enter divisor: ";
2202
+ cin >> divisor;
2203
+
2204
+ quotient = dividend / divisor;
2205
+ remainder = dividend % divisor;
2206
+
2207
+ cout << "Quotient = " << quotient << endl;
2208
+ cout << "Remainder = " << remainder;
2209
+
2210
+ return 0;
345
2211
  }
346
- @font-face { /* atrule, rule */
347
- font-family: 'Lato'; /* property, punctuation, string */
2212
+ </code></pre>
2213
+
2214
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-csharp">using System;
2215
+
2216
+ namespace Method {
2217
+
2218
+ class Program {
2219
+
2220
+ // method declaration
2221
+ public void display() {
2222
+ Console.WriteLine("Hello World");
2223
+ }
2224
+
2225
+ static void Main(string[] args) {
2226
+
2227
+ // create class object
2228
+ Program p1 = new Program();
2229
+
2230
+ //call method
2231
+ p1.display();
2232
+
2233
+ Console.ReadLine();
2234
+
2235
+ }
2236
+ }
2237
+ }
2238
+ </code></pre>
2239
+
2240
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-css">.grumpy > img {
2241
+ background-image: url("smile.png");
2242
+ height: 100%;
2243
+ width: var(--some-var);
2244
+ }
2245
+ @font-face {
2246
+ font-family: 'Lato';
348
2247
  font-style: normal;
349
- src: local('Lato Regular'); /* property, function, string */
2248
+ src: local('Lato Regular');
350
2249
  }
351
- @media (prefers-reduced-motion: reduce) { /* atrule, rule, property */
2250
+ @media (prefers-reduced-motion: reduce) {
352
2251
  :host([opened]), :host([opened-above]) {
353
- animation: none !important; /* property, important */
2252
+ animation: none !important;
354
2253
  }
355
2254
  }
356
2255
  </code></pre>
357
2256
 
358
- <pre class="d2l-code"><code class="language-markup line-numbers">&lt;!DOCTYPE html&gt; &lt;!-- doctype, doctype-tag, name --&gt;
359
- &lt;html&gt; &lt;!-- tag, punctuation --&gt;
360
- &lt;body class="typography"&gt; &lt;!-- attr-name, attr-value --&gt;
361
- &lt;![CDATA[ some cdata section ]]&gt; &lt;!-- cdata --&gt;
362
- &lt;div style="color: blue;"&gt; &lt;!-- attr-name, attr-value, attr-equals, value, css, property --&gt;
363
- &amp;pound; &lt;!-- entity, named-entity --&gt;
364
- &amp;#163; &lt;!-- entity --&gt;
2257
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-haskell">{-# START_FILE main.hs #-}
2258
+ import System.IO
2259
+
2260
+ main = do
2261
+ handle &lt;- openFile "file.txt" ReadMode
2262
+ contents &lt;- hGetContents handle
2263
+ putStr contents
2264
+ hClose handle
2265
+
2266
+ {-# START_FILE file.txt #-}
2267
+ Hello, world!
2268
+
2269
+ import System.Random
2270
+
2271
+ main = (randomRIO (1, 100) :: IO Int) &gt;&gt;= print
2272
+ </code></pre>
2273
+
2274
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-java">public class VowelConsonant {
2275
+
2276
+ public static void main(String[] args) {
2277
+
2278
+ char ch = 'i';
2279
+
2280
+ if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u' )
2281
+ System.out.println(ch + " is vowel");
2282
+ else
2283
+ System.out.println(ch + " is consonant");
2284
+
2285
+ }
2286
+ }
2287
+ </code></pre>
2288
+
2289
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-javascript">
2290
+ /* grumpy javascript */
2291
+
2292
+ import { stuff } from 'some/where.js';
2293
+
2294
+ function helloGrumpy(name) {
2295
+ console.log(`Hi there ${name}.`);
2296
+ }
2297
+
2298
+ class Wizard extends Human { }
2299
+
2300
+ const grumpy = new Wizard();
2301
+
2302
+ let wizardFoods = [...donuts, ... cakes, ...pies];
2303
+
2304
+ const wizardsLikeBeer = false;
2305
+
2306
+ const favouriteNumber = 3.14159;
2307
+
2308
+ const PI = 3.14159;
2309
+
2310
+ const regex = /[^\w\s]/g; // regex, regex-delimiter, regex-source, regex-flag
2311
+ </code></pre>
2312
+
2313
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-json">{
2314
+ "jinxed": "gnomes",
2315
+ "grumpy": [ "wizards" ],
2316
+ "jelly": 99,
2317
+ "donut": true,
2318
+ "fritter": null
2319
+ }
2320
+ </code></pre>
2321
+
2322
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-kotlin">fun main(args: Array<String>) {
2323
+
2324
+ val a = 2.3
2325
+ val b = 4
2326
+ val c = 5.6
2327
+ val root1: Double
2328
+ val root2: Double
2329
+ val output: String
2330
+
2331
+ val determinant = b * b - 4.0 * a * c
2332
+
2333
+ // condition for real and different roots
2334
+ if (determinant > 0) {
2335
+ root1 = (-b + Math.sqrt(determinant)) / (2 * a)
2336
+ root2 = (-b - Math.sqrt(determinant)) / (2 * a)
2337
+
2338
+ output = "root1 = %.2f and root2 = %.2f".format(root1, root2)
2339
+ }
2340
+ // Condition for real and equal roots
2341
+ else if (determinant == 0.0) {
2342
+ root2 = -b / (2 * a)
2343
+ root1 = root2
2344
+
2345
+ output = "root1 = root2 = %.2f;".format(root1)
2346
+ }
2347
+ // If roots are not real
2348
+ else {
2349
+ val realPart = -b / (2 * a)
2350
+ val imaginaryPart = Math.sqrt(-determinant) / (2 * a)
2351
+
2352
+ output = "root1 = %.2f+%.2fi and root2 = %.2f-%.2fi".format(realPart, imaginaryPart, realPart, imaginaryPart)
2353
+ }
2354
+
2355
+ println(output)
2356
+ }
2357
+ </code></pre>
2358
+
2359
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-latex">
2360
+ \begin{aligned} \nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = \frac{4\pi}{c}\vec{\mathbf{j}} \\ \nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\ \nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\ \nabla \cdot \vec{\mathbf{B}} & = 0 \end{aligned}
2361
+
2362
+ P(E) = {n \choose k} p^k (1-p)^{ n-k}
2363
+
2364
+ \begin{aligned} \dot{x} & = \sigma(y-x) \\ \dot{y} & = \rho x - y - xz \\ \dot{z} & = -\beta z + xy \end{aligned}
2365
+ </code></pre>
2366
+
2367
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-markup">&lt;!DOCTYPE html&gt; &lt;!-- doctype, doctype-tag, name --&gt;
2368
+ &lt;html&gt;
2369
+ &lt;body class="typography"&gt;
2370
+ &lt;![CDATA[ some cdata section ]]&gt;
2371
+ &lt;div style="color: blue;"&gt;
2372
+ &amp;pound;
2373
+ &amp;#163;
365
2374
  &lt;/div&gt;
366
2375
  &lt;/body&gt;
367
2376
  &lt;/html&gt;
368
2377
  </code></pre>
369
2378
 
370
- <pre class="d2l-code d2l-code-dark"><code class="language-sql line-numbers">DECLARE @MyCounter INT; /* keyword, variable, punctuation */
2379
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-matlab">for n = 1:5
2380
+ x = n*0.1;
2381
+ z = myfunc2(x,2,3,7);
2382
+ fprintf('x = %4.2f f(x) = %8.4f \r',x,z)
2383
+ end
2384
+ </code></pre>
371
2385
 
372
- SELECT AVG(Calories) AS AverageCalories FROM Desserts; /* keyword, function */
2386
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-python"># Program to check if a number is prime or not
373
2387
 
374
- SELECT * FROM Desserts /* keyword, operator */
2388
+ num = 29
375
2389
 
376
- SET ROWCOUNT 4; /* keyword, number */
2390
+ # To take input from the user
2391
+ #num = int(input("Enter a number: "))
377
2392
 
378
- SET @Hidden = FALSE; /* keyword, variable, boolean */
2393
+ # define a flag variable
2394
+ flag = False
379
2395
 
380
- SET @Donuts = 'Yummy'; /* keyword, variable, string */
2396
+ # prime numbers are greater than 1
2397
+ if num > 1:
2398
+ # check for factors
2399
+ for i in range(2, num):
2400
+ if (num % i) == 0:
2401
+ # if factor is found, set flag to True
2402
+ flag = True
2403
+ # break out of loop
2404
+ break
2405
+
2406
+ # check if flag is True
2407
+ if flag:
2408
+ print(num, "is not a prime number")
2409
+ else:
2410
+ print(num, "is a prime number")
381
2411
  </code></pre>
382
2412
 
383
- <pre class="d2l-code d2l-code-dark"><code class="language-json line-numbers">{ /* punctuation */
384
- "jinxed": "gnomes", /* property, operator, string */
385
- "grumpy": [ "wizards" ],
386
- "jelly": 99, /* property, operator, number */
387
- "donut": true, /* property, operator, boolean */
388
- "fritter": null /* property, operator, null, keyword */
2413
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-r"># decimal variable
2414
+ num = as.integer(readline(prompt = "Enter a number: "))
2415
+ # num = 15
2416
+ isPrime = 0
2417
+ if (num > 1) {
2418
+ isPrime = 1
2419
+ for (i in 2: (num - 1)) {
2420
+ if ((num %% i) == 0) {
2421
+ isPrime = 0
2422
+ break
2423
+ }
2424
+ }
2425
+ }
2426
+ if (num == 2) isPrime = 1
2427
+ if (isPrime == 1) {
2428
+ print(paste(num, "is a prime number"))
2429
+ } else {
2430
+ print(paste(num, "is not a prime number"))
389
2431
  }
390
2432
  </code></pre>
391
2433
 
2434
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-racket">(define (rgb-maker mk)
2435
+ (lambda (sz)
2436
+ (vc-append (colorize (mk sz) "red")
2437
+ (colorize (mk sz) "green")
2438
+ (colorize (mk sz) "blue"))))
2439
+ </code></pre>
2440
+
2441
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-regex">(\W|^)[\w.\-]{0,25}@(yahoo|hotmail|gmail)\.com(\W|$)
2442
+ (\W|^)po[#\-]{0,1}\s{0,1}\d{2}[\s-]{0,1}\d{4}(\W|$)
2443
+ ^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$
2444
+ \b(?:word1\W+(?:\w+\W+){1,6}?word2|word2\W+(?:\w+\W+){1,6}?word1)\b
2445
+ ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$
2446
+ </code></pre>
2447
+
2448
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-sql">DECLARE @MyCounter INT; /* keyword, variable, punctuation */
2449
+
2450
+ SELECT AVG(Calories) AS AverageCalories FROM Desserts;
2451
+
2452
+ SELECT * FROM Desserts
2453
+
2454
+ SET ROWCOUNT 4;
2455
+
2456
+ SET @Hidden = FALSE;
2457
+
2458
+ SET @Donuts = 'Yummy';
2459
+ </code></pre>
2460
+
2461
+ <pre class="d2l-code d2l-code-dark line-numbers"><code class="language-wolfram">CloudDeploy[
2462
+ FormFunction[FormObject[{"ImageURL" -> "String"}],
2463
+ ImageEffect[
2464
+ ColorConvert[
2465
+ ImageMultiply[
2466
+ ColorConvert[
2467
+ ImageAdd[ImageAdjust[Import[#ImageURL], .2],
2468
+ RGBColor[.25, .25, -.1]], "HSB"], Hue[1, .7, 1]],
2469
+ "RGB"], {"PoissonNoise", .5}] &amp;, "JPEG"],
2470
+ Permissions -> "Public"]
2471
+ </code></pre>
2472
+
392
2473
  <h2 class="d2l-heading-3">More Samples (Web Component Scope)</h2>
393
2474
 
394
2475
  <d2l-demo-prism dark></d2l-demo-prism>