kcc-gem-theme-original 1.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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +142 -0
- data/_data/navigation.yml +154 -0
- data/_includes/accordion.html +36 -0
- data/_includes/accordion_path-sorting.html +29 -0
- data/_includes/body.html +5 -0
- data/_includes/breadcrumbs.html +44 -0
- data/_includes/card-section.html +26 -0
- data/_includes/chat-now.html +8 -0
- data/_includes/contacts-tan.html +94 -0
- data/_includes/contacts.html +96 -0
- data/_includes/document-head.html +25 -0
- data/_includes/emergency-alerts.html +29 -0
- data/_includes/foot.html +3 -0
- data/_includes/footer.html +193 -0
- data/_includes/hash/theme_hash.yml +1 -0
- data/_includes/hero-slider.html +36 -0
- data/_includes/nav-global.html +40 -0
- data/_includes/nav-local.html +34 -0
- data/_includes/nav-sub.html +19 -0
- data/_includes/preconnect.html +16 -0
- data/_includes/scripts/custom.html +4 -0
- data/_includes/scripts/google-api.html +2 -0
- data/_includes/scripts/google-noscript.html +9 -0
- data/_includes/scripts/google-tag.html +23 -0
- data/_includes/scripts/kcc-alerts.html +2 -0
- data/_includes/scripts/kcc-mega-nav.html +2 -0
- data/_includes/scripts/kcc-nav.html +2 -0
- data/_includes/scripts/kcc-theme-landing.html +2 -0
- data/_includes/scripts/kcc-theme.html +2 -0
- data/_includes/scripts/table-cdn.html +6 -0
- data/_includes/scripts/translate.html +11 -0
- data/_includes/scripts/vendor.html +8 -0
- data/_includes/styles/fonts.html +4 -0
- data/_includes/styles/main.html +6 -0
- data/_includes/styles/vendor.html +8 -0
- data/_includes/svg/check.html +11 -0
- data/_includes/svg/check_circle-24px.html +13 -0
- data/_includes/svg/email-24px.html +13 -0
- data/_includes/svg/goals.html +21 -0
- data/_includes/svg/kcc-copy.html +62 -0
- data/_includes/svg/kcc.html +65 -0
- data/_includes/svg/kcc.svg +59 -0
- data/_includes/svg/love.html +13 -0
- data/_includes/svg/place-24px.html +13 -0
- data/_includes/svg/save-money.html +26 -0
- data/_includes/tabbed-content.html +27 -0
- data/_includes/translate.html +3 -0
- data/_layouts/default.html +31 -0
- data/_layouts/markdown.html +13 -0
- data/_layouts/page.html +8 -0
- data/_layouts/sub-nav.html +6 -0
- data/assets/css/content.css +1 -0
- data/assets/css/main.css +1 -0
- data/assets/img/alert.svg +1 -0
- data/assets/img/arrow-right.svg +1 -0
- data/assets/img/arrow_right_alt.svg +1 -0
- data/assets/img/blank-contact.svg +1 -0
- data/assets/img/blue-next.svg +1 -0
- data/assets/img/blue-prev.svg +1 -0
- data/assets/img/dbl-next.svg +1 -0
- data/assets/img/dbl-next_mobile.svg +1 -0
- data/assets/img/dbl-prev.svg +1 -0
- data/assets/img/dbl-prev_mobile.svg +1 -0
- data/assets/img/facebook-f_white.svg +1 -0
- data/assets/img/facebook.svg +1 -0
- data/assets/img/heading-bg-underline-tan.png +0 -0
- data/assets/img/heading-bg-underline-transparent.png +0 -0
- data/assets/img/heading-bg-underline.png +0 -0
- data/assets/img/home.svg +8 -0
- data/assets/img/iccmc-logo_blue-transparent.png +0 -0
- data/assets/img/instagram-white.svg +1 -0
- data/assets/img/instagram.svg +1 -0
- data/assets/img/itransfer.png +0 -0
- data/assets/img/kankakee-community-college-blue.svg +1 -0
- data/assets/img/kankakee-community-college-word-logo.svg +1 -0
- data/assets/img/kcc-logo-inverse.svg +1 -0
- data/assets/img/kcc-logo-white.svg +1 -0
- data/assets/img/kcc-logo.svg +1 -0
- data/assets/img/kcc-placeholder-square.png +0 -0
- data/assets/img/kcc-placeholder.png +0 -0
- data/assets/img/kcc-text-logo-white.svg +1 -0
- data/assets/img/kcc-text-logo.svg +1 -0
- data/assets/img/keyboard_arrow_right.svg +1 -0
- data/assets/img/linkedin-white.svg +1 -0
- data/assets/img/linkedin.svg +1 -0
- data/assets/img/pause.svg +1 -0
- data/assets/img/pause_mobile.svg +1 -0
- data/assets/img/pinterest-p_white.svg +1 -0
- data/assets/img/pinterest.svg +1 -0
- data/assets/img/placeholder_16to9.jpg +0 -0
- data/assets/img/placeholder_4by3.jpg +0 -0
- data/assets/img/placeholder_square-1by1.jpg +0 -0
- data/assets/img/placeholder_square.jpg +0 -0
- data/assets/img/play.svg +1 -0
- data/assets/img/play_mobile.svg +1 -0
- data/assets/img/search.svg +1 -0
- data/assets/img/social-icon.svg +1 -0
- data/assets/img/twitter.svg +1 -0
- data/assets/img/video.svg +1 -0
- data/assets/img/volleyball.svg +1 -0
- data/assets/img/x-logo.svg +11 -0
- data/assets/img/x.svg +1 -0
- data/assets/img/xitter.svg +1 -0
- data/assets/img/youtube-white.svg +1 -0
- data/assets/img/youtube.svg +1 -0
- data/assets/img/yt-loading.png +0 -0
- data/assets/js/dist/102.197fcdd9ea9a90f7ba8e.bundle.js +1 -0
- data/assets/js/dist/13.197fcdd9ea9a90f7ba8e.bundle.js +2 -0
- data/assets/js/dist/13.197fcdd9ea9a90f7ba8e.bundle.js.LICENSE.txt +5 -0
- data/assets/js/dist/143.197fcdd9ea9a90f7ba8e.bundle.js +1 -0
- data/assets/js/dist/183.197fcdd9ea9a90f7ba8e.bundle.js +1 -0
- data/assets/js/dist/3.197fcdd9ea9a90f7ba8e.bundle.js +1 -0
- data/assets/js/dist/3.197fcdd9ea9a90f7ba8e.css +1 -0
- data/assets/js/dist/303.197fcdd9ea9a90f7ba8e.bundle.js +1 -0
- data/assets/js/dist/384.197fcdd9ea9a90f7ba8e.bundle.js +1 -0
- data/assets/js/dist/453.197fcdd9ea9a90f7ba8e.bundle.js +2 -0
- data/assets/js/dist/453.197fcdd9ea9a90f7ba8e.bundle.js.LICENSE.txt +5 -0
- data/assets/js/dist/635.197fcdd9ea9a90f7ba8e.bundle.js +2 -0
- data/assets/js/dist/635.197fcdd9ea9a90f7ba8e.bundle.js.LICENSE.txt +29 -0
- data/assets/js/dist/723.197fcdd9ea9a90f7ba8e.bundle.js +1 -0
- data/assets/js/dist/873.197fcdd9ea9a90f7ba8e.bundle.js +1 -0
- data/assets/js/dist/965.197fcdd9ea9a90f7ba8e.bundle.js +1 -0
- data/assets/js/dist/bootstrap.197fcdd9ea9a90f7ba8e.bundle.js +0 -0
- data/assets/js/dist/bootstrap.197fcdd9ea9a90f7ba8e.css +1 -0
- data/assets/js/dist/theme.197fcdd9ea9a90f7ba8e.bundle.js +2 -0
- data/assets/js/dist/theme.197fcdd9ea9a90f7ba8e.bundle.js.LICENSE.txt +47 -0
- data/assets/js/dist/theme.197fcdd9ea9a90f7ba8e.css +1 -0
- data/assets/js/nav/closeNavOnClick.js +22 -0
- data/assets/js/nav/highlightCurrentNav.js +44 -0
- data/assets/js/nav/moveSearchIcon.js +94 -0
- data/assets/js/nav/nav.js +13 -0
- data/assets/js/nav/searchToggleNav.js +46 -0
- data/assets/js/nav/toggleNavSearchDropdownOnWindowResize.js +52 -0
- data/assets/js/src/alerts.js +24 -0
- data/assets/js/src/all.js +83 -0
- data/assets/js/src/bootstrap.js +4 -0
- data/assets/js/src/cacheResponse.js +22 -0
- data/assets/js/src/campusAlertsSheetsAPI.js +53 -0
- data/assets/js/src/checkForPrefersReducedMotion.js +17 -0
- data/assets/js/src/contentHashLink.js +102 -0
- data/assets/js/src/createAlertsHtml.js +46 -0
- data/assets/js/src/footerDate.js +13 -0
- data/assets/js/src/getCachedResponse.js +37 -0
- data/assets/js/src/lazyLoad.js +13 -0
- data/assets/js/src/parseMarkdownToHTML.js +85 -0
- data/assets/js/src/sliders.js +81 -0
- data/assets/js/src/translate.js +62 -0
- data/assets/js/src/walkText.js +31 -0
- data/assets/js/src/wrapPowerText.js +11 -0
- data/assets/js/src/ytEmbed.js +30 -0
- data/assets/scss/0-tools/_bootstrap-overrides.scss +72 -0
- data/assets/scss/0-tools/_cloudcannon.scss +16 -0
- data/assets/scss/0-tools/_google-translate-overrides.scss +127 -0
- data/assets/scss/0-tools/_gsc-overrides.scss +144 -0
- data/assets/scss/0-tools/_vars.scss +72 -0
- data/assets/scss/1-base/_background.scss +5 -0
- data/assets/scss/1-base/_buttons.scss +121 -0
- data/assets/scss/1-base/_html.scss +4 -0
- data/assets/scss/1-base/_img.scss +12 -0
- data/assets/scss/1-base/_links.scss +126 -0
- data/assets/scss/1-base/_svg.scss +82 -0
- data/assets/scss/1-base/_typography.scss +640 -0
- data/assets/scss/2-modules/_accordion.scss +43 -0
- data/assets/scss/2-modules/_benefits.scss +371 -0
- data/assets/scss/2-modules/_breadcrumbs.scss +32 -0
- data/assets/scss/2-modules/_campus-alerts.scss +3 -0
- data/assets/scss/2-modules/_card-section.scss +9 -0
- data/assets/scss/2-modules/_contacts.scss +46 -0
- data/assets/scss/2-modules/_error.scss +10 -0
- data/assets/scss/2-modules/_footer.scss +122 -0
- data/assets/scss/2-modules/_header.scss +21 -0
- data/assets/scss/2-modules/_hero-slider.scss +331 -0
- data/assets/scss/2-modules/_img-hover.scss +70 -0
- data/assets/scss/2-modules/_loader.scss +9 -0
- data/assets/scss/2-modules/_nav-global.scss +315 -0
- data/assets/scss/2-modules/_nav-landing.scss +203 -0
- data/assets/scss/2-modules/_nav-local.scss +45 -0
- data/assets/scss/2-modules/_social-icons.scss +36 -0
- data/assets/scss/2-modules/_sub-nav.scss +32 -0
- data/assets/scss/2-modules/_yt-embed.scss +14 -0
- data/assets/scss/3-layout/_background.scss +3 -0
- data/assets/scss/3-layout/_content.scss +37 -0
- data/assets/scss/3-layout/_margins.scss +22 -0
- data/assets/scss/3-layout/_padding.scss +19 -0
- data/assets/scss/3-layout/_positioning.scss +343 -0
- data/assets/scss/3-layout/_section.scss +22 -0
- data/assets/scss/3-layout/_tables.scss +8 -0
- data/assets/scss/3-layout/_thank-you.scss +5 -0
- data/assets/scss/4-pages/index/_home.scss +15 -0
- data/assets/scss/bootstrap.scss +98 -0
- data/assets/scss/kcc-theme.scss +50 -0
- data/assets/scss/translate.scss +5 -0
- metadata +278 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
const navLinks = '.nav-link:not(.dropdown-toggle)'; // Bootstrap 4 class
|
2
|
+
|
3
|
+
function hideBootstrapMenu(menu, Collapse) {
|
4
|
+
const bsCollapse = new Collapse(menu, { toggle: false });
|
5
|
+
|
6
|
+
bsCollapse.hide();
|
7
|
+
}
|
8
|
+
|
9
|
+
function closeMenuOnClick(Collapse) {
|
10
|
+
document.addEventListener('click', e => {
|
11
|
+
if ( !e.target.matches(navLinks) || e.target.classList.contains('dropdown-toggle') ) // Bail out of the rest of the code if the click event's target is not what we want!
|
12
|
+
return;
|
13
|
+
|
14
|
+
const menu = document.getElementById('mainNavContent');
|
15
|
+
|
16
|
+
if (menu.classList.contains('show')) {
|
17
|
+
hideBootstrapMenu(menu, Collapse);
|
18
|
+
}
|
19
|
+
});
|
20
|
+
}
|
21
|
+
|
22
|
+
export default closeMenuOnClick;
|
@@ -0,0 +1,44 @@
|
|
1
|
+
// Custom Vanilla JS to highlight the user's current location in the navigation bar and the sub-nav navigation bar
|
2
|
+
function setActive(link) {
|
3
|
+
const li = link.parentNode;
|
4
|
+
|
5
|
+
li.classList.add('active');
|
6
|
+
link.insertAdjacentHTML('beforeend', ' <span class="visually-hidden">(current)</span>');
|
7
|
+
}
|
8
|
+
|
9
|
+
function checkNavLinks(navList) {
|
10
|
+
const pathname = window.location.pathname;
|
11
|
+
const locationIsContactHash = window.location.hash === '#contact';
|
12
|
+
const locationIsHome = window.location.pathname === '/';
|
13
|
+
|
14
|
+
[...navList].forEach(item => {
|
15
|
+
const link = item.querySelector('a');
|
16
|
+
const href = link.getAttribute('href').replace(/^\/?\.\.\/(\.\.\/)?(\.\.\/)?/g, '/');
|
17
|
+
const linkIsHome = link.textContent.toLowerCase() === 'home';
|
18
|
+
const linkIsMatch = (pathname.indexOf(href) !== -1);
|
19
|
+
|
20
|
+
if (locationIsHome || locationIsContactHash) {
|
21
|
+
if (linkIsHome) {
|
22
|
+
setActive(link);
|
23
|
+
}
|
24
|
+
} else {
|
25
|
+
if (linkIsMatch && !linkIsHome) {
|
26
|
+
setActive(link);
|
27
|
+
}
|
28
|
+
}
|
29
|
+
});
|
30
|
+
}
|
31
|
+
|
32
|
+
function highlightNav() {
|
33
|
+
const navList = document.querySelectorAll('.js-nav-item');
|
34
|
+
|
35
|
+
if (document.getElementById('subNavNav')) {
|
36
|
+
const subNavList = document.querySelectorAll('.js-sub-nav-item');
|
37
|
+
|
38
|
+
checkNavLinks(subNavList);
|
39
|
+
}
|
40
|
+
|
41
|
+
checkNavLinks(navList);
|
42
|
+
}
|
43
|
+
|
44
|
+
export default highlightNav;
|
@@ -0,0 +1,94 @@
|
|
1
|
+
function checkXIcon() {
|
2
|
+
const checkXIconOnLoad = (function() {
|
3
|
+
let executed = false;
|
4
|
+
return function() {
|
5
|
+
if (!executed) {
|
6
|
+
executed = true;
|
7
|
+
// do checkXIconOnLoad
|
8
|
+
const icon = document.getElementById('xIcon');
|
9
|
+
const xIsHidden = icon.getAttribute('style') === 'display: none;';
|
10
|
+
xIsHidden ? removeClear() : clearXIcon();
|
11
|
+
}
|
12
|
+
};
|
13
|
+
})();
|
14
|
+
checkXIconOnLoad(); // "do checkXIconOnLoad" happens
|
15
|
+
}
|
16
|
+
|
17
|
+
function clearXIcon() {
|
18
|
+
const targetEl = document.querySelector('button.gsc-search-button-v2');
|
19
|
+
targetEl.classList.add('gsc-overrides__clear-x');
|
20
|
+
}
|
21
|
+
|
22
|
+
function removeClear() {
|
23
|
+
const targetEl = document.querySelector('button.gsc-search-button-v2');
|
24
|
+
targetEl.classList.remove('gsc-overrides__clear-x');
|
25
|
+
}
|
26
|
+
|
27
|
+
function addId() {
|
28
|
+
const xIcon = document.querySelector('.gsst_a');
|
29
|
+
xIcon.setAttribute('id', 'xIcon');
|
30
|
+
}
|
31
|
+
|
32
|
+
function gscInit() {
|
33
|
+
var cx = '006320264078644364913:sy48bet-lr8';
|
34
|
+
var gcse = document.createElement('script');
|
35
|
+
gcse.type = 'text/javascript';
|
36
|
+
gcse.async = true;
|
37
|
+
gcse.src = 'https://cse.google.com/cse.js?cx=' + cx;
|
38
|
+
var s = document.getElementsByTagName('script')[0];
|
39
|
+
s.parentNode.insertBefore(gcse, s);
|
40
|
+
}
|
41
|
+
|
42
|
+
function moveSearchIcon() {
|
43
|
+
const pageHasGSearch = document.getElementById('searchCollapse');
|
44
|
+
|
45
|
+
if ( pageHasGSearch ) {
|
46
|
+
let initSearchPromise = new Promise((resolve, reject) => {
|
47
|
+
gscInit();
|
48
|
+
resolve();
|
49
|
+
});
|
50
|
+
initSearchPromise.then(() => {
|
51
|
+
|
52
|
+
let addIdPromise = new Promise((resolve, reject) => {
|
53
|
+
|
54
|
+
const targetNode = document.getElementById('searchCollapse');
|
55
|
+
const config = { attributes: true, childList: true, subtree: true };
|
56
|
+
const callback = function(mutationsList, observer) {
|
57
|
+
for(const mutation of mutationsList) {
|
58
|
+
if (mutation.type == 'childList') {
|
59
|
+
addId();
|
60
|
+
resolve();
|
61
|
+
}
|
62
|
+
}
|
63
|
+
};
|
64
|
+
const observer = new MutationObserver(callback);
|
65
|
+
observer.observe(targetNode, config);
|
66
|
+
// Later, you can stop observing
|
67
|
+
//observer.disconnect();
|
68
|
+
});
|
69
|
+
addIdPromise.then(() => {
|
70
|
+
checkXIcon();
|
71
|
+
const targetNode = document.getElementById('xIcon');
|
72
|
+
const config = { attributes: true, childList: true, subtree: true };
|
73
|
+
const callback = function(mutationsList, observer) {
|
74
|
+
for(const mutation of mutationsList) {
|
75
|
+
if (mutation.type == 'attributes') {
|
76
|
+
const xIsHidden = targetNode.getAttribute('style') === 'display: none;';
|
77
|
+
if (xIsHidden) {
|
78
|
+
removeClear();
|
79
|
+
} else {
|
80
|
+
clearXIcon();
|
81
|
+
}
|
82
|
+
}
|
83
|
+
}
|
84
|
+
};
|
85
|
+
const observer = new MutationObserver(callback);
|
86
|
+
observer.observe(targetNode, config);
|
87
|
+
// Later, you can stop observing
|
88
|
+
//observer.disconnect();
|
89
|
+
});
|
90
|
+
});
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
export default moveSearchIcon;
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import highlightNav from './highlightCurrentNav.js';
|
2
|
+
import searchToggle from './searchToggleNav.js';
|
3
|
+
import moveSearchIcon from './moveSearchIcon.js';
|
4
|
+
// import closeMenuOnClick from './closeNavOnClick.js';
|
5
|
+
import toggleSearchDropdownOnWindowResize from './toggleNavSearchDropdownOnWindowResize.js';
|
6
|
+
|
7
|
+
|
8
|
+
export default function nav() {
|
9
|
+
highlightNav();
|
10
|
+
searchToggle();
|
11
|
+
moveSearchIcon();
|
12
|
+
toggleSearchDropdownOnWindowResize();
|
13
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
// Custom JS to toggle the search form on mobile devices
|
2
|
+
const mainNav = document.getElementById('mainNav');
|
3
|
+
const globalNav = document.getElementById('globalNav');
|
4
|
+
|
5
|
+
function switchToX(icon, button) {
|
6
|
+
icon.style.backgroundImage = 'url("/assets/img/x.svg")';
|
7
|
+
icon.setAttribute('alt', 'Close icon');
|
8
|
+
button.setAttribute('aria-label', 'Close search');
|
9
|
+
}
|
10
|
+
|
11
|
+
function switchToSearch(icon, button) {
|
12
|
+
icon.style.backgroundImage = 'url("/assets/img/search.svg")';
|
13
|
+
icon.setAttribute('alt', 'Search icon');
|
14
|
+
button.setAttribute('aria-label', 'Open search');
|
15
|
+
}
|
16
|
+
|
17
|
+
function searchToggle() {
|
18
|
+
if (!document.getElementById('searchIcon'))
|
19
|
+
return;
|
20
|
+
|
21
|
+
const searchButton = document.getElementById('searchIcon');
|
22
|
+
|
23
|
+
document.addEventListener('click', function (e) {
|
24
|
+
// If the clicked element doesn't have the right selector, bail
|
25
|
+
if (!e.target.closest('#searchIcon')) return;
|
26
|
+
// Don't follow the link
|
27
|
+
e.preventDefault();
|
28
|
+
|
29
|
+
const searchIconElement = document.getElementById('searchImg');
|
30
|
+
const searchCollapse = document.getElementById('searchCollapse');
|
31
|
+
const searchIconBackgroundImage = searchIconElement.style.backgroundImage;
|
32
|
+
const iconIsSearch = (searchIconBackgroundImage.indexOf('assets/img/search.svg') != -1);
|
33
|
+
|
34
|
+
if (iconIsSearch) {
|
35
|
+
switchToX(searchIconElement, searchButton);
|
36
|
+
searchCollapse.setAttribute('aria-hidden', 'false');
|
37
|
+
} else {
|
38
|
+
switchToSearch(searchIconElement, searchButton);
|
39
|
+
searchCollapse.setAttribute('aria-hidden', 'true');
|
40
|
+
}
|
41
|
+
searchCollapse.classList.toggle('nav-global__search-collapse--visible');
|
42
|
+
mainNav.classList.toggle('nav-local__search-toggle');
|
43
|
+
globalNav.classList.toggle('nav-global__search-toggle');
|
44
|
+
}, false);
|
45
|
+
}
|
46
|
+
export default searchToggle;
|
@@ -0,0 +1,52 @@
|
|
1
|
+
// Custom JS to Close the Navigation menu, if its open, & if the screen goes above 992px wide (Bootstrap 4 'lg' devices)
|
2
|
+
const searchCollapseVisibleClass = 'nav-global__search-collapse--visible'; // Class in the HTML when the search collapse is open/visible
|
3
|
+
const globalNavSearchVisibleClass = 'nav-global__search-toggle';
|
4
|
+
const localNavSearchVisibleClass = 'nav-local__search-toggle';
|
5
|
+
|
6
|
+
function removeClassFromElement(el, classToRemove) {
|
7
|
+
el.classList.remove(classToRemove);
|
8
|
+
}
|
9
|
+
|
10
|
+
function checkElementCollapseState(el, classToCheckFor) {
|
11
|
+
if ( ! el.classList.contains(classToCheckFor) )
|
12
|
+
return;
|
13
|
+
|
14
|
+
removeClassFromElement(el, classToCheckFor);
|
15
|
+
}
|
16
|
+
|
17
|
+
function toggleSearchIconToX(searchIcon) {
|
18
|
+
const searchSpan = searchIcon.querySelector('#searchImg');
|
19
|
+
|
20
|
+
searchIcon.setAttribute('aria-label', 'Toggle Search');
|
21
|
+
searchSpan.setAttribute('alt', 'Open icon');
|
22
|
+
searchSpan.setAttribute('style', 'background-image: url("/assets/img/search.svg")');
|
23
|
+
}
|
24
|
+
|
25
|
+
function checkSearchToggleIcon(searchIcon) {
|
26
|
+
let ariaLabel = searchIcon.getAttribute('aria-label');
|
27
|
+
|
28
|
+
if ( ! ariaLabel === 'Toggle Close' )
|
29
|
+
return;
|
30
|
+
|
31
|
+
toggleSearchIconToX(searchIcon);
|
32
|
+
}
|
33
|
+
|
34
|
+
function windowResizeHandler() {
|
35
|
+
if ( window.innerWidth >= 992 ) {
|
36
|
+
const searchCollapseElement = document.getElementById('searchCollapse');
|
37
|
+
const globalNav = document.getElementById('globalNav');
|
38
|
+
const localNav = document.getElementById('mainNav');
|
39
|
+
const searchIcon = document.getElementById('searchIcon');
|
40
|
+
|
41
|
+
checkElementCollapseState(searchCollapseElement, searchCollapseVisibleClass);
|
42
|
+
checkElementCollapseState(globalNav, globalNavSearchVisibleClass);
|
43
|
+
checkElementCollapseState(localNav, localNavSearchVisibleClass);
|
44
|
+
checkSearchToggleIcon(searchIcon);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
function toggleSearchDropdownOnWindowResize() {
|
49
|
+
window.addEventListener('resize', windowResizeHandler);
|
50
|
+
}
|
51
|
+
|
52
|
+
export default toggleSearchDropdownOnWindowResize;
|
@@ -0,0 +1,24 @@
|
|
1
|
+
/*
|
2
|
+
// Custom JS | written by https://github.com/wdzajicek
|
3
|
+
// © 2020 Kankakee Community College
|
4
|
+
// =================================================== */
|
5
|
+
import start from './campusAlertsSheetsAPI.js';
|
6
|
+
import getCachedResponse from './getCachedResponse.js';
|
7
|
+
import checkForPrefersReducedMotion from './checkForPrefersReducedMotion.js';
|
8
|
+
|
9
|
+
function alerts(Collapse) {
|
10
|
+
checkForPrefersReducedMotion();
|
11
|
+
|
12
|
+
// Checks if our cached alert is already in sessionStorage
|
13
|
+
if (window.sessionStorage.getItem('Alert-Content')) {
|
14
|
+
// If not, build the alert from a new Google API response
|
15
|
+
gapi.load('client', () => {
|
16
|
+
start(Collapse);
|
17
|
+
});
|
18
|
+
} else {
|
19
|
+
// Otherwise, build the alert from our cached response
|
20
|
+
getCachedResponse(Collapse);
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
export default alerts;
|
@@ -0,0 +1,83 @@
|
|
1
|
+
import '../../scss/kcc-theme.scss'; // Import scss file into webpack main entry-point for webpack compiled css
|
2
|
+
|
3
|
+
import Collapse from 'bootstrap/js/dist/collapse';
|
4
|
+
|
5
|
+
// function loadModule(...theArgs) {
|
6
|
+
// const len = theArgs.length;
|
7
|
+
// let module, defaultFn, path;
|
8
|
+
|
9
|
+
// module = theArgs[0];
|
10
|
+
// len == 2 ? path = theArgs[1] : len == 3 ? path = theArgs[2] : null;
|
11
|
+
// len == 2 ? defaultFn = module : defaultFn = theArgs[1];
|
12
|
+
// return import(`${path}${module}.js`).then(({ default: defaultFn }) => defaultFn() );
|
13
|
+
// }
|
14
|
+
|
15
|
+
window.addEventListener('load', async () => {
|
16
|
+
|
17
|
+
if (document.querySelector('[data-bs-toggle="dropdown"]')) {
|
18
|
+
// Dropdown does not need to be called to existing dropdown HTML markup work
|
19
|
+
const { default: Dropdown } = await import('bootstrap/js/dist/dropdown');
|
20
|
+
}
|
21
|
+
|
22
|
+
import('./alerts').then(({ default: alerts }) => alerts(Collapse));
|
23
|
+
|
24
|
+
import('../nav/nav').then(({ default: nav }) => nav());
|
25
|
+
|
26
|
+
if (document.getElementById('google_translate_element')) {
|
27
|
+
import('../../scss/translate.scss').then(() => {
|
28
|
+
import('./translate').then(({ default: translate }) => translate());
|
29
|
+
})
|
30
|
+
}
|
31
|
+
|
32
|
+
if (document.querySelector('.hero-slider__slider')) {
|
33
|
+
import('./wrapPowerText')
|
34
|
+
.then(({ default: wrapPowerText }) => wrapPowerText())
|
35
|
+
.then(() => {
|
36
|
+
import('./sliders').then(({ default: initSliders }) => initSliders())
|
37
|
+
})
|
38
|
+
}
|
39
|
+
|
40
|
+
if (document.querySelector('img[data-src]')) {
|
41
|
+
import('./lazyLoad').then(({ default: lazyLoad }) => lazyLoad());
|
42
|
+
}
|
43
|
+
|
44
|
+
if (document.getElementById('currentYear')) {
|
45
|
+
import('./footerDate')
|
46
|
+
.then(({ default: footerDate }) => footerDate());
|
47
|
+
}
|
48
|
+
|
49
|
+
import('./walkText').then(({ default: walkText }) => walkText(document.body));
|
50
|
+
|
51
|
+
if (document.querySelector('[data-bs-toggle="modal"]')) {
|
52
|
+
// This import enables modals in pages with modal HTML markup
|
53
|
+
const { default: Modal } = await import('bootstrap/js/dist/modal');
|
54
|
+
}
|
55
|
+
|
56
|
+
// loadModule('alerts','./').then(() => { // Get the campus alerts message & build it out
|
57
|
+
// loadModule('addClassToOpenNavbar', './');
|
58
|
+
// return;
|
59
|
+
// }).then(() => {
|
60
|
+
// if (document.getElementById('google_translate_element')) { // Check for elements used with Google Translate
|
61
|
+
// import('../../scss/translate.scss').then(() => { // Load custom styling for Google Translate conditionally
|
62
|
+
// loadModule('translate', 'watchForMenuClicks', './'); // Then load the custom translate JS for functionality
|
63
|
+
// });
|
64
|
+
// }
|
65
|
+
// }).then(() => {
|
66
|
+
// import('../nav/nav/nav').then(({ default: nav }) => nav()); // JS for custom navbar functionality
|
67
|
+
// });
|
68
|
+
|
69
|
+
// loadModule('wrapPowerText', './').then(() => {
|
70
|
+
// return loadModule('sliders', 'initSliders', './');
|
71
|
+
// }).then(() => {
|
72
|
+
// if (document.querySelector('img[data-src]')) {
|
73
|
+
// return loadModule('lazyLoad', './');
|
74
|
+
// }
|
75
|
+
// }).then(() => {
|
76
|
+
// return loadModule('footerDate', './');
|
77
|
+
// }).then(() => {
|
78
|
+
// import('./walkText').then(({default: walkText}) => {
|
79
|
+
// walkText(document.body); // walkText() needs an argument
|
80
|
+
// });
|
81
|
+
// });
|
82
|
+
|
83
|
+
});
|
@@ -0,0 +1,22 @@
|
|
1
|
+
/*
|
2
|
+
// Custom JS | written by https://github.com/wdzajicek
|
3
|
+
// © 2020 Kankakee Community College
|
4
|
+
// =================================================== */
|
5
|
+
// Modules' default function stores our Google Sheet response in sessionStorage to be retrieved later
|
6
|
+
// Each key gets set to a column in our data
|
7
|
+
// Each key's value gets set to the corresponding cell in the row below
|
8
|
+
// ====================================================================
|
9
|
+
function cacheResponse(response) { // response from Google API's spreadsheet.values.get() method
|
10
|
+
const values = response.result.values; // This is where the table's data is in a Sheets response in Sheets API V4
|
11
|
+
const [, headerRow, bodyRow] = values; // 1st row = instructions, 2nd row = header row, 3rd row = body row
|
12
|
+
|
13
|
+
for (let i = 0, len = bodyRow.length; i < len; i++ ) {
|
14
|
+
const cell = bodyRow[i];
|
15
|
+
const column = headerRow[i];
|
16
|
+
|
17
|
+
window.sessionStorage.setItem(column.replace(' ', '-'), cell);
|
18
|
+
}
|
19
|
+
//window.sessionStorage.clear();
|
20
|
+
}
|
21
|
+
|
22
|
+
export default cacheResponse;
|
@@ -0,0 +1,53 @@
|
|
1
|
+
/*
|
2
|
+
// Custom JS | written by https://github.com/wdzajicek
|
3
|
+
// © 2020 Kankakee Community College
|
4
|
+
// =================================================== */
|
5
|
+
// 1. Execute Google API call to grab Google Sheet data from:
|
6
|
+
// https://docs.google.com/spreadsheets/d/1plXBiZY5pVbhNT-mszxEuqCl4zy8wMnz9gXXbbT_yLs/edit#gid=0
|
7
|
+
// 2. Build & inject the alert message into the page
|
8
|
+
// 3. Run the `contentHashLink` module after alert has painted into DOM (and altered documents hight)
|
9
|
+
// 4. Cache the API response in sessionStorage
|
10
|
+
// =================================================== //
|
11
|
+
import createAlertsHtml from './createAlertsHtml.js';
|
12
|
+
import contentHashLink from './contentHashLink.js';
|
13
|
+
import cacheResponse from './cacheResponse.js';
|
14
|
+
|
15
|
+
const SHEET_KEY = '1plXBiZY5pVbhNT-mszxEuqCl4zy8wMnz9gXXbbT_yLs'; // Corresponds to the ID of the Google Sheet
|
16
|
+
const SHEET_TAB = 'Alerts'; // Corresponds to the tab of workbook: either 'Alerts' or 'Alerts Testing' unless you make a new one.
|
17
|
+
// const devSheetTab = 'ALERTS_TESTING';
|
18
|
+
const sheetParams = {
|
19
|
+
spreadsheetId: SHEET_KEY,
|
20
|
+
range: SHEET_TAB
|
21
|
+
// range: devSheetTab
|
22
|
+
}
|
23
|
+
const apiParams = { // This is configuration for API call with spreadsheets that are setup as readonly
|
24
|
+
'apiKey': 'AIzaSyCEBsbXfFcdbkASlg-PodD1rT_Fe3Nw62A',
|
25
|
+
'discoveryDocs': ['https://www.googleapis.com/discovery/v1/apis/sheets/v4/rest']
|
26
|
+
};
|
27
|
+
|
28
|
+
function init(Collapse) {
|
29
|
+
gapi.client.init(apiParams).then(() => { // Executes an API request, and returns a Promise.
|
30
|
+
return gapi.client.sheets.spreadsheets.values.get(sheetParams)
|
31
|
+
}).then((response) => {
|
32
|
+
createAlertsHtml(response, Collapse); // Build the html & inject it into the DOM
|
33
|
+
return response;
|
34
|
+
}).then((response) => {
|
35
|
+
cacheResponse(response); // Cache the Google API response for subsequent page loads in the site
|
36
|
+
}, (err)=> {
|
37
|
+
console.error("Execute error", err);
|
38
|
+
contentHashLink(Collapse);
|
39
|
+
});
|
40
|
+
}
|
41
|
+
|
42
|
+
function start(Collapse) {
|
43
|
+
if ( ! document.getElementById('emergencyAlerts') )
|
44
|
+
return contentHashLink(Collapse);
|
45
|
+
|
46
|
+
init(Collapse);
|
47
|
+
//var t1 = performance.now();
|
48
|
+
//console.info("Call to 'init' took " + (t1 - t0) + " milliseconds.");
|
49
|
+
}
|
50
|
+
// Loads the JavaScript client library and invokes `start` afterwards.
|
51
|
+
// Usage:
|
52
|
+
// gapi.load('client', start);
|
53
|
+
export default start;
|
@@ -0,0 +1,17 @@
|
|
1
|
+
function checkForPrefersReduceMotion() {
|
2
|
+
const reducedMotionMediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
|
3
|
+
let reducedMotion = reducedMotionMediaQuery.matches ? true : false;
|
4
|
+
|
5
|
+
localStorage.setItem('userPrefersReducedMotion', reducedMotion);
|
6
|
+
|
7
|
+
reducedMotionMediaQuery.addEventListener('change', _e => {
|
8
|
+
if (reducedMotionMediaQuery.matches) {
|
9
|
+
reducedMotion = true;
|
10
|
+
} else {
|
11
|
+
reducedMotion = false;
|
12
|
+
}
|
13
|
+
localStorage.setItem('userPrefersReducedMotion', reducedMotion);
|
14
|
+
});
|
15
|
+
}
|
16
|
+
|
17
|
+
export default checkForPrefersReduceMotion;
|
@@ -0,0 +1,102 @@
|
|
1
|
+
// Custom JS to do cool stuff with BS accordions and tabs by manipulating URL hashes and query's
|
2
|
+
// EXAMPLE:
|
3
|
+
// https://<ORIGIN>/?id=course-withdrawals#tuition-payment-and-deadlines
|
4
|
+
// The above URL will:
|
5
|
+
// 1. Open the #tuition-payment-and-deadlines accordion if it exists
|
6
|
+
// 2. The ?id=course-withdrawals query will:
|
7
|
+
// - look inside the opened accordion for an element with the id 'course-withdrawals', and
|
8
|
+
// - scroll that matching element into the user's viewport (in this case it's a heading within that accordion card)
|
9
|
+
//
|
10
|
+
// This JS will allow us to link to a specific area of content in a page where a traditional hash link wouldn't work
|
11
|
+
// In this case hash links won't work because the element with he matching ID is "stuck" in a closed accordion or tab.
|
12
|
+
//
|
13
|
+
const idRegex = /^id=/g; // Lets just cache these reused regex's here
|
14
|
+
const queryStartRegex = /^\?/g;
|
15
|
+
const endingSlashRegex = /\/$/g;
|
16
|
+
const REDUCED_MOTION_STORAGE_KEY = 'userPrefersReducedMotion'; // This localStorage key is set by module: './checkForPrefersReducedMotion.js'
|
17
|
+
const scrollIntoViewOptionsObject = {
|
18
|
+
behavior: 'smooth',
|
19
|
+
block: 'center'
|
20
|
+
}
|
21
|
+
const reducedMotionscrollIntoViewOptionsObject = {
|
22
|
+
block: 'center'
|
23
|
+
}
|
24
|
+
|
25
|
+
function focusElement(el) {
|
26
|
+
const prefersReducedMotion = window.localStorage.getItem(REDUCED_MOTION_STORAGE_KEY);
|
27
|
+
|
28
|
+
prefersReducedMotion == 'true' ? el.scrollIntoView(reducedMotionscrollIntoViewOptionsObject) : el.scrollIntoView(scrollIntoViewOptionsObject);
|
29
|
+
return el.focus();
|
30
|
+
}
|
31
|
+
|
32
|
+
function processIdQuery(query, hash) {
|
33
|
+
let id = query.replace(idRegex, '');
|
34
|
+
const parentEl = document.querySelector(hash);
|
35
|
+
const heading = parentEl.querySelector(`#${id}`);
|
36
|
+
|
37
|
+
focusElement(heading);
|
38
|
+
}
|
39
|
+
|
40
|
+
function checkForQuery(query, hash) {
|
41
|
+
query.search(idRegex) !== -1 ?
|
42
|
+
processIdQuery(query, hash)
|
43
|
+
: null;
|
44
|
+
}
|
45
|
+
|
46
|
+
function findContentTarget(hash) {
|
47
|
+
const target = document.querySelector(hash);
|
48
|
+
|
49
|
+
focusElement(target);
|
50
|
+
}
|
51
|
+
|
52
|
+
async function checkForMatchingTabOrAccordion(hash, Collapse) {
|
53
|
+
if (document.querySelector(`.nav-tabs a[href="${hash}"]`)) { // Looks for a matching BS4 tab element
|
54
|
+
const { default: Tab } = await import('bootstrap/js/dist/tab');
|
55
|
+
let tab = document.querySelector(`.nav-tabs a[href="${hash}"]`);
|
56
|
+
const bsTab = new Tab(tab, { toggle: false });
|
57
|
+
|
58
|
+
tab.addEventListener('shown.bs.tab', () => {
|
59
|
+
if (window.location.search) {
|
60
|
+
checkForQuery(window.location.search.replace(queryStartRegex, ''), hash);
|
61
|
+
}
|
62
|
+
});
|
63
|
+
bsTab.show();
|
64
|
+
findContentTarget(`${hash}-label`); // You need to .scrollIntoView() & .focus() on the tab-label which is an <a href="...">. It won't work to do .scrollIntoView() and .focus() on the div
|
65
|
+
} else if (document.querySelector(`.accordion ${hash}.collapse`)) { // Looks for a matching BS4 collapse element
|
66
|
+
let card = document.querySelector(hash);
|
67
|
+
const bsCollapse = new Collapse(card, { toggle: false });
|
68
|
+
|
69
|
+
card.addEventListener('shown.bs.collapse', _e => {
|
70
|
+
if (window.location.search) {
|
71
|
+
checkForQuery(window.location.search.replace(queryStartRegex, ''), hash);
|
72
|
+
}
|
73
|
+
});
|
74
|
+
bsCollapse.show();
|
75
|
+
findContentTarget(hash);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
function checkForHash(Collapse) {
|
80
|
+
if (window.location.hash) {
|
81
|
+
let hash = window.location.hash.replace(endingSlashRegex, '');
|
82
|
+
|
83
|
+
checkForMatchingTabOrAccordion(hash, Collapse);
|
84
|
+
}
|
85
|
+
return;
|
86
|
+
}
|
87
|
+
|
88
|
+
function initContentHashLink(Collapse) {
|
89
|
+
checkForHash(Collapse);
|
90
|
+
window.addEventListener('hashchange', _e => {
|
91
|
+
checkForHash(Collapse);
|
92
|
+
}, false);
|
93
|
+
}
|
94
|
+
|
95
|
+
function contentHashLink(Collapse) {
|
96
|
+
if (!document.querySelector('#accordion') && !document.querySelector('.nav.nav-tabs'))
|
97
|
+
return;
|
98
|
+
|
99
|
+
initContentHashLink(Collapse);
|
100
|
+
}
|
101
|
+
|
102
|
+
export default contentHashLink;
|
@@ -0,0 +1,46 @@
|
|
1
|
+
/*
|
2
|
+
// Custom JS | written by https://github.com/wdzajicek
|
3
|
+
// © 2020 Kankakee Community College
|
4
|
+
// =================================================== */
|
5
|
+
// JS module to build alert message using data from Google Sheets API v4
|
6
|
+
//
|
7
|
+
// This exported module requires you pass it's default-function the `response` object from the API call, as the only argument
|
8
|
+
import contentHashLink from './contentHashLink.js';
|
9
|
+
import parseMarkdownToHTML from './parseMarkdownToHTML.js'; // Parses a simplified markdown into html & creates the paragraph el's with appropriate class
|
10
|
+
|
11
|
+
function injectAlert(target, alert) {
|
12
|
+
target.innerHTML = alert;
|
13
|
+
return target.classList.add('position__offset-alert--visible');
|
14
|
+
}
|
15
|
+
|
16
|
+
function createAlertsHtml(response, Collapse) { // Incoming response from our Google Sheet via the Sheets API
|
17
|
+
// This is where the cell values hide in the response object from the Google API.
|
18
|
+
|
19
|
+
let [visibility, allPages, content, expire, start, end] = response.result.values[2]; // The 3rd row has our table's data
|
20
|
+
if (visibility === 'FALSE') return contentHashLink(Collapse); // Predefined dropdown options in the Sheet are `'TRUE'` & `'FALSE'`
|
21
|
+
|
22
|
+
const alertDiv = document.getElementById('emergencyAlerts'); // This targets an element built into the DOM that we inject everything into.
|
23
|
+
let d = new Date;
|
24
|
+
let s = new Date(start);
|
25
|
+
let e = new Date(end);
|
26
|
+
const alertIsActive = expire === 'FALSE' || expire === 'TRUE' && s.getTime() <= d.getTime() && e.getTime() > d.getTime();
|
27
|
+
const indexPageOnly = allPages === 'TRUE' || allPages === 'FALSE' && window.location.pathname == '/';
|
28
|
+
let alert = `
|
29
|
+
<div class="container">
|
30
|
+
<div class="row">
|
31
|
+
<div class="col">
|
32
|
+
<div class="alert alert-warning">
|
33
|
+
${parseMarkdownToHTML(content)}
|
34
|
+
</div>
|
35
|
+
</div>
|
36
|
+
</div>
|
37
|
+
</div>`;
|
38
|
+
|
39
|
+
[d,s,e].map(d => d.setHours(0, 0, 0, 0));
|
40
|
+
if (alertIsActive && indexPageOnly) {
|
41
|
+
injectAlert(alertDiv, alert);
|
42
|
+
}
|
43
|
+
return contentHashLink(Collapse);
|
44
|
+
}
|
45
|
+
|
46
|
+
export default createAlertsHtml;
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// Update copyright year if its not current
|
2
|
+
const yearSpan = document.getElementById('currentYear');
|
3
|
+
|
4
|
+
function footerDate() {
|
5
|
+
const d = new Date();
|
6
|
+
const fullYear = d.getFullYear();
|
7
|
+
|
8
|
+
if (yearSpan.innerHTML === `${fullYear}`)
|
9
|
+
return;
|
10
|
+
|
11
|
+
yearSpan.innerHTML = fullYear;
|
12
|
+
}
|
13
|
+
export default footerDate;
|