kcc-gem-theme-original 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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;
|