jekyll-theme-apcsp 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/_includes/alert.md +0 -0
  4. data/_includes/footer.md +0 -0
  5. data/_includes/head.html +0 -0
  6. data/_includes/header.md +1 -0
  7. data/_includes/nav.md +0 -0
  8. data/_layouts/page.html +308 -0
  9. data/_layouts/redirect.html +12 -0
  10. data/_sass/bootstrap/LICENSE +22 -0
  11. data/_sass/bootstrap/scss/_accordion.scss +146 -0
  12. data/_sass/bootstrap/scss/_alert.scss +71 -0
  13. data/_sass/bootstrap/scss/_badge.scss +40 -0
  14. data/_sass/bootstrap/scss/_breadcrumb.scss +42 -0
  15. data/_sass/bootstrap/scss/_button-group.scss +142 -0
  16. data/_sass/bootstrap/scss/_buttons.scss +158 -0
  17. data/_sass/bootstrap/scss/_card.scss +234 -0
  18. data/_sass/bootstrap/scss/_carousel.scss +229 -0
  19. data/_sass/bootstrap/scss/_close.scss +40 -0
  20. data/_sass/bootstrap/scss/_code.scss +48 -0
  21. data/_sass/bootstrap/scss/_containers.scss +41 -0
  22. data/_sass/bootstrap/scss/_custom-forms.scss +526 -0
  23. data/_sass/bootstrap/scss/_dropdown.scss +248 -0
  24. data/_sass/bootstrap/scss/_forms.scss +9 -0
  25. data/_sass/bootstrap/scss/_functions.scss +302 -0
  26. data/_sass/bootstrap/scss/_grid.scss +33 -0
  27. data/_sass/bootstrap/scss/_helpers.scss +10 -0
  28. data/_sass/bootstrap/scss/_images.scss +42 -0
  29. data/_sass/bootstrap/scss/_input-group.scss +208 -0
  30. data/_sass/bootstrap/scss/_jumbotron.scss +17 -0
  31. data/_sass/bootstrap/scss/_list-group.scss +191 -0
  32. data/_sass/bootstrap/scss/_maps.scss +54 -0
  33. data/_sass/bootstrap/scss/_media.scss +8 -0
  34. data/_sass/bootstrap/scss/_mixins.scss +43 -0
  35. data/_sass/bootstrap/scss/_modal.scss +237 -0
  36. data/_sass/bootstrap/scss/_nav.scss +172 -0
  37. data/_sass/bootstrap/scss/_navbar.scss +274 -0
  38. data/_sass/bootstrap/scss/_offcanvas.scss +143 -0
  39. data/_sass/bootstrap/scss/_pagination.scss +111 -0
  40. data/_sass/bootstrap/scss/_placeholders.scss +51 -0
  41. data/_sass/bootstrap/scss/_popover.scss +198 -0
  42. data/_sass/bootstrap/scss/_print.scss +141 -0
  43. data/_sass/bootstrap/scss/_progress.scss +59 -0
  44. data/_sass/bootstrap/scss/_reboot.scss +610 -0
  45. data/_sass/bootstrap/scss/_root.scss +76 -0
  46. data/_sass/bootstrap/scss/_spinners.scss +85 -0
  47. data/_sass/bootstrap/scss/_tables.scss +164 -0
  48. data/_sass/bootstrap/scss/_toasts.scss +70 -0
  49. data/_sass/bootstrap/scss/_tooltip.scss +122 -0
  50. data/_sass/bootstrap/scss/_transitions.scss +27 -0
  51. data/_sass/bootstrap/scss/_type.scss +104 -0
  52. data/_sass/bootstrap/scss/_utilities.scss +647 -0
  53. data/_sass/bootstrap/scss/_variables.scss +1631 -0
  54. data/_sass/bootstrap/scss/bootstrap-grid.scss +68 -0
  55. data/_sass/bootstrap/scss/bootstrap-reboot.scss +14 -0
  56. data/_sass/bootstrap/scss/bootstrap-utilities.scss +19 -0
  57. data/_sass/bootstrap/scss/bootstrap.scss +54 -0
  58. data/_sass/bootstrap/scss/forms/_floating-labels.scss +70 -0
  59. data/_sass/bootstrap/scss/forms/_form-check.scss +175 -0
  60. data/_sass/bootstrap/scss/forms/_form-control.scss +189 -0
  61. data/_sass/bootstrap/scss/forms/_form-range.scss +91 -0
  62. data/_sass/bootstrap/scss/forms/_form-select.scss +71 -0
  63. data/_sass/bootstrap/scss/forms/_form-text.scss +11 -0
  64. data/_sass/bootstrap/scss/forms/_input-group.scss +121 -0
  65. data/_sass/bootstrap/scss/forms/_labels.scss +36 -0
  66. data/_sass/bootstrap/scss/forms/_validation.scss +12 -0
  67. data/_sass/bootstrap/scss/helpers/_clearfix.scss +3 -0
  68. data/_sass/bootstrap/scss/helpers/_color-bg.scss +10 -0
  69. data/_sass/bootstrap/scss/helpers/_colored-links.scss +12 -0
  70. data/_sass/bootstrap/scss/helpers/_position.scss +36 -0
  71. data/_sass/bootstrap/scss/helpers/_ratio.scss +26 -0
  72. data/_sass/bootstrap/scss/helpers/_stacks.scss +15 -0
  73. data/_sass/bootstrap/scss/helpers/_stretched-link.scss +15 -0
  74. data/_sass/bootstrap/scss/helpers/_text-truncation.scss +7 -0
  75. data/_sass/bootstrap/scss/helpers/_visually-hidden.scss +8 -0
  76. data/_sass/bootstrap/scss/helpers/_vr.scss +8 -0
  77. data/_sass/bootstrap/scss/mixins/_alert.scss +15 -0
  78. data/_sass/bootstrap/scss/mixins/_backdrop.scss +14 -0
  79. data/_sass/bootstrap/scss/mixins/_background-variant.scss +23 -0
  80. data/_sass/bootstrap/scss/mixins/_badge.scss +17 -0
  81. data/_sass/bootstrap/scss/mixins/_border-radius.scss +78 -0
  82. data/_sass/bootstrap/scss/mixins/_box-shadow.scss +18 -0
  83. data/_sass/bootstrap/scss/mixins/_breakpoints.scss +127 -0
  84. data/_sass/bootstrap/scss/mixins/_buttons.scss +71 -0
  85. data/_sass/bootstrap/scss/mixins/_caret.scss +64 -0
  86. data/_sass/bootstrap/scss/mixins/_clearfix.scss +9 -0
  87. data/_sass/bootstrap/scss/mixins/_color-scheme.scss +7 -0
  88. data/_sass/bootstrap/scss/mixins/_container.scss +11 -0
  89. data/_sass/bootstrap/scss/mixins/_deprecate.scss +10 -0
  90. data/_sass/bootstrap/scss/mixins/_float.scss +14 -0
  91. data/_sass/bootstrap/scss/mixins/_forms.scss +152 -0
  92. data/_sass/bootstrap/scss/mixins/_gradients.scss +47 -0
  93. data/_sass/bootstrap/scss/mixins/_grid-framework.scss +80 -0
  94. data/_sass/bootstrap/scss/mixins/_grid.scss +151 -0
  95. data/_sass/bootstrap/scss/mixins/_hover.scss +37 -0
  96. data/_sass/bootstrap/scss/mixins/_image.scss +16 -0
  97. data/_sass/bootstrap/scss/mixins/_list-group.scss +24 -0
  98. data/_sass/bootstrap/scss/mixins/_lists.scss +7 -0
  99. data/_sass/bootstrap/scss/mixins/_nav-divider.scss +11 -0
  100. data/_sass/bootstrap/scss/mixins/_pagination.scss +10 -0
  101. data/_sass/bootstrap/scss/mixins/_reset-text.scss +17 -0
  102. data/_sass/bootstrap/scss/mixins/_resize.scss +6 -0
  103. data/_sass/bootstrap/scss/mixins/_screen-reader.scss +34 -0
  104. data/_sass/bootstrap/scss/mixins/_size.scss +7 -0
  105. data/_sass/bootstrap/scss/mixins/_table-row.scss +39 -0
  106. data/_sass/bootstrap/scss/mixins/_table-variants.scss +24 -0
  107. data/_sass/bootstrap/scss/mixins/_text-emphasis.scss +17 -0
  108. data/_sass/bootstrap/scss/mixins/_text-hide.scss +11 -0
  109. data/_sass/bootstrap/scss/mixins/_text-truncate.scss +8 -0
  110. data/_sass/bootstrap/scss/mixins/_transition.scss +26 -0
  111. data/_sass/bootstrap/scss/mixins/_utilities.scss +92 -0
  112. data/_sass/bootstrap/scss/mixins/_visibility.scss +8 -0
  113. data/_sass/bootstrap/scss/mixins/_visually-hidden.scss +29 -0
  114. data/_sass/bootstrap/scss/utilities/_align.scss +8 -0
  115. data/_sass/bootstrap/scss/utilities/_api.scss +47 -0
  116. data/_sass/bootstrap/scss/utilities/_background.scss +19 -0
  117. data/_sass/bootstrap/scss/utilities/_borders.scss +75 -0
  118. data/_sass/bootstrap/scss/utilities/_clearfix.scss +3 -0
  119. data/_sass/bootstrap/scss/utilities/_display.scss +26 -0
  120. data/_sass/bootstrap/scss/utilities/_embed.scss +39 -0
  121. data/_sass/bootstrap/scss/utilities/_flex.scss +51 -0
  122. data/_sass/bootstrap/scss/utilities/_float.scss +11 -0
  123. data/_sass/bootstrap/scss/utilities/_interactions.scss +5 -0
  124. data/_sass/bootstrap/scss/utilities/_overflow.scss +5 -0
  125. data/_sass/bootstrap/scss/utilities/_position.scss +32 -0
  126. data/_sass/bootstrap/scss/utilities/_screenreaders.scss +11 -0
  127. data/_sass/bootstrap/scss/utilities/_shadows.scss +6 -0
  128. data/_sass/bootstrap/scss/utilities/_sizing.scss +20 -0
  129. data/_sass/bootstrap/scss/utilities/_spacing.scss +73 -0
  130. data/_sass/bootstrap/scss/utilities/_stretched-link.scss +19 -0
  131. data/_sass/bootstrap/scss/utilities/_text.scss +72 -0
  132. data/_sass/bootstrap/scss/utilities/_visibility.scss +13 -0
  133. data/_sass/bootstrap/scss/vendor/_rfs.scss +354 -0
  134. data/_sass/jekyll-theme-cs50.scss +298 -0
  135. data/_sass/page.scss +228 -0
  136. data/_sass/rouge.scss +35 -0
  137. data/assets/@fortawesome/fontawesome-free/css/all.min.css +5 -0
  138. data/assets/@fortawesome/fontawesome-free/webfonts/fa-brands-400.eot +0 -0
  139. data/assets/@fortawesome/fontawesome-free/webfonts/fa-brands-400.svg +3717 -0
  140. data/assets/@fortawesome/fontawesome-free/webfonts/fa-brands-400.ttf +0 -0
  141. data/assets/@fortawesome/fontawesome-free/webfonts/fa-brands-400.woff +0 -0
  142. data/assets/@fortawesome/fontawesome-free/webfonts/fa-brands-400.woff2 +0 -0
  143. data/assets/@fortawesome/fontawesome-free/webfonts/fa-regular-400.eot +0 -0
  144. data/assets/@fortawesome/fontawesome-free/webfonts/fa-regular-400.svg +801 -0
  145. data/assets/@fortawesome/fontawesome-free/webfonts/fa-regular-400.ttf +0 -0
  146. data/assets/@fortawesome/fontawesome-free/webfonts/fa-regular-400.woff +0 -0
  147. data/assets/@fortawesome/fontawesome-free/webfonts/fa-regular-400.woff2 +0 -0
  148. data/assets/@fortawesome/fontawesome-free/webfonts/fa-solid-900.eot +0 -0
  149. data/assets/@fortawesome/fontawesome-free/webfonts/fa-solid-900.svg +5034 -0
  150. data/assets/@fortawesome/fontawesome-free/webfonts/fa-solid-900.ttf +0 -0
  151. data/assets/@fortawesome/fontawesome-free/webfonts/fa-solid-900.woff +0 -0
  152. data/assets/@fortawesome/fontawesome-free/webfonts/fa-solid-900.woff2 +0 -0
  153. data/assets/algolia-min.css +1 -0
  154. data/assets/algoliasearch/dist/algoliasearch-lite.umd.js +2 -0
  155. data/assets/algoliasearchLite.min.js +3 -0
  156. data/assets/bootstrap/LICENSE +22 -0
  157. data/assets/bootstrap/dist/js/bootstrap.bundle.min.js +7 -0
  158. data/assets/bootstrap/dist/js/bootstrap.bundle.min.js.map +1 -0
  159. data/assets/bootstrap/dist/js/bootstrap.min.js +7 -0
  160. data/assets/bootstrap-table/LICENSE +21 -0
  161. data/assets/bootstrap-table/dist/bootstrap-table.min.css +10 -0
  162. data/assets/bootstrap-table/dist/bootstrap-table.min.js +10 -0
  163. data/assets/bootstrap-table/dist/extensions/mobile/bootstrap-table-mobile.min.js +10 -0
  164. data/assets/instantsearch.js/LICENSE +21 -0
  165. data/assets/instantsearch.js/dist/instantsearch.production.min.js +3 -0
  166. data/assets/instantsearch.js/dist/instantsearch.production.min.js.map +1 -0
  167. data/assets/instantsearch.production.min.js +3 -0
  168. data/assets/jekyll-theme-cs50.js +620 -0
  169. data/assets/jquery/LICENSE.txt +20 -0
  170. data/assets/jquery/dist/jquery.min.js +2 -0
  171. data/assets/luxon.min.js +1 -0
  172. data/assets/moment-timezone-with-data.min.js +1 -0
  173. data/assets/moment.min.js +1 -0
  174. data/assets/page.js +4 -0
  175. data/assets/page.scss +4 -0
  176. data/assets/popper.js/dist/umd/popper.min.js +5 -0
  177. data/assets/reset-min.css +1 -0
  178. data/assets/scratchblocks.min.js +11 -0
  179. data/assets/scratchblocks.min.js.map +1 -0
  180. data/lib/jekyll-theme-cs50/constants.rb +59 -0
  181. data/lib/jekyll-theme-cs50.rb +606 -0
  182. data/lib/liquid-tag-parser.rb +1 -0
  183. metadata +350 -0
@@ -0,0 +1,620 @@
1
+ // Infer baseurl from this file's (known) path
2
+ const a = document.createElement('a');
3
+ a.href = document.currentScript.src;
4
+ const matches = a.pathname.match(/^(.+)\/assets\/jekyll-theme-cs50\.js$/);
5
+ if (matches) {
6
+ window.baseurl = matches[1];
7
+ }
8
+
9
+ // https://github.com/typekit/webfontloader#get-started
10
+ WebFont.load({
11
+ google: {
12
+ families: ['PT Sans', 'PT Sans:bold', 'PT Sans:ital']
13
+ }
14
+ });
15
+
16
+ // On DOMContentLoaded
17
+ $(document).on('DOMContentLoaded', function() {
18
+
19
+ // Current timestamp
20
+ const now = luxon.DateTime.local();
21
+
22
+ // data-after, data-before
23
+ $('[data-after], [data-before]').each(function(index, element) {
24
+
25
+ // Return true iff element should be removed
26
+ const remove = function() {
27
+ if (data = $(element).attr('data-before')) {
28
+ return !(now < luxon.DateTime.fromISO($(element).attr('data-before')));
29
+ }
30
+ else if (data = $(element).attr('data-after')) {
31
+ return !(now > luxon.DateTime.fromISO($(element).attr('data-after')));
32
+ }
33
+ };
34
+
35
+ // Remember element's siblings
36
+ const $prev = $(element).prev(), $next = $(element).next();
37
+
38
+ // Siblings to be merged
39
+ const SIBLINGS = ['DL', 'OL', 'UL'];
40
+
41
+ // If element should be removed
42
+ if (remove()) {
43
+
44
+ // Remove element
45
+ $(element).remove();
46
+
47
+ // Merge siblings
48
+ if (SIBLINGS.includes($prev.prop('tagName')) && $prev.prop('tagName') === $next.prop('tagName')) {
49
+ $prev.append($next.children());
50
+ $next.remove();
51
+ }
52
+ }
53
+ else {
54
+
55
+ // Unwrap element
56
+ const $children = $(element).children().unwrap();
57
+
58
+ // If element had one child
59
+ if ($children.length === 1) {
60
+
61
+ // Merge siblings
62
+ if (SIBLINGS.includes($children.prop('tagName'))) {
63
+ if ($prev.prop('tagName') === $children.prop('tagName')) {
64
+ $children.prepend($prev.children());
65
+ $prev.remove();
66
+ }
67
+ if ($children.prop('tagName') == $next.prop('tagName')) {
68
+ $children.append($next.children());
69
+ $next.remove();
70
+ }
71
+ }
72
+ }
73
+ }
74
+ });
75
+
76
+ // Remembers that alert with hash has been dismissed by storing hash in localStorage
77
+ const dismiss = function(hash) {
78
+ let alert;
79
+ try {
80
+ alert = JSON.parse(localStorage.getItem('alert'));
81
+ if (!Array.isArray(alert)) {
82
+ throw new Error();
83
+ }
84
+ }
85
+ catch (err) {
86
+ alert = [];
87
+ }
88
+ if (!alert.includes(hash)) {
89
+ alert.push(hash);
90
+ }
91
+ localStorage.setItem('alert', JSON.stringify(alert));
92
+ };
93
+
94
+ // Returns true iff alert with hash has already been dismissed
95
+ const dismissed = function(hash) {
96
+ try {
97
+ const alert = JSON.parse(localStorage.getItem('alert'));
98
+ return Array.isArray(alert) && alert.includes(hash);
99
+ }
100
+ catch (err) {
101
+ return false;
102
+ }
103
+ };
104
+
105
+ // Listen for dismissal of fixed-top alert
106
+ $('#alert').on('closed.bs.alert', function() {
107
+
108
+ // Resize UI
109
+ $(window).trigger('resize');
110
+
111
+ // Remember that alert has been dismissed
112
+ dismiss($(this).attr('data-hash'));
113
+ });
114
+
115
+ // Remove fixed-top alert if already dismissed
116
+ if (dismissed($('#alert').attr('data-hash'))) {
117
+ $('#alert').remove();
118
+ }
119
+
120
+ // Listen for details in fixed-top alert
121
+ $('#alert details').on('toggle', function() {
122
+
123
+ // Resize UI
124
+ $(window).trigger('resize');
125
+ });
126
+
127
+ // data-alert
128
+ $('[data-alert]').each(function(index, element) {
129
+
130
+ // Split data-alert on whitespace
131
+ for (let alert of $(element).attr('data-alert').split(/ +/)) {
132
+
133
+ // If valid class
134
+ if (['primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark', 'dismissible'].includes(alert)) {
135
+
136
+ // Add it to element
137
+ $(element).addClass('alert-' + alert);
138
+ }
139
+ }
140
+
141
+ // If dismissible, reveal button
142
+ if ($(element).hasClass('alert-dismissible')) {
143
+ $(element).children('[data-bs-dismiss]').removeClass('d-none');
144
+ }
145
+
146
+ // Add .alert-link to links
147
+ $(element).find('a').addClass('alert-link');
148
+
149
+ // Add .alert-heading to headings
150
+ $(element).find('h1, h2, h3, h4, h5, h6').each(function(index, element) {
151
+ const tagName = $(element).prop('tagName');
152
+ $(element).replaceWith(function() {
153
+ return $('<p>').append($(this).contents()).addClass(tagName.toLowerCase()).addClass('alert-heading');
154
+ });
155
+ });
156
+ });
157
+
158
+ // data-calendar
159
+ $('[data-calendar]').each(function(index, element) {
160
+
161
+ // Display calendar in user's time zone
162
+ // https://stackoverflow.com/a/32511510/5156190
163
+ if ($(element).attr('data-calendar')) {
164
+ let src = $(element).attr('data-calendar');
165
+ src += '&ctz=' + luxon.DateTime.local().zoneName;
166
+ $(element).attr('src', src);
167
+ }
168
+ });
169
+
170
+ // data-local
171
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#Syntax
172
+ // https://english.stackexchange.com/a/100754
173
+ $('[data-local]').each(function(index, element) {
174
+
175
+ // HTML to display
176
+ let html;
177
+
178
+ // Parse attribute
179
+ const local = $(element).attr('data-local');
180
+ const locals = local.split('/');
181
+
182
+ // If range
183
+ if (locals.length == 2) {
184
+
185
+ // Parse start
186
+ const start = luxon.DateTime.fromISO(locals[0]).setLocale(CS50.locale);
187
+
188
+ // Parse end
189
+ const end = luxon.DateTime.fromISO(locals[1]).setLocale(CS50.locale);
190
+
191
+ // Options for formatting start
192
+ const opts = {
193
+ day: CS50.local.day,
194
+ hour: CS50.local.hour,
195
+ minute: CS50.local.minute,
196
+ month: CS50.local.month,
197
+ weekday: CS50.local.weekday,
198
+ year: CS50.local.year
199
+ };
200
+
201
+ // If start and end on different dates or if clocks change between start and end
202
+ if (start.toLocaleString(luxon.DateTime.DATE_SHORT) !== end.toLocaleString(luxon.DateTime.DATE_SHORT) ||
203
+ start.toLocal().offsetNameLong !== end.toLocal().offsetNameLong) {
204
+
205
+ // Add time zone to start
206
+ opts.timeZoneName = CS50.local.timeZoneName;
207
+ }
208
+
209
+ // If start and end on same date (and English locale), or if end on midnight of start
210
+ if (CS50.locale === 'en' && (
211
+ start.toLocaleString(luxon.DateTime.DATE_SHORT) === end.toLocaleString(luxon.DateTime.DATE_SHORT) ||
212
+ end.toLocaleString(luxon.DateTime.TIME_24_WITH_SECONDS) === '24:00:00' &&
213
+ start.toLocaleString(luxon.DateTime.DATE_SHORT) == end.minus({days: 1}).toLocaleString(luxon.DateTime.DATE_SHORT))) {
214
+
215
+ // Format end without date
216
+ html = start.toLocaleString(opts) + ' – ' + end.toLocaleString({
217
+ hour: CS50.local.hour,
218
+ minute: CS50.local.minute,
219
+ timeZoneName: CS50.local.timeZoneName
220
+ });
221
+ }
222
+
223
+ // If start and end on different dates
224
+ else {
225
+
226
+ // Format end without date
227
+ html = start.toLocaleString(opts) + ' – ' + end.toLocaleString({
228
+ day: CS50.local.day,
229
+ hour: CS50.local.hour,
230
+ minute: CS50.local.minute,
231
+ month: CS50.local.month,
232
+ timeZoneName: CS50.local.timeZoneName,
233
+ weekday: CS50.local.weekday,
234
+ year: CS50.local.year
235
+ });
236
+ }
237
+ }
238
+ else {
239
+
240
+ // Parse start
241
+ const start = luxon.DateTime.fromISO(locals[0]).setLocale(CS50.locale);
242
+
243
+ // Format start
244
+ html = start.toLocaleString({
245
+ day: CS50.local.day,
246
+ hour: CS50.local.hour,
247
+ minute: CS50.local.minute,
248
+ month: CS50.local.month,
249
+ timeZoneName: CS50.local.timeZoneName,
250
+ weekday: CS50.local.weekday,
251
+ year: CS50.local.year
252
+ });
253
+ }
254
+
255
+ // Display HTML
256
+ $(this).html(html);
257
+
258
+ // Inject clock after date-local (and, if date-local is inside a link, outside that link)
259
+ const $clock = $('<a data-clock href="https://time.cs50.io/' + local + '"><i class="far fa-clock" title="CS50 Time Converter"></i></a>');
260
+ const $closest = $(this).closest('a');
261
+ if ($closest.length) {
262
+ $closest.after($clock);
263
+ }
264
+ else {
265
+ $(this).after($clock);
266
+ }
267
+ });
268
+
269
+ // Toggle clocks on hover
270
+ const enableClocks = function(element) {
271
+ $('[data-clock]').each(function(index, element) {
272
+ $(element).on('mouseover', function() {
273
+ $(element).find('.fa-clock').removeClass('far').addClass('fas');
274
+ });
275
+ $(element).on('click mouseout', function() {
276
+ $(element).find('.fa-clock').removeClass('fas').addClass('far');
277
+ });
278
+ });
279
+ };
280
+ enableClocks();
281
+
282
+ // Enable tooltips
283
+ const enableTooltips = function() {
284
+ $('[data-bs-toggle="tooltip"]').each(function(index, element) {
285
+ new bootstrap.Tooltip(element);
286
+ });
287
+ };
288
+ enableTooltips();
289
+
290
+ // Re-attach tooltips after tables have responded
291
+ // https://github.com/wenzhixin/bootstrap-table/issues/572#issuecomment-76503607
292
+ $('table').on('post-body.bs.table', function() {
293
+ enableClocks();
294
+ enableTooltips();
295
+ });
296
+
297
+ // Ensure tables are responsive
298
+ // https://bootstrap-table.com/docs/extensions/mobile/
299
+ $('table').each(function(index, element) {
300
+
301
+ // Workaround for https://github.com/wenzhixin/bootstrap-table/issues/5470
302
+ $(element).find('thead td, thead th').each(function(index, element) {
303
+ if ($(element).css('text-align')) {
304
+ $(element).wrapInner('<div style="text-align: ' + $(element).css('text-align') + '">');
305
+ }
306
+ });
307
+
308
+ // Enable bootstrap-table
309
+ try {
310
+ $(element).bootstrapTable({
311
+ classes: 'table table-bordered table-striped',
312
+ minWidth: 992, // https://getbootstrap.com/docs/5.0/layout/breakpoints/#available-breakpoints
313
+ mobileResponsive: true,
314
+ onPostBody: function(data) {
315
+
316
+ // Left-align cards on mobile
317
+ $(element).find('.card-view-title, .card-view-title > *, .card-view-value').css('text-align', 'left');
318
+ }
319
+ });
320
+ }
321
+ catch(err) {} // In case no thead
322
+ });
323
+
324
+ // data-marker
325
+ $('[data-marker]').each(function(index, element) {
326
+
327
+ // Add .fa-ul to parent ul
328
+ $(element).parent().addClass('fa-ul');
329
+
330
+ // Filter
331
+ const filter = function() {
332
+ return !$(this).is('ol, ul');
333
+ };
334
+
335
+ // Listener
336
+ const click = function(eventObject) {
337
+
338
+ // If it wasn't a descendent link that was clicked
339
+ if (!$(eventObject.target).is('a')) {
340
+
341
+ // Don't propgate to nested lists
342
+ eventObject.stopPropagation();
343
+
344
+ // Toggle marker
345
+ const marker = $(element).attr('data-marker');
346
+ if (marker === '+') {
347
+ $(element).attr('data-marker', '-');
348
+ $(element).find('> .fa-li > .fa-plus-square').removeClass('fa-plus-square').addClass('fa-minus-square');
349
+ }
350
+ else if (marker === '-') {
351
+ $(element).attr('data-marker', '+');
352
+ $(element).find('> .fa-li > .fa-minus-square').removeClass('fa-minus-square').addClass('fa-plus-square');
353
+ }
354
+ $(window).trigger('resize');
355
+ }
356
+ };
357
+
358
+ // Icons
359
+ const plus = $('<span class="fa-li"><i class="far fa-plus-square"></i></span>').click(click);
360
+ const minus = $('<span class="fa-li"><i class="far fa-minus-square"></i></span>').click(click);
361
+ const square = $('<span class="fa-li"><i class="fas fa-square"></i></span>');
362
+
363
+ // Wrapper
364
+ const $span = $('<span>').click(click);
365
+
366
+ // If +
367
+ if ($(element).attr('data-marker') === '+') {
368
+ $(element).contents().filter(filter).wrap($span);
369
+ $(element).prepend(plus);
370
+ }
371
+
372
+ // If -
373
+ else if ($(element).attr('data-marker') === '-') {
374
+ $(element).contents().filter(filter).wrap($span);
375
+ $(element).prepend(minus);
376
+ }
377
+
378
+ // If *
379
+ else if ($(element).attr('data-marker') === '*') {
380
+ $(element).prepend(square);
381
+ }
382
+ });
383
+
384
+ // Also add .fa-ul to TOC, if any, for consistency
385
+ $('.markdown-toc').addClass('fa-ul');
386
+
387
+ // Get next slice of elements
388
+ function next(element) {
389
+
390
+ // Next siblings
391
+ const siblings = element.nextAll();
392
+
393
+ // First sibling after this element
394
+ const start = siblings.index(element) + 1;
395
+
396
+ // Following buttons
397
+ const buttons = siblings.slice(start).find('[data-next]');
398
+
399
+ // Last sibling before next button
400
+ let end = (buttons.length > 0) ? siblings.index(buttons[0]) : siblings.length;
401
+
402
+ // Next slice
403
+ return siblings.slice(start, end);
404
+ }
405
+
406
+ // data-next
407
+ $('[data-next]').each(function(index, element) {
408
+
409
+ // Hide next elements
410
+ next($(this).parent()).addClass('next');
411
+
412
+ // Listen for clicks
413
+ $(this).click(function() {
414
+
415
+ // Show next elements
416
+ next($(this).parent()).removeClass('next');
417
+
418
+ // Update margin
419
+ $(window).trigger('resize');
420
+
421
+ // Remember p-wrapped button's offset
422
+ let top = $(this).parent().offset().top;
423
+ let bottom = top + $(this).parent().outerHeight(true);
424
+
425
+ // Scroll to next elements
426
+ $('html, body').animate({scrollTop: bottom + 1}, 500);
427
+
428
+ // Disable button
429
+ $(this).prop('disabled', true);
430
+ });
431
+ });
432
+
433
+ // Ensure iframes responsive in Safari on iOS (for, e.g., Google Calendars), per https://stackoverflow.com/a/23083463/5156190
434
+ $('iframe').each(function(index, element) {
435
+ if (!$(this).attr('scrolling')) {
436
+ $(this).attr('scrolling', 'no');
437
+ }
438
+ });
439
+
440
+ // Render Mermaid charts
441
+ $('code[class="language-mermaid"]').each(function(index, element) {
442
+
443
+ // Replace pre > code with div
444
+ const $element = $(element);
445
+ const $div = $('<div class="mermaid">').text($element.text());
446
+ $element.parent().replaceWith($div);
447
+
448
+ // Render chart
449
+ mermaid.init({}, $div.get(0));
450
+
451
+ // Left-align Mermaid, until https://github.com/mermaid-js/mermaid/issues/1983
452
+ // https://stackoverflow.com/a/6322799/5156190
453
+ $div.children('svg').attr('preserveAspectRatio', 'xMinYMin meet');
454
+ });
455
+
456
+ // Render Scratch blocks
457
+ scratchblocks.renderMatching('pre code.language-scratch', {
458
+ style: 'scratch3'
459
+ });
460
+
461
+ // Remove PRE wrapper, since not actually preformatted text
462
+ $('pre code.language-scratch').each(function(index, element) {
463
+ $(element).parent().replaceWith($(element).children());
464
+ });
465
+
466
+ // https://github.com/scratchblocks/scratchblocks/pull/301#issuecomment-829428605
467
+ $('.scratchblocks svg').each(function(index, element) {
468
+ const bbox = element.getBBox();
469
+ const height = Math.floor(bbox.height) + 2; // Prevents clipping of bottom of some blocks
470
+ $(element).attr('width', bbox.width);
471
+ $(element).attr('height', height);
472
+ $(element).parent().css('height', Math.ceil(element.getBoundingClientRect().height) + 'px');
473
+ });
474
+
475
+ // If H1 is immediately followed H2 (and no other H2 siblings),
476
+ // treat H1 as title and H2 as subtitle, relocating in DOM as customized heading
477
+ // https://getbootstrap.com/docs/4.6/content/typography/#customizing-headings
478
+ const $title = $('main h1').first();
479
+ const $subtitle = $title.next('h2');
480
+ if ($title.length && $subtitle.length && !$subtitle.nextAll('h2').length) {
481
+ $title.append(' ').append($('<small>').addClass('text-muted').append($subtitle.detach().contents()));
482
+ }
483
+
484
+ // Get headings
485
+ const headings = $([
486
+ 'main h1',
487
+ 'main h2',
488
+ 'main h3',
489
+ 'main h4',
490
+ 'main h5',
491
+ 'main h6'].join(','));
492
+ headings.each(function(index, element) {
493
+
494
+ // If it has an id
495
+ if ($(element).attr('id')) {
496
+
497
+ // Link heading's children to heading (unless already linked)
498
+ $(element).contents().each(function(index, node) {
499
+ if (!$(node).is('a')) {
500
+ $(node).wrapAll($('<a data-id href="#' + $(element).attr('id') + '"></a>'));
501
+ }
502
+ });
503
+
504
+ // Relocate id to an anchor (so that it can be invisibly positioned below any alert)
505
+ // https://stackoverflow.com/a/13184714
506
+ $(element).before($('<a data-id id="' + $(element).attr('id') + '"></a>'))
507
+ $(element).removeAttr('id');
508
+ }
509
+ });
510
+
511
+ // Listen for hashchange
512
+ $(window).on('hashchange', function() {
513
+
514
+ // Find heading
515
+ let heading;
516
+ try {
517
+ heading = $(window.location.hash); // In case syntactically invalid ID
518
+ }
519
+ catch (err) {
520
+ return false;
521
+ }
522
+ if (!heading.length) {
523
+ return false;
524
+ }
525
+
526
+ // Previous siblings
527
+ heading.prevAll().removeClass('next').find('[data-next]').prop('disabled', true);
528
+
529
+ // This heading
530
+ heading.removeClass('next');
531
+
532
+ // Next siblings
533
+ next(heading).removeClass('next');
534
+ });
535
+ $(window).trigger('hashchange');
536
+
537
+ // Listen for resize
538
+ $(window).on('resize', function() {
539
+
540
+ // Return true iff small device (on which aside will be above main)
541
+ const mobile = function() {
542
+ return $('aside').position().top < $('main').position().top;
543
+ };
544
+
545
+ // Get headings
546
+ const headings = $([
547
+ 'main h1:not(.next)',
548
+ 'main h2:not(.next)',
549
+ 'main h3:not(.next)',
550
+ 'main h4:not(.next)',
551
+ 'main h5:not(.next)',
552
+ 'main h6:not(.next)'].join(','));
553
+
554
+ // Ensure last heading, if any, can be anchored atop page
555
+ if (headings.last().offset()) {
556
+ var top = headings.last().offset().top;
557
+ }
558
+ else {
559
+ var top = 0;
560
+ }
561
+
562
+ // On small devices
563
+ if (mobile()) {
564
+ var margin = $(window).height() - ($('main').outerHeight() + $('aside').outerHeight() - top);
565
+ }
566
+
567
+ // On large devices
568
+ else {
569
+ var margin = $(window).height() - ($('main').outerHeight() - top);
570
+ }
571
+
572
+ // Update margin
573
+ $('main').css('margin-bottom', Math.max(0, Math.ceil(margin)) + 'px');
574
+
575
+ // Resize search UI
576
+ if (mobile()) {
577
+
578
+ // Shrink
579
+ $('#search .form-control').removeClass('form-control-lg');
580
+ $('#search .btn').removeClass('btn-lg');
581
+ }
582
+ else {
583
+
584
+ // Grow
585
+ $('#search .form-control').addClass('form-control-lg');
586
+ $('#search .btn').addClass('btn-lg');
587
+ }
588
+
589
+ // Calculate height of alert, if any
590
+ const height = $('#alert').outerHeight(true) || 0;
591
+
592
+ // Position aside
593
+ if (mobile()) {
594
+ $('aside').css('height', '');
595
+ $('aside').css('margin-top', height + 'px');
596
+ $('aside').css('top', '');
597
+ $('main').css('margin-top', '');
598
+ }
599
+ else {
600
+ $('aside').css('height', ($(window).height() - height) + 'px');
601
+ $('aside').css('margin-top', '');
602
+ $('aside').css('top', height + 'px');
603
+ $('main').css('margin-top', height + 'px');
604
+ }
605
+
606
+ // Position headings' anchors below alert
607
+ // https://stackoverflow.com/a/13184714
608
+ $('a[data-id][id]').css('top', '-' + height + 'px');
609
+
610
+ });
611
+ $(window).trigger('resize');
612
+
613
+ // Resize iframes dynamically
614
+ $('iframe').on('load', function() {
615
+ $(this).iFrameResize();
616
+ });
617
+
618
+ // Reveal page
619
+ $('body').removeClass('invisible');
620
+ });
@@ -0,0 +1,20 @@
1
+ Copyright OpenJS Foundation and other contributors, https://openjsf.org/
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.