@pimaonline/pimaonline-themepack 2.4.1 → 3.0.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 (92) hide show
  1. package/LICENSE.md +30 -0
  2. package/README.md +69 -111
  3. package/dist/css/main.css +1 -1
  4. package/dist/css/themes/ecn/styles.css +1 -0
  5. package/dist/css/themes/eng/styles.css +1 -0
  6. package/dist/css/themes/fsc/styles.css +1 -0
  7. package/dist/css/themes/lang/styles.css +1 -1
  8. package/dist/css/themes/ss/styles.css +1 -0
  9. package/dist/img/theme-images/ecn/arrow-2.svg +4 -0
  10. package/dist/img/theme-images/ecn/arrow.svg +4 -0
  11. package/dist/img/theme-images/ecn/point.svg +3 -0
  12. package/dist/img/theme-images/eng/button-bkg.svg +178 -0
  13. package/dist/img/theme-images/eng/halftone-banner.svg +1 -0
  14. package/dist/img/theme-images/eng/halftone.svg +177 -0
  15. package/dist/img/theme-images/eng/long-button-bkg.svg +353 -0
  16. package/dist/img/theme-images/fsc/bottomwave-pinkred.svg +17 -0
  17. package/dist/img/theme-images/fsc/bottomwave-redorange.svg +17 -0
  18. package/dist/img/theme-images/fsc/bottomwave-yellow.svg +17 -0
  19. package/dist/img/theme-images/fsc/bottomwave-yelloworange.svg +17 -0
  20. package/dist/img/theme-images/fsc/fire-icon.png +0 -0
  21. package/dist/img/theme-images/fsc/mainwave-pinkred.svg +17 -0
  22. package/dist/img/theme-images/fsc/mainwave-redorange.svg +17 -0
  23. package/dist/img/theme-images/fsc/mainwave-yellow.svg +17 -0
  24. package/dist/img/theme-images/fsc/mainwave-yelloworange.svg +17 -0
  25. package/dist/img/theme-images/lang/country-flags/argentina_flag.png +0 -0
  26. package/dist/img/theme-images/lang/country-flags/bolivia_flag.png +0 -0
  27. package/dist/img/theme-images/lang/country-flags/chile_flag.png +0 -0
  28. package/dist/img/theme-images/lang/country-flags/colombia_flag.png +0 -0
  29. package/dist/img/theme-images/lang/country-flags/costa-rica_flag.png +0 -0
  30. package/dist/img/theme-images/lang/country-flags/cuba_flag.png +0 -0
  31. package/dist/img/theme-images/lang/country-flags/dominican-republic_flag.png +0 -0
  32. package/dist/img/theme-images/lang/country-flags/ecuador_flag.png +0 -0
  33. package/dist/img/theme-images/lang/country-flags/el-salvador_flag.png +0 -0
  34. package/dist/img/theme-images/lang/country-flags/guatemala_flag.png +0 -0
  35. package/dist/img/theme-images/lang/country-flags/honduras_flag.png +0 -0
  36. package/dist/img/theme-images/lang/country-flags/mexico_flag.png +0 -0
  37. package/dist/img/theme-images/lang/country-flags/nicaragua_flag.png +0 -0
  38. package/dist/img/theme-images/lang/country-flags/panama_flag.png +0 -0
  39. package/dist/img/theme-images/lang/country-flags/paraguay_flag.png +0 -0
  40. package/dist/img/theme-images/lang/country-flags/peru_flag.png +0 -0
  41. package/dist/img/theme-images/lang/country-flags/puerto-rice_flag.png +0 -0
  42. package/dist/img/theme-images/lang/country-flags/spain_flag.png +0 -0
  43. package/dist/img/theme-images/lang/country-flags/uruguay_flag.png +0 -0
  44. package/dist/img/theme-images/lang/country-flags/venezuela_flag.png +0 -0
  45. package/dist/img/theme-images/music/half_note.svg +5 -5
  46. package/dist/img/theme-images/resort/flourish-left.svg +32 -32
  47. package/dist/img/theme-images/resort/flourish-main.svg +37 -37
  48. package/dist/img/theme-images/resort/flourish-right.svg +31 -31
  49. package/dist/img/theme-images/resort/separator.svg +15 -15
  50. package/dist/img/theme-images/ss/blockquote.svg +3 -0
  51. package/dist/img/theme-images/ss/list-style.svg +3 -0
  52. package/dist/img/theme-images/ss/main-large-blob.svg +3 -0
  53. package/dist/img/theme-images/ss/main-small-blob.svg +3 -0
  54. package/dist/img/theme-images/ss/small-blob.svg +3 -0
  55. package/dist/img/theme-images/ss/tall-blob.svg +3 -0
  56. package/dist/img/theme-images/widgets/separator.svg +17 -17
  57. package/dist/js/jumpTo.js +3 -3
  58. package/dist/js/scripts.js +326 -326
  59. package/dist/js/scripts2.js +541 -361
  60. package/dist/plugins/fancybox/fancybox-example.html +51 -51
  61. package/dist/plugins/fancybox/fancybox.css +72 -72
  62. package/dist/plugins/fancybox/helpers/jquery.fancybox-buttons.css +97 -97
  63. package/dist/plugins/fancybox/helpers/jquery.fancybox-buttons.js +122 -122
  64. package/dist/plugins/fancybox/helpers/jquery.fancybox-media.js +201 -201
  65. package/dist/plugins/fancybox/helpers/jquery.fancybox-thumbs.css +54 -54
  66. package/dist/plugins/fancybox/helpers/jquery.fancybox-thumbs.js +165 -165
  67. package/dist/plugins/fancybox/jquery.fancybox.css +274 -274
  68. package/dist/plugins/fancybox/jquery.fancybox.js +2018 -2018
  69. package/dist/plugins/fancybox/jquery.fancybox.pack.js +46 -46
  70. package/dist/plugins/flashcards/README.md +135 -135
  71. package/dist/plugins/flashcards/config.rb +24 -24
  72. package/dist/plugins/flashcards/css/style.css +215 -215
  73. package/dist/plugins/flashcards/flashcards-example.html +65 -65
  74. package/dist/plugins/flashcards/index.html +90 -90
  75. package/dist/plugins/flashcards/js/flash_cards.min.js +11 -11
  76. package/dist/plugins/flashcards/js/plugins/flash_cards.js +62 -62
  77. package/dist/plugins/flashcards/js/plugins/jquery.cycle.js +1147 -1147
  78. package/dist/plugins/flashcards/js/vendor/jquery-1.7.2.js +9404 -9404
  79. package/dist/plugins/flashcards/js/vendor/jquery-1.7.2.min.js +3 -3
  80. package/dist/plugins/flashcards/js/vendor/modernizr-2.5.3.min.js +3 -3
  81. package/dist/plugins/flashcards/resources/fonts/flash_cards/flash_cards.svg +20 -20
  82. package/dist/plugins/floating-particles/floating-particles.js +67 -67
  83. package/dist/plugins/font-awesome-icons/webfonts/fa-brands-400.svg +3570 -3570
  84. package/dist/plugins/font-awesome-icons/webfonts/fa-regular-400.svg +803 -803
  85. package/dist/plugins/font-awesome-icons/webfonts/fa-solid-900.svg +4700 -4700
  86. package/dist/plugins/global-homepage-overrides/global-homepage-overrides.css +539 -539
  87. package/dist/plugins/global-homepage-overrides/global-homepage-overrides.html +18 -18
  88. package/dist/plugins/global-homepage-overrides/global-homepage-overrides.js +52 -52
  89. package/dist/plugins/preview-banner/preview-banner.css +125 -125
  90. package/dist/plugins/preview-banner/preview-banner.html +17 -17
  91. package/dist/plugins/preview-banner/preview-banner.js +56 -56
  92. package/package.json +39 -40
@@ -1,327 +1,327 @@
1
- /// @description Main JS file for PimaOnline Themepack
2
- /// @dependencies jQuery 3.3.1 or later
3
-
4
- window.addEventListener("DOMContentLoaded", () => {
5
-
6
- const courseBody = document.querySelector("body");
7
- const contentWrapper = document.querySelector("#content-wrapper");
8
- const secondColumn = document.querySelector("#second-column");
9
- const thirdColumn = document.querySelector("#third-column");
10
- const columnWidget = document.querySelector("#column-widget");
11
- const videoWrapper = document.querySelector("#video-wrapper");
12
- const rolePres = document.querySelectorAll('[role="presentation"]');
13
- const imageGallery = document.querySelector(".image-gallery");
14
- const vocabListWidget = document.querySelector("dl.vocab-list");
15
- const vocabTerms = document.querySelectorAll("dl.vocab-list dt");
16
- const vocabDefs = document.querySelectorAll("dl.vocab-list dd");
17
- const vocabCloseBtns = document.querySelectorAll("dl.vocab-list button");
18
- const vocabLists = document.querySelectorAll("dl[class^='vocab-list']");
19
- const mediaContainers = document.querySelectorAll(".media-container");
20
- const tabsWidgets = document.querySelectorAll(".tabs");
21
-
22
- // Grid
23
- const addGrid = () => {
24
- if (secondColumn && thirdColumn) {
25
- courseBody.id = "three-column";
26
- } else if (secondColumn && !columnWidget) {
27
- courseBody.id = "two-column";
28
- } else if (columnWidget) {
29
- courseBody.id = "two-col-widget";
30
- } else if (videoWrapper) {
31
- courseBody.id = "video-grid";
32
- } else {
33
- courseBody.id = "one-column";
34
- }
35
- };
36
- addGrid();
37
-
38
- // JS to add role and aria-label to content-wrapper, second-column, and third-column
39
- const addAria = () => {
40
- contentWrapper.setAttribute("role", "main");
41
- if (secondColumn) {
42
- secondColumn.setAttribute("role", "region");
43
- secondColumn.setAttribute("aria-label", "Second column");
44
- }
45
- if (thirdColumn) {
46
- thirdColumn.setAttribute("role", "region");
47
- thirdColumn.setAttribute("aria-label", "Third column");
48
- }
49
- };
50
- addAria();
51
-
52
- // Clean up HTML
53
- const cleanMarkup = () => {
54
- // Remove role="presentation" attr from any element that has it
55
- if (rolePres) {
56
- rolePres.forEach((roleElem) => roleElem.removeAttribute("role"));
57
- }
58
- // Set functino to remove atrributes from elements
59
- const discardAttributes = (element, ...attributes) => {
60
- attributes.forEach((attribute) => element.removeAttribute(attribute));
61
- }
62
- // Remove attributes from tables
63
- const tableElems = document.querySelectorAll("table, thead, tbody, tr, th, td");
64
- tableElems.forEach((elem) => {
65
- discardAttributes(elem, "cellspacing", "cellpadding", "width", "style");
66
- });
67
- };
68
- cleanMarkup();
69
-
70
- // Helper JS for Responsive Tables
71
- const initResponsiveTables = () => {
72
- const tables = document.querySelectorAll(".display, .display-lg")
73
- for (let table = 0; table < tables.length; table++) {
74
- let headertext = [],
75
- headers = tables[table].querySelectorAll(".display table th, table.display th, .display-lg table th, table.display-lg th"),
76
- tablebody = tables[table].querySelector(".display table tbody, table.display tbody, .display-lg table tbody, table.display-lg tbody");
77
- for (let header = 0; header < headers.length; header++) {
78
- let current = headers[header];
79
- headertext.push(current.textContent.replace(/\r?\n|\r/, ""));
80
- }
81
- for (let y = 0, row; row = tablebody.rows[y]; y++) {
82
- for (let j = 0, col; col = row.cells[j]; j++) {
83
- col.setAttribute("data-th", headertext[j]);
84
- }
85
- }
86
- }
87
- }
88
- initResponsiveTables();
89
-
90
- // This is called by anchor links via onlick="" in the HTML
91
- // Added because default anchor links don't work on all browsers using D2L
92
- const addScript = (script) => {
93
- let newScript = document.createElement("script");
94
- newScript.setAttribute("src", script);
95
-
96
- document.body.append(newScript);
97
- }
98
-
99
- if(document.querySelector("[onclick]")) {
100
- addScript("https://cdn.jsdelivr.net/npm/@pimaonline/pimaonline-themepack/dist/js/jumpTo.js");
101
- }
102
-
103
- // Image gallery
104
- const callImageGallery = () => {
105
- // Create link element with font-awesome cdn and append it to the <head>
106
- const docHead = document.querySelector("head");
107
- const fontAwesomeCdn = document.createElement("link");
108
- fontAwesomeCdn.setAttribute("rel", "stylesheet");
109
- fontAwesomeCdn.setAttribute("href", "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css");
110
- docHead.appendChild(fontAwesomeCdn);
111
- // Begin image gallery
112
- const imgGalleries = document.querySelectorAll(".image-gallery"),
113
- imgBoxes = document.querySelectorAll(".image-box"),
114
- modalBoxContent = `<div class="modal-box invisible">
115
- <div class="gallery-overlay"></div>
116
- <figure class="modal-box--image"><i class="fa-solid fa-x close-img"></i> <img src="#" alt="image here" /><figcaption class="img-caption"></figcaption></figure>
117
- </div>
118
- <button class="hide-gallery">Hide</button>`;
119
-
120
- // createModalBox.innerHTML = modalBoxContent;
121
- for (let imgGallery = 0; imgGallery < imgGalleries.length; imgGallery++) {
122
- imgGalleries[imgGallery].insertAdjacentHTML("afterbegin", modalBoxContent);
123
- }
124
-
125
- if (document.querySelector(".modal-box")) {
126
- const overlay = document.querySelector(".gallery-overlay"),
127
- modalBox = document.querySelector(".modal-box"),
128
- modalImg = document.querySelector(".modal-box--image img"),
129
- modalCaption = document.querySelector(".img-caption"),
130
- closeImg = document.querySelector(".close-img");
131
-
132
- for (let imgBox = 0; imgBox < imgBoxes.length; imgBox++) {
133
- imgBoxes[imgBox].onclick = function () {
134
- modalBox.classList.remove("invisible");
135
- let imgSrc = this.querySelector("img").src;
136
- modalImg.src = imgSrc;
137
- let imgCaption = this.querySelector("img").alt;
138
- modalCaption.innerHTML = imgCaption;
139
- }
140
- }
141
- overlay.onclick = () => {
142
- modalBox.classList.add("invisible");
143
- }
144
- window.onkeydown = (esc) => {
145
- if (esc.keyCode === 27) {
146
- modalBox.classList.add("invisible");
147
- }
148
- }
149
- closeImg.onclick = () => {
150
- modalBox.classList.add("invisible");
151
- }
152
- const hideGalleries = document.querySelectorAll(".hide-gallery");
153
- for (let hideGallery = 0; hideGallery < hideGalleries.length; hideGallery++) {
154
- hideGalleries[hideGallery].addEventListener("click", () => {
155
- hideGalleries[hideGallery].nextElementSibling.classList.toggle("invisible");
156
- if (hideGalleries[hideGallery].innerHTML === "Hide") {
157
- hideGalleries[hideGallery].innerHTML = "Show";
158
- } else {
159
- hideGalleries[hideGallery].innerHTML = "Hide";
160
- }
161
- });
162
- }
163
- };
164
- }
165
- if (imageGallery) {
166
- callImageGallery();
167
- }
168
-
169
- // Vocab list widget
170
- const callVocabList = () => {
171
- if (vocabCloseBtns) {
172
- for(let btn = 0; btn < vocabCloseBtns.length; btn++) {
173
- vocabCloseBtns[btn].addEventListener("click", () => {
174
- for(let node = 0; node < vocabLists[btn].children.length;node++) {
175
- if(vocabLists[btn].children[node].tagName == "DD") {
176
- vocabLists[btn].children[node].removeAttribute("style");
177
- }
178
- if(vocabLists[btn].children[node].tagName == "DT") {
179
- vocabLists[btn].children[node].removeAttribute("class");
180
- }
181
- }});
182
- }
183
- }
184
- for (let activeTerm = 0; activeTerm < vocabTerms.length; activeTerm++) {
185
- vocabTerms[activeTerm].addEventListener("click", function() {
186
- this.classList.toggle("active");
187
- let termPanel = this.nextElementSibling;
188
- if (termPanel.style.display === "block") { termPanel.removeAttribute("style"); }
189
- else { termPanel.style.display = "block"; }
190
- });
191
-
192
- vocabTerms[activeTerm].addEventListener("keydown", function(e) {
193
- if(e.key === "Enter") {
194
- this.classList.toggle("active");
195
- let termPanel = this.nextElementSibling;
196
- if (termPanel.style.display === "block") { termPanel.removeAttribute("style"); }
197
- else { termPanel.style.display = "block"; }
198
- }
199
- });
200
- }
201
- }
202
- if (vocabListWidget) {callVocabList();}
203
-
204
- //
205
- const addMediaContainersAria = () => {
206
- mediaContainers.forEach((eachContainer, index) => {
207
- // loopID: find the current index value, convert it to its letter equivalent, then convert to lowercase
208
- let loopId = String.fromCharCode(index + 65).toLowerCase();
209
- let mediaObject = eachContainer.querySelector(".media-object");
210
- let iframe = mediaObject.firstElementChild;
211
- let mediaInfo = mediaObject.nextElementSibling;
212
-
213
- // If element DOES NOT have "aria-describedby" && it DOES have a sibling element.
214
- if (!iframe.hasAttribute("aria-describedby") && mediaInfo != null) {
215
- iframe.setAttribute("aria-describedby", `${loopId}`);
216
- mediaInfo.id = `${[loopId]}`;
217
- }
218
- });
219
- }
220
- if (mediaContainers) {addMediaContainersAria();}
221
-
222
- //Tabs Widget
223
- const callTabsWidget = () => {
224
-
225
- let tabsWidgetsNum = 0;
226
-
227
- tabsWidgets.forEach((tab,index) => {
228
- let tabInputs = tab.querySelectorAll("input")
229
- let tabLabels = tab.querySelectorAll("label")
230
- let tabDivs = tab.querySelectorAll("div")
231
-
232
- let groupNum = index + 1;
233
-
234
- //Add region and aria-label to parent div
235
- tab.setAttribute("role", "region");
236
- tab.setAttribute("aria-label", `tab group ${groupNum}`)
237
-
238
- for(tabIndex = 0; tabIndex < tabInputs.length; tabIndex++) {
239
-
240
- let tabNum = tabsWidgetsNum + 1;
241
-
242
- //Add class, id, name, and aria-described by for inputs
243
- tabInputs[tabIndex].classList.add("tab-input");
244
- tabInputs[tabIndex].setAttribute("type", "radio")
245
- tabInputs[tabIndex].setAttribute("id", `tab${tabNum}`);
246
- tabInputs[tabIndex].setAttribute("name", `hint-group-${groupNum}` )
247
- tabInputs[tabIndex].setAttribute("aria-describedby", `tabHeading${tabNum}`)
248
- //Add class and for for labels
249
- tabLabels[tabIndex].classList.add("tab-header");
250
- tabLabels[tabIndex].setAttribute("for", `tab${tabNum}`)
251
- //Add class, tabindex, and id for divs
252
- tabDivs[tabIndex].classList.add("tab-panel")
253
- tabDivs[tabIndex].setAttribute("tabindex", 0)
254
- tabDivs[tabIndex].setAttribute("id", `tabHeading${tabNum}`)
255
- //Add attributes for hide tab
256
- if(tabIndex + 1 == tabInputs.length) {
257
- tabLabels[tabIndex].classList.add("hide-tab")
258
- tabInputs[tabIndex].checked = true;
259
- tabDivs[tabIndex].classList.add("hide-panel")
260
- }
261
- tabsWidgetsNum++;
262
- }
263
- })
264
- }
265
- if (tabsWidgets) {callTabsWidget();}
266
-
267
- // Toggle footnotes
268
- const toggleBtns = document.querySelectorAll(".toggle-btn, .toggle-footnotes");
269
-
270
- if (document.querySelector(".toggle-btn") || document.querySelector(".toggle-footnotes")) {
271
- for (let toggleBtn = 0; toggleBtn < toggleBtns.length; toggleBtn++) {
272
- // Add tabindex
273
- toggleBtns[toggleBtn].setAttribute("tabindex", "0");
274
-
275
- // Show/hide on click
276
- toggleBtns[toggleBtn].addEventListener("click", () => {
277
- toggleBtns[toggleBtn].nextElementSibling.classList.toggle("show");
278
- })
279
-
280
- // Show/hide on enter for users who use tab
281
- toggleBtns[toggleBtn].addEventListener("keydown", (enter) => {
282
- if (enter.keyCode === 13) {
283
- toggleBtns[toggleBtn].nextElementSibling.classList.toggle("show");
284
- }
285
- })
286
- }
287
- }
288
-
289
- // Call function with jQuery scripts
290
- const callJquery = () => {
291
- // Toggle Button's Arrow Right Points Down on Click
292
- $('.arrow-right').on('click', function () {
293
- $(this).toggleClass('arrow-down');
294
- });
295
- // TOOLTIP
296
- // Allows Screen readers to toggle a tooltip on click and to say if the tooltip is collapsed or expanded.
297
- $(".tooltip").click(function () {
298
- $(this).children(".tip-hover").toggle();
299
- if ($(this).children(".tip-hover").is(':visible')) {
300
- $(this).attr('aria-expanded', 'true');
301
- $(this).removeClass('hidden');
302
- } else {
303
- $(this).attr('aria-expanded', 'false');
304
- $(this).addClass('hidden');
305
- }
306
- });
307
- let start = 999;
308
- $('.tooltip').each(function (i) {
309
- $(this).css('z-index', start--);
310
- });
311
- $(".tooltip .video-container").parent().css("width", "450px");
312
- }
313
- callJquery();
314
-
315
- // Fancybox
316
- if (document.querySelector(".fancybox")) {
317
- $("[data-fancybox]").fancybox({
318
- idleTime: false,
319
- topRatio: 0.1,
320
- helpers: {
321
- title: {
322
- type: 'inside'
323
- },
324
- }
325
- });
326
- }
1
+ /// @description Main JS file for PimaOnline Themepack
2
+ /// @dependencies jQuery 3.3.1 or later
3
+
4
+ window.addEventListener("DOMContentLoaded", () => {
5
+
6
+ const courseBody = document.querySelector("body");
7
+ const contentWrapper = document.querySelector("#content-wrapper");
8
+ const secondColumn = document.querySelector("#second-column");
9
+ const thirdColumn = document.querySelector("#third-column");
10
+ const columnWidget = document.querySelector("#column-widget");
11
+ const videoWrapper = document.querySelector("#video-wrapper");
12
+ const rolePres = document.querySelectorAll('[role="presentation"]');
13
+ const imageGallery = document.querySelector(".image-gallery");
14
+ const vocabListWidget = document.querySelector("dl.vocab-list");
15
+ const vocabTerms = document.querySelectorAll("dl.vocab-list dt");
16
+ const vocabDefs = document.querySelectorAll("dl.vocab-list dd");
17
+ const vocabCloseBtns = document.querySelectorAll("dl.vocab-list button");
18
+ const vocabLists = document.querySelectorAll("dl[class^='vocab-list']");
19
+ const mediaContainers = document.querySelectorAll(".media-container");
20
+ const tabsWidgets = document.querySelectorAll(".tabs");
21
+
22
+ // Grid
23
+ const addGrid = () => {
24
+ if (secondColumn && thirdColumn) {
25
+ courseBody.id = "three-column";
26
+ } else if (secondColumn && !columnWidget) {
27
+ courseBody.id = "two-column";
28
+ } else if (columnWidget) {
29
+ courseBody.id = "two-col-widget";
30
+ } else if (videoWrapper) {
31
+ courseBody.id = "video-grid";
32
+ } else {
33
+ courseBody.id = "one-column";
34
+ }
35
+ };
36
+ addGrid();
37
+
38
+ // JS to add role and aria-label to content-wrapper, second-column, and third-column
39
+ const addAria = () => {
40
+ contentWrapper.setAttribute("role", "main");
41
+ if (secondColumn) {
42
+ secondColumn.setAttribute("role", "region");
43
+ secondColumn.setAttribute("aria-label", "Second column");
44
+ }
45
+ if (thirdColumn) {
46
+ thirdColumn.setAttribute("role", "region");
47
+ thirdColumn.setAttribute("aria-label", "Third column");
48
+ }
49
+ };
50
+ addAria();
51
+
52
+ // Clean up HTML
53
+ const cleanMarkup = () => {
54
+ // Remove role="presentation" attr from any element that has it
55
+ if (rolePres) {
56
+ rolePres.forEach((roleElem) => roleElem.removeAttribute("role"));
57
+ }
58
+ // Set functino to remove atrributes from elements
59
+ const discardAttributes = (element, ...attributes) => {
60
+ attributes.forEach((attribute) => element.removeAttribute(attribute));
61
+ }
62
+ // Remove attributes from tables
63
+ const tableElems = document.querySelectorAll("table, thead, tbody, tr, th, td");
64
+ tableElems.forEach((elem) => {
65
+ discardAttributes(elem, "cellspacing", "cellpadding", "width", "style");
66
+ });
67
+ };
68
+ cleanMarkup();
69
+
70
+ // Helper JS for Responsive Tables
71
+ const initResponsiveTables = () => {
72
+ const tables = document.querySelectorAll(".display, .display-lg")
73
+ for (let table = 0; table < tables.length; table++) {
74
+ let headertext = [],
75
+ headers = tables[table].querySelectorAll(".display table th, table.display th, .display-lg table th, table.display-lg th"),
76
+ tablebody = tables[table].querySelector(".display table tbody, table.display tbody, .display-lg table tbody, table.display-lg tbody");
77
+ for (let header = 0; header < headers.length; header++) {
78
+ let current = headers[header];
79
+ headertext.push(current.textContent.replace(/\r?\n|\r/, ""));
80
+ }
81
+ for (let y = 0, row; row = tablebody.rows[y]; y++) {
82
+ for (let j = 0, col; col = row.cells[j]; j++) {
83
+ col.setAttribute("data-th", headertext[j]);
84
+ }
85
+ }
86
+ }
87
+ }
88
+ initResponsiveTables();
89
+
90
+ // This is called by anchor links via onlick="" in the HTML
91
+ // Added because default anchor links don't work on all browsers using D2L
92
+ const addScript = (script) => {
93
+ let newScript = document.createElement("script");
94
+ newScript.setAttribute("src", script);
95
+
96
+ document.body.append(newScript);
97
+ }
98
+
99
+ if(document.querySelector("[onclick]")) {
100
+ addScript("https://cdn.jsdelivr.net/npm/@pimaonline/pimaonline-themepack/dist/js/jumpTo.js");
101
+ }
102
+
103
+ // Image gallery
104
+ const callImageGallery = () => {
105
+ // Create link element with font-awesome cdn and append it to the <head>
106
+ const docHead = document.querySelector("head");
107
+ const fontAwesomeCdn = document.createElement("link");
108
+ fontAwesomeCdn.setAttribute("rel", "stylesheet");
109
+ fontAwesomeCdn.setAttribute("href", "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css");
110
+ docHead.appendChild(fontAwesomeCdn);
111
+ // Begin image gallery
112
+ const imgGalleries = document.querySelectorAll(".image-gallery"),
113
+ imgBoxes = document.querySelectorAll(".image-box"),
114
+ modalBoxContent = `<div class="modal-box invisible">
115
+ <div class="gallery-overlay"></div>
116
+ <figure class="modal-box--image"><i class="fa-solid fa-x close-img"></i> <img src="#" alt="image here" /><figcaption class="img-caption"></figcaption></figure>
117
+ </div>
118
+ <button class="hide-gallery">Hide</button>`;
119
+
120
+ // createModalBox.innerHTML = modalBoxContent;
121
+ for (let imgGallery = 0; imgGallery < imgGalleries.length; imgGallery++) {
122
+ imgGalleries[imgGallery].insertAdjacentHTML("afterbegin", modalBoxContent);
123
+ }
124
+
125
+ if (document.querySelector(".modal-box")) {
126
+ const overlay = document.querySelector(".gallery-overlay"),
127
+ modalBox = document.querySelector(".modal-box"),
128
+ modalImg = document.querySelector(".modal-box--image img"),
129
+ modalCaption = document.querySelector(".img-caption"),
130
+ closeImg = document.querySelector(".close-img");
131
+
132
+ for (let imgBox = 0; imgBox < imgBoxes.length; imgBox++) {
133
+ imgBoxes[imgBox].onclick = function () {
134
+ modalBox.classList.remove("invisible");
135
+ let imgSrc = this.querySelector("img").src;
136
+ modalImg.src = imgSrc;
137
+ let imgCaption = this.querySelector("img").alt;
138
+ modalCaption.innerHTML = imgCaption;
139
+ }
140
+ }
141
+ overlay.onclick = () => {
142
+ modalBox.classList.add("invisible");
143
+ }
144
+ window.onkeydown = (esc) => {
145
+ if (esc.keyCode === 27) {
146
+ modalBox.classList.add("invisible");
147
+ }
148
+ }
149
+ closeImg.onclick = () => {
150
+ modalBox.classList.add("invisible");
151
+ }
152
+ const hideGalleries = document.querySelectorAll(".hide-gallery");
153
+ for (let hideGallery = 0; hideGallery < hideGalleries.length; hideGallery++) {
154
+ hideGalleries[hideGallery].addEventListener("click", () => {
155
+ hideGalleries[hideGallery].nextElementSibling.classList.toggle("invisible");
156
+ if (hideGalleries[hideGallery].innerHTML === "Hide") {
157
+ hideGalleries[hideGallery].innerHTML = "Show";
158
+ } else {
159
+ hideGalleries[hideGallery].innerHTML = "Hide";
160
+ }
161
+ });
162
+ }
163
+ };
164
+ }
165
+ if (imageGallery) {
166
+ callImageGallery();
167
+ }
168
+
169
+ // Vocab list widget
170
+ const callVocabList = () => {
171
+ if (vocabCloseBtns) {
172
+ for(let btn = 0; btn < vocabCloseBtns.length; btn++) {
173
+ vocabCloseBtns[btn].addEventListener("click", () => {
174
+ for(let node = 0; node < vocabLists[btn].children.length;node++) {
175
+ if(vocabLists[btn].children[node].tagName == "DD") {
176
+ vocabLists[btn].children[node].removeAttribute("style");
177
+ }
178
+ if(vocabLists[btn].children[node].tagName == "DT") {
179
+ vocabLists[btn].children[node].removeAttribute("class");
180
+ }
181
+ }});
182
+ }
183
+ }
184
+ for (let activeTerm = 0; activeTerm < vocabTerms.length; activeTerm++) {
185
+ vocabTerms[activeTerm].addEventListener("click", function() {
186
+ this.classList.toggle("active");
187
+ let termPanel = this.nextElementSibling;
188
+ if (termPanel.style.display === "block") { termPanel.removeAttribute("style"); }
189
+ else { termPanel.style.display = "block"; }
190
+ });
191
+
192
+ vocabTerms[activeTerm].addEventListener("keydown", function(e) {
193
+ if(e.key === "Enter") {
194
+ this.classList.toggle("active");
195
+ let termPanel = this.nextElementSibling;
196
+ if (termPanel.style.display === "block") { termPanel.removeAttribute("style"); }
197
+ else { termPanel.style.display = "block"; }
198
+ }
199
+ });
200
+ }
201
+ }
202
+ if (vocabListWidget) {callVocabList();}
203
+
204
+ //
205
+ const addMediaContainersAria = () => {
206
+ mediaContainers.forEach((eachContainer, index) => {
207
+ // loopID: find the current index value, convert it to its letter equivalent, then convert to lowercase
208
+ let loopId = String.fromCharCode(index + 65).toLowerCase();
209
+ let mediaObject = eachContainer.querySelector(".media-object");
210
+ let iframe = mediaObject.firstElementChild;
211
+ let mediaInfo = mediaObject.nextElementSibling;
212
+
213
+ // If element DOES NOT have "aria-describedby" && it DOES have a sibling element.
214
+ if (!iframe.hasAttribute("aria-describedby") && mediaInfo != null) {
215
+ iframe.setAttribute("aria-describedby", `${loopId}`);
216
+ mediaInfo.id = `${[loopId]}`;
217
+ }
218
+ });
219
+ }
220
+ if (mediaContainers) {addMediaContainersAria();}
221
+
222
+ //Tabs Widget
223
+ const callTabsWidget = () => {
224
+
225
+ let tabsWidgetsNum = 0;
226
+
227
+ tabsWidgets.forEach((tab,index) => {
228
+ let tabInputs = tab.querySelectorAll("input")
229
+ let tabLabels = tab.querySelectorAll("label")
230
+ let tabDivs = tab.querySelectorAll("div")
231
+
232
+ let groupNum = index + 1;
233
+
234
+ //Add region and aria-label to parent div
235
+ tab.setAttribute("role", "region");
236
+ tab.setAttribute("aria-label", `tab group ${groupNum}`)
237
+
238
+ for(tabIndex = 0; tabIndex < tabInputs.length; tabIndex++) {
239
+
240
+ let tabNum = tabsWidgetsNum + 1;
241
+
242
+ //Add class, id, name, and aria-described by for inputs
243
+ tabInputs[tabIndex].classList.add("tab-input");
244
+ tabInputs[tabIndex].setAttribute("type", "radio")
245
+ tabInputs[tabIndex].setAttribute("id", `tab${tabNum}`);
246
+ tabInputs[tabIndex].setAttribute("name", `hint-group-${groupNum}` )
247
+ tabInputs[tabIndex].setAttribute("aria-describedby", `tabHeading${tabNum}`)
248
+ //Add class and for for labels
249
+ tabLabels[tabIndex].classList.add("tab-header");
250
+ tabLabels[tabIndex].setAttribute("for", `tab${tabNum}`)
251
+ //Add class, tabindex, and id for divs
252
+ tabDivs[tabIndex].classList.add("tab-panel")
253
+ tabDivs[tabIndex].setAttribute("tabindex", 0)
254
+ tabDivs[tabIndex].setAttribute("id", `tabHeading${tabNum}`)
255
+ //Add attributes for hide tab
256
+ if(tabIndex + 1 == tabInputs.length) {
257
+ tabLabels[tabIndex].classList.add("hide-tab")
258
+ tabInputs[tabIndex].checked = true;
259
+ tabDivs[tabIndex].classList.add("hide-panel")
260
+ }
261
+ tabsWidgetsNum++;
262
+ }
263
+ })
264
+ }
265
+ if (tabsWidgets) {callTabsWidget();}
266
+
267
+ // Toggle footnotes
268
+ const toggleBtns = document.querySelectorAll(".toggle-btn, .toggle-footnotes");
269
+
270
+ if (document.querySelector(".toggle-btn") || document.querySelector(".toggle-footnotes")) {
271
+ for (let toggleBtn = 0; toggleBtn < toggleBtns.length; toggleBtn++) {
272
+ // Add tabindex
273
+ toggleBtns[toggleBtn].setAttribute("tabindex", "0");
274
+
275
+ // Show/hide on click
276
+ toggleBtns[toggleBtn].addEventListener("click", () => {
277
+ toggleBtns[toggleBtn].nextElementSibling.classList.toggle("show");
278
+ })
279
+
280
+ // Show/hide on enter for users who use tab
281
+ toggleBtns[toggleBtn].addEventListener("keydown", (enter) => {
282
+ if (enter.keyCode === 13) {
283
+ toggleBtns[toggleBtn].nextElementSibling.classList.toggle("show");
284
+ }
285
+ })
286
+ }
287
+ }
288
+
289
+ // Call function with jQuery scripts
290
+ const callJquery = () => {
291
+ // Toggle Button's Arrow Right Points Down on Click
292
+ $('.arrow-right').on('click', function () {
293
+ $(this).toggleClass('arrow-down');
294
+ });
295
+ // TOOLTIP
296
+ // Allows Screen readers to toggle a tooltip on click and to say if the tooltip is collapsed or expanded.
297
+ $(".tooltip").click(function () {
298
+ $(this).children(".tip-hover").toggle();
299
+ if ($(this).children(".tip-hover").is(':visible')) {
300
+ $(this).attr('aria-expanded', 'true');
301
+ $(this).removeClass('hidden');
302
+ } else {
303
+ $(this).attr('aria-expanded', 'false');
304
+ $(this).addClass('hidden');
305
+ }
306
+ });
307
+ let start = 999;
308
+ $('.tooltip').each(function (i) {
309
+ $(this).css('z-index', start--);
310
+ });
311
+ $(".tooltip .video-container").parent().css("width", "450px");
312
+ }
313
+ callJquery();
314
+
315
+ // Fancybox
316
+ if (document.querySelector(".fancybox")) {
317
+ $("[data-fancybox]").fancybox({
318
+ idleTime: false,
319
+ topRatio: 0.1,
320
+ helpers: {
321
+ title: {
322
+ type: 'inside'
323
+ },
324
+ }
325
+ });
326
+ }
327
327
  });