@brightspace-ui/core 2.29.2 → 2.29.5
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.
- package/components/filter/README.md +19 -2
- package/components/tooltip/README.md +45 -6
- package/components/tooltip/tooltip-help.js +7 -1
- package/custom-elements.json +5 -0
- package/helpers/demo/prism.html +2128 -47
- package/helpers/prism.js +113 -68
- package/package.json +1 -1
package/helpers/demo/prism.html
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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">
|
|
328
|
+
<h2 class="d2l-heading-3">Large Samples</h2>
|
|
329
|
+
|
|
330
|
+
<pre class="d2l-code d2l-code-dark line-numbers"><code class="language-markup"><!DOCTYPE html>
|
|
331
|
+
<html lang="en">
|
|
332
|
+
<head>
|
|
333
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
334
|
+
<meta charset="UTF-8">
|
|
335
|
+
<link rel="stylesheet" href="../../demo/styles.css" type="text/css">
|
|
336
|
+
<script type="module">
|
|
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
|
+
</script>
|
|
350
|
+
<style>
|
|
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 > 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
|
+
</style>
|
|
382
|
+
</head>
|
|
383
|
+
<body unresolved>
|
|
384
|
+
|
|
385
|
+
<d2l-demo-page page-title="d2l-card">
|
|
386
|
+
|
|
387
|
+
<h2>Subtle Card (badges, no-link)</h2>
|
|
388
|
+
|
|
389
|
+
<d2l-demo-snippet>
|
|
390
|
+
<template>
|
|
391
|
+
<div class="subtle-demo">
|
|
392
|
+
|
|
393
|
+
<d2l-card subtle align-center text="Image Badge" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 280px; width: 245px;">
|
|
394
|
+
<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">
|
|
395
|
+
<div slot="badge" class="badge">
|
|
396
|
+
<img alt="" src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/94/Stick_Figure.svg/340px-Stick_Figure.svg.png">
|
|
397
|
+
</div>
|
|
398
|
+
<div slot="content">Image Badge</div>
|
|
399
|
+
</d2l-card>
|
|
400
|
+
|
|
401
|
+
<d2l-card subtle align-center text="Status Badge" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 280px; width: 245px;">
|
|
402
|
+
<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">
|
|
403
|
+
<div class="badge-status" slot="badge">
|
|
404
|
+
<d2l-status-indicator text="Success" state="success"></d2l-status-indicator>
|
|
405
|
+
</div>
|
|
406
|
+
<div slot="content">Status Badge</div>
|
|
407
|
+
</d2l-card>
|
|
408
|
+
|
|
409
|
+
<d2l-card subtle align-center text="No Link" style="height: 280px; width: 245px;">
|
|
410
|
+
<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">
|
|
411
|
+
<div slot="content">No Link</div>
|
|
412
|
+
</d2l-card>
|
|
413
|
+
|
|
414
|
+
</div>
|
|
415
|
+
</template>
|
|
416
|
+
</d2l-demo-snippet>
|
|
417
|
+
|
|
418
|
+
<h2>Subtle Card (header actions, meta-content, footer links)</h2>
|
|
419
|
+
|
|
420
|
+
<d2l-demo-snippet>
|
|
421
|
+
<template>
|
|
422
|
+
<div class="subtle-demo">
|
|
423
|
+
|
|
424
|
+
<d2l-card subtle align-center text="Hydrology" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 300px; width: 245px;">
|
|
425
|
+
<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">
|
|
426
|
+
<d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!">
|
|
427
|
+
<d2l-dropdown-content>
|
|
428
|
+
<div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div>
|
|
429
|
+
<div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div>
|
|
430
|
+
<div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div>
|
|
431
|
+
</d2l-dropdown-content>
|
|
432
|
+
</d2l-dropdown-more>
|
|
433
|
+
<d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"></d2l-button-icon>
|
|
434
|
+
<div slot="content"><div>Hydrology</div><d2l-card-content-meta>This is some extra meta data that will fill the content slot of the card.</d2l-card-content-meta></div>
|
|
435
|
+
<div slot="footer">
|
|
436
|
+
<d2l-card-footer-link id="googleDriveLink1" icon="tier1:google-drive" text="Google Drive" secondary-count="100" href="https://www.google.ca/drive/">
|
|
437
|
+
<d2l-tooltip slot="tooltip" for="googleDriveLink1">Go to Google Drive</d2l-tooltip>
|
|
438
|
+
</d2l-card-footer-link>
|
|
439
|
+
<d2l-card-footer-link id="rssFeedLink1" icon="tier1:rss" text="RSS Feed" secondary-count="1">
|
|
440
|
+
<d2l-tooltip slot="tooltip" for="rssFeedLink1">RSS Feed</d2l-tooltip>
|
|
441
|
+
</d2l-card-footer-link>
|
|
442
|
+
<d2l-card-footer-link id="outcomesLink1" icon="tier1:outcomes" text="Outcomes" secondary-count="5">
|
|
443
|
+
<d2l-tooltip slot="tooltip" for="outcomesLink1">Outcomes</d2l-tooltip>
|
|
444
|
+
</d2l-card-footer-link>
|
|
445
|
+
<d2l-card-footer-link id="assignmentsLink1" icon="tier1:assignments" text="Assignments" secondary-count="3">
|
|
446
|
+
<d2l-tooltip slot="tooltip" position="top" style="width: 100%;" for="assignmentsLink1">You have 3 assignments due tomorrow.</d2l-tooltip>
|
|
447
|
+
</d2l-card-footer-link>
|
|
448
|
+
</div>
|
|
449
|
+
</d2l-card>
|
|
450
|
+
|
|
451
|
+
<d2l-card subtle align-center text="Grade 2" href="https://en.wikipedia.org/wiki/Second_grade" style="height: 300px; width: 245px;">
|
|
452
|
+
<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">
|
|
453
|
+
<d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!">
|
|
454
|
+
<d2l-dropdown-content><div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div></d2l-dropdown-content>
|
|
455
|
+
</d2l-dropdown-more>
|
|
456
|
+
<d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"></d2l-button-icon>
|
|
457
|
+
<div slot="content">Grade 2</div>
|
|
458
|
+
<div slot="footer">
|
|
459
|
+
<d2l-card-footer-link id="googleDriveLink2" icon="tier1:google-drive" text="Google Drive" secondary-count="100" href="https://www.google.ca/drive/">
|
|
460
|
+
<d2l-tooltip slot="tooltip" for="googleDriveLink2">Go to Google Drive</d2l-tooltip>
|
|
461
|
+
</d2l-card-footer-link>
|
|
462
|
+
<d2l-card-footer-link id="rssFeedLink2" icon="tier1:rss" text="RSS Feed" secondary-count="1">
|
|
463
|
+
<d2l-tooltip slot="tooltip" for="rssFeedLink2">RSS Feed</d2l-tooltip>
|
|
464
|
+
</d2l-card-footer-link>
|
|
465
|
+
<d2l-card-footer-link id="outcomesLink2" icon="tier1:outcomes" text="Outcomes" secondary-count="5">
|
|
466
|
+
<d2l-tooltip slot="tooltip" for="outcomesLink2">Outcomes</d2l-tooltip>
|
|
467
|
+
</d2l-card-footer-link>
|
|
468
|
+
</div>
|
|
469
|
+
</d2l-card>
|
|
470
|
+
|
|
471
|
+
<d2l-card subtle align-center text="Painting" href="https://en.wikipedia.org/wiki/Painting" style="height: 300px; width: 245px;">
|
|
472
|
+
<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">
|
|
473
|
+
<d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!">
|
|
474
|
+
<d2l-dropdown-content><div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div></d2l-dropdown-content>
|
|
475
|
+
</d2l-dropdown-more>
|
|
476
|
+
<d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"></d2l-button-icon>
|
|
477
|
+
<div slot="content">Painting</div>
|
|
478
|
+
<d2l-button slot="footer" style="width: 100%;">Shiny Button</d2l-button>
|
|
479
|
+
</d2l-card>
|
|
480
|
+
|
|
481
|
+
</div>
|
|
482
|
+
</template>
|
|
483
|
+
</d2l-demo-snippet>
|
|
484
|
+
|
|
485
|
+
<h2>Card (badges, no-link)</h2>
|
|
486
|
+
|
|
487
|
+
<d2l-demo-snippet>
|
|
488
|
+
<template>
|
|
489
|
+
|
|
490
|
+
<d2l-card align-center text="Image Badge" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 280px; width: 245px;">
|
|
491
|
+
<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">
|
|
492
|
+
<div slot="badge" class="badge">
|
|
493
|
+
<img alt="" src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/94/Stick_Figure.svg/340px-Stick_Figure.svg.png">
|
|
494
|
+
</div>
|
|
495
|
+
<div slot="content">Image Badge</div>
|
|
496
|
+
</d2l-card>
|
|
497
|
+
|
|
498
|
+
<d2l-card align-center text="Status Badge" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 280px; width: 245px;">
|
|
499
|
+
<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">
|
|
500
|
+
<div class="badge-status" slot="badge">
|
|
501
|
+
<d2l-status-indicator text="Success" state="success"></d2l-status-indicator>
|
|
502
|
+
</div>
|
|
503
|
+
<div slot="content">Status Badge</div>
|
|
504
|
+
</d2l-card>
|
|
505
|
+
|
|
506
|
+
<d2l-card align-center text="No Link" style="height: 280px; width: 245px;">
|
|
507
|
+
<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">
|
|
508
|
+
<div slot="content">No Link</div>
|
|
509
|
+
</d2l-card>
|
|
510
|
+
|
|
511
|
+
</template>
|
|
512
|
+
</d2l-demo-snippet>
|
|
513
|
+
|
|
514
|
+
<h2>Card (header actions, meta-content, footer links)</h2>
|
|
515
|
+
|
|
516
|
+
<d2l-demo-snippet>
|
|
517
|
+
<template>
|
|
518
|
+
|
|
519
|
+
<d2l-card align-center text="Hydrology" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 300px; width: 245px;">
|
|
520
|
+
<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">
|
|
521
|
+
<d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!">
|
|
522
|
+
<d2l-dropdown-content>
|
|
523
|
+
<div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div>
|
|
524
|
+
<div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div>
|
|
525
|
+
<div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div>
|
|
526
|
+
</d2l-dropdown-content>
|
|
527
|
+
</d2l-dropdown-more>
|
|
528
|
+
<d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"></d2l-button-icon>
|
|
529
|
+
<div slot="content"><div>Hydrology</div><d2l-card-content-meta>This is some extra meta data that will fill the content slot of the card.</d2l-card-content-meta></div>
|
|
530
|
+
<div slot="footer">
|
|
531
|
+
<d2l-card-footer-link id="googleDriveLink3" icon="tier1:google-drive" text="Google Drive" secondary-count="100" href="https://www.google.ca/drive/">
|
|
532
|
+
<d2l-tooltip slot="tooltip" for="googleDriveLink3">Go to Google Drive</d2l-tooltip>
|
|
533
|
+
</d2l-card-footer-link>
|
|
534
|
+
<d2l-card-footer-link id="rssFeedLink3" icon="tier1:rss" text="RSS Feed" secondary-count="1">
|
|
535
|
+
<d2l-tooltip slot="tooltip" for="rssFeedLink3">RSS Feed</d2l-tooltip>
|
|
536
|
+
</d2l-card-footer-link>
|
|
537
|
+
<d2l-card-footer-link id="outcomesLink3" icon="tier1:outcomes" text="Outcomes" secondary-count="5">
|
|
538
|
+
<d2l-tooltip slot="tooltip" for="outcomesLink3">Outcomes</d2l-tooltip>
|
|
539
|
+
</d2l-card-footer-link>
|
|
540
|
+
<d2l-card-footer-link id="assignmentsLink3" icon="tier1:assignments" text="Assignments" secondary-count="3">
|
|
541
|
+
<d2l-tooltip slot="tooltip" position="top" style="width: 100%;" for="assignmentsLink3">You have 3 assignments due tomorrow.</d2l-tooltip>
|
|
542
|
+
</d2l-card-footer-link>
|
|
543
|
+
</div>
|
|
544
|
+
</d2l-card>
|
|
545
|
+
|
|
546
|
+
<d2l-card align-center text="Painting" href="https://en.wikipedia.org/wiki/Painting" style="height: 300px; width: 245px;">
|
|
547
|
+
<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">
|
|
548
|
+
<d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!">
|
|
549
|
+
<d2l-dropdown-content><div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div></d2l-dropdown-content>
|
|
550
|
+
</d2l-dropdown-more>
|
|
551
|
+
<d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"></d2l-button-icon>
|
|
552
|
+
<div slot="content">Painting</div>
|
|
553
|
+
<d2l-button slot="footer" style="width: 100%;">Shiny Button</d2l-button>
|
|
554
|
+
</d2l-card>
|
|
555
|
+
|
|
556
|
+
<d2l-card align-center text="Grade 2" href="https://en.wikipedia.org/wiki/Second_grade" style="height: 300px; width: 245px;">
|
|
557
|
+
<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">
|
|
558
|
+
<d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!">
|
|
559
|
+
<d2l-dropdown-content><div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div></d2l-dropdown-content>
|
|
560
|
+
</d2l-dropdown-more>
|
|
561
|
+
<d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"></d2l-button-icon>
|
|
562
|
+
<div slot="content">Grade 2</div>
|
|
563
|
+
<div slot="footer">
|
|
564
|
+
<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/">
|
|
565
|
+
<d2l-tooltip slot="tooltip" for="googleDriveLink4">Go to Google Drive</d2l-tooltip>
|
|
566
|
+
</d2l-card-footer-link>
|
|
567
|
+
<d2l-card-footer-link id="rssFeedLink4" icon="tier1:rss" text="RSS Feed" secondary-count-type="count" secondary-count="1">
|
|
568
|
+
<d2l-tooltip slot="tooltip" for="rssFeedLink4">RSS Feed</d2l-tooltip>
|
|
569
|
+
</d2l-card-footer-link>
|
|
570
|
+
<d2l-card-footer-link id="outcomesLink4" icon="tier1:outcomes" text="Outcomes" secondary-count-type="count" secondary-count="5">
|
|
571
|
+
<d2l-tooltip slot="tooltip" for="outcomesLink4">Outcomes</d2l-tooltip>
|
|
572
|
+
</d2l-card-footer-link>
|
|
573
|
+
</div>
|
|
574
|
+
</d2l-card>
|
|
575
|
+
|
|
576
|
+
</template>
|
|
577
|
+
</d2l-demo-snippet>
|
|
578
|
+
|
|
579
|
+
<h2>Card (with header loading)</h2>
|
|
580
|
+
|
|
581
|
+
<d2l-demo-snippet>
|
|
582
|
+
<template>
|
|
583
|
+
|
|
584
|
+
<d2l-card align-center text="Hydrology" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 300px; width: 245px;">
|
|
585
|
+
<d2l-card-loading-shimmer slot="header" loading style="display: block; height: 103.5px; width: 100%;">
|
|
586
|
+
<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">
|
|
587
|
+
</d2l-card-loading-shimmer>
|
|
588
|
+
<div slot="content"><div>Hydrology</div><d2l-card-content-meta>This is some extra meta data that will fill the content slot of the card.</d2l-card-content-meta></div>
|
|
589
|
+
</d2l-card>
|
|
590
|
+
|
|
591
|
+
<div>
|
|
592
|
+
<d2l-button id="toggleLoading">Toggle Loading State</d2l-button>
|
|
593
|
+
</div>
|
|
594
|
+
|
|
595
|
+
<script>
|
|
596
|
+
document.querySelector('#toggleLoading').addEventListener('click', () => {
|
|
597
|
+
const loadingContainer = document.querySelector('d2l-card-loading-shimmer');
|
|
598
|
+
loadingContainer.loading = !loadingContainer.loading;
|
|
599
|
+
});
|
|
600
|
+
</script>
|
|
601
|
+
</template>
|
|
602
|
+
</d2l-demo-snippet>
|
|
603
|
+
|
|
604
|
+
</d2l-demo-page>
|
|
605
|
+
</body>
|
|
606
|
+
</html>
|
|
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 => 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) => {
|
|
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 = () => {
|
|
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 > 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 < 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(() => {
|
|
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) => {
|
|
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(() => {
|
|
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() => {
|
|
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(() => focusable.focus());
|
|
1167
|
+
} else {
|
|
1168
|
+
content.setAttribute('tabindex', '-1');
|
|
1169
|
+
content.focus();
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
setTimeout(() =>
|
|
1174
|
+
this.dispatchEvent(new CustomEvent('d2l-dropdown-open', { bubbles: true, composed: true })), 0
|
|
1175
|
+
);
|
|
1176
|
+
|
|
1177
|
+
this.__dismissibleId = setDismissible(() => {
|
|
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() => {
|
|
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 > 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 > this.maxHeight
|
|
1304
|
+
&& headerFooterHeight < this.maxHeight
|
|
1305
|
+
? this.maxHeight - headerFooterHeight - 2
|
|
1306
|
+
: availableHeight - headerFooterHeight;
|
|
1307
|
+
this.__toggleOverflowY(contentRect.height + headerFooterHeight > 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 > 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 > 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) >= 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 >= 0 ? Math.min(spaceAround.above, this.boundary.above) : spaceAround.above;
|
|
1346
|
+
constrained.below = this.boundary.below >= 0 ? Math.min(spaceAround.below, this.boundary.below) : spaceAround.below;
|
|
1347
|
+
constrained.left = this.boundary.left >= 0 ? Math.min(spaceAround.left, this.boundary.left) : spaceAround.left;
|
|
1348
|
+
constrained.right = this.boundary.right >= 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 > (maxWidthOverride - 20)) widthOverride = maxWidthOverride - 20;
|
|
1492
|
+
if (widthOverride && minWidthOverride && widthOverride < (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 < 0 ? -this._ifrauContextInfo.top : 0}px`;
|
|
1507
|
+
} else if (window.innerHeight > 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
|
-
|
|
318
|
-
|
|
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
|
-
|
|
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 >= spaceRequired.height) {
|
|
1575
|
+
return false;
|
|
1576
|
+
}
|
|
1577
|
+
if (spaceAround.above >= 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 > spaceAround.below;
|
|
1585
|
+
}
|
|
1586
|
+
if (spaceAroundScroll.below >= spaceRequired.height) {
|
|
1587
|
+
return false;
|
|
1588
|
+
}
|
|
1589
|
+
if (spaceAroundScroll.above >= 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 <= 0) {
|
|
1601
|
+
return contentXAdjustment * -1;
|
|
1602
|
+
}
|
|
1603
|
+
if (spaceAround.left > contentXAdjustment && spaceAround.right > contentXAdjustment) {
|
|
1604
|
+
// center with target
|
|
1605
|
+
return contentXAdjustment * -1;
|
|
1606
|
+
}
|
|
1607
|
+
const isRTL = this.getAttribute('dir') === 'rtl';
|
|
1608
|
+
if (!isRTL) {
|
|
1609
|
+
if (spaceAround.left < contentXAdjustment) {
|
|
1610
|
+
// slide content right (not enough space to center)
|
|
1611
|
+
return spaceAround.left * -1;
|
|
1612
|
+
} else if (spaceAround.right < contentXAdjustment) {
|
|
1613
|
+
// slide content left (not enough space to center)
|
|
1614
|
+
return (centerDelta * -1) + spaceAround.right;
|
|
1615
|
+
}
|
|
1616
|
+
} else {
|
|
1617
|
+
if (spaceAround.left < contentXAdjustment) {
|
|
1618
|
+
// slide content right (not enough space to center)
|
|
1619
|
+
return (centerDelta * -1) + spaceAround.left;
|
|
1620
|
+
} else if (spaceAround.right < 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(() => 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
|
+
<div
|
|
1715
|
+
id="d2l-dropdown-wrapper"
|
|
1716
|
+
class="d2l-dropdown-content-width"
|
|
1717
|
+
style=${styleMap(widthStyle)}
|
|
1718
|
+
?data-closing="${this._closing}">
|
|
1719
|
+
<div class=${classMap(topClasses)} style=${styleMap(headerStyle)}>
|
|
1720
|
+
<slot name="header" @slotchange="${this.__handleHeaderSlotChange}"></slot>
|
|
1721
|
+
</div>
|
|
1722
|
+
<div
|
|
1723
|
+
class="d2l-dropdown-content-container"
|
|
1724
|
+
style=${styleMap(contentStyle)}
|
|
1725
|
+
@scroll=${this.__toggleScrollStyles}>
|
|
1726
|
+
<slot class="d2l-dropdown-content-slot"></slot>
|
|
1727
|
+
</div>
|
|
1728
|
+
<div class=${classMap(bottomClasses)} style=${styleMap(footerStyle)}>
|
|
1729
|
+
<slot name="footer" @slotchange="${this.__handleFooterSlotChange}"></slot>
|
|
1730
|
+
<d2l-button
|
|
1731
|
+
class="dropdown-close-btn"
|
|
1732
|
+
style=${styleMap(closeButtonStyles)}
|
|
1733
|
+
@click=${this.close}>
|
|
1734
|
+
${this.localize('components.dropdown.close')}
|
|
1735
|
+
</d2l-button>
|
|
1736
|
+
</div>
|
|
1737
|
+
</div>
|
|
1738
|
+
`;
|
|
1739
|
+
|
|
1740
|
+
if (this.trapFocus) {
|
|
1741
|
+
dropdownContentSlots = html`
|
|
1742
|
+
<d2l-focus-trap
|
|
1743
|
+
@d2l-focus-trap-enter="${this._handleFocusTrapEnter}"
|
|
1744
|
+
?trap="${this.opened}">
|
|
1745
|
+
${dropdownContentSlots}
|
|
1746
|
+
</d2l-focus-trap>`;
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
const dropdown = html`
|
|
1750
|
+
<div class="d2l-dropdown-content-position" style=${styleMap(positionStyle)}>
|
|
1751
|
+
${dropdownContentSlots}
|
|
1752
|
+
</div>
|
|
1753
|
+
`;
|
|
1754
|
+
|
|
1755
|
+
return (this.mobileTray) ? html`
|
|
1756
|
+
${dropdown}
|
|
1757
|
+
<d2l-backdrop
|
|
1758
|
+
for-target="d2l-dropdown-wrapper"
|
|
1759
|
+
?shown="${this._showBackdrop}" >
|
|
1760
|
+
</d2l-backdrop>`
|
|
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
|
+
<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}">
|
|
2058
|
+
<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)}">
|
|
2068
|
+
<span class="d2l-card-link-text d2l-offscreen">${this.text}</span>
|
|
2069
|
+
</a>
|
|
2070
|
+
<div class="${classMap(linkContainerClass)}">
|
|
2071
|
+
<div class="d2l-card-header"><slot name="header"></slot></div>
|
|
2072
|
+
<div class="d2l-card-badge" style="${styleMap(badgeStyle)}"><slot name="badge"></slot></div>
|
|
2073
|
+
<div class="d2l-card-content"><slot name="content"></slot></div>
|
|
2074
|
+
</div>
|
|
2075
|
+
<div class="d2l-card-actions"><slot name="actions"></slot></div>
|
|
2076
|
+
<div class="${classMap(footerClass)}"><slot name="footer"></slot></div>
|
|
2077
|
+
</div>
|
|
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 < 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2177
|
+
<pre class="d2l-code d2l-code-dark line-numbers"><code class="language-c">#include <stdio.h>
|
|
2178
|
+
int main() {
|
|
2179
|
+
char c;
|
|
2180
|
+
printf("Enter a character: ");
|
|
2181
|
+
scanf("%c", &c);
|
|
335
2182
|
|
|
336
|
-
|
|
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
|
-
|
|
2187
|
+
return 0;
|
|
2188
|
+
}
|
|
339
2189
|
</code></pre>
|
|
340
2190
|
|
|
341
|
-
<pre class="d2l-code"><code class="language-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
2191
|
+
<pre class="d2l-code d2l-code-dark line-numbers"><code class="language-cpp">#include <iostream>
|
|
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
|
-
|
|
347
|
-
|
|
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');
|
|
2248
|
+
src: local('Lato Regular');
|
|
350
2249
|
}
|
|
351
|
-
@media (prefers-reduced-motion: reduce) {
|
|
2250
|
+
@media (prefers-reduced-motion: reduce) {
|
|
352
2251
|
:host([opened]), :host([opened-above]) {
|
|
353
|
-
animation: none !important;
|
|
2252
|
+
animation: none !important;
|
|
354
2253
|
}
|
|
355
2254
|
}
|
|
356
2255
|
</code></pre>
|
|
357
2256
|
|
|
358
|
-
<pre class="d2l-code"><code class="language-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
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 <- openFile "file.txt" ReadMode
|
|
2262
|
+
contents <- 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) >>= 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"><!DOCTYPE html> <!-- doctype, doctype-tag, name -->
|
|
2368
|
+
<html>
|
|
2369
|
+
<body class="typography">
|
|
2370
|
+
<![CDATA[ some cdata section ]]>
|
|
2371
|
+
<div style="color: blue;">
|
|
2372
|
+
&pound;
|
|
2373
|
+
&#163;
|
|
365
2374
|
</div>
|
|
366
2375
|
</body>
|
|
367
2376
|
</html>
|
|
368
2377
|
</code></pre>
|
|
369
2378
|
|
|
370
|
-
<pre class="d2l-code d2l-code-dark"><code class="language-
|
|
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
|
-
|
|
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
|
-
|
|
2388
|
+
num = 29
|
|
375
2389
|
|
|
376
|
-
|
|
2390
|
+
# To take input from the user
|
|
2391
|
+
#num = int(input("Enter a number: "))
|
|
377
2392
|
|
|
378
|
-
|
|
2393
|
+
# define a flag variable
|
|
2394
|
+
flag = False
|
|
379
2395
|
|
|
380
|
-
|
|
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-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
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}] &, "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>
|