Koha/koha-tmpl/opac-tmpl/bootstrap/js/cookieconsent.js
Owen Leonard 5fe1ad8ac6
Bug 35402: Update the OPAC and staff interface to Bootstrap 5
This patch updates the OPAC and staff interface to use Bootstrap 5.
Bootstrap CSS assets are now pulled from node_modules and compiled into
staff-global.css and opac.css at build time. This update lays the
foundations of some other chnages, especially the addition of a dark
mode in the future.

Hundreds of templates have been updated, mostly with updates to the grid
markup. Most of the responsive behavior is still the same with the
exception of improved flexibility of headers and footers in both the
OPAC and staff interface.

The other most common change is to add a new "namespace" to data
attributes used by Bootstrap, e.g. "data-bs-target" or "data-bs-toggle".
Modal markup has also been updated everywhere. Other common changes:
dropdown button markup, alert markup (we now use Bootstrap's "alert
alert-warning" and "alert alert-info" instead of our old "dialog alert"
and "dialog info").

Bootstrap 5 now uses CSS variables which we can override in our own
'_variables.scss' (in both the OPAC and staff) to accomplish a lot of
the style overrides which we previously put in staff-global.scss.

Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
2024-08-23 15:58:41 +02:00

223 lines
7.6 KiB
JavaScript

(function () {
// Has the user previously consented, establish our
// initial state
let selected = [];
let existingConsent = '';
// The presence of a 'cookieConsent' local storage item indicates
// that previous consent has been set. If the value is empty, then
// no consent to non-essential cookies was given
const hasStoredConsent = localStorage.getItem('cookieConsent');
getExistingConsent();
// The consent bar may not be in the DOM if it is not being used
const consentBar = $('#cookieConsentBar');
if (!consentBar) {
return;
}
// Initialize the consent modal and prevent the modal
// from being closed with anything but the buttons
const cookieConsentModal = new bootstrap.Modal( document.getElementById("cookieConsentModal"), {
backdrop: 'static',
keyboard: false,
focus: true,
show: true
});
if (hasStoredConsent === null) {
showConsentBar();
} else {
showYourCookies();
}
addButtonHandlers();
// When the modal is opened, populate our state based on currently
// selected values
const cookieConsentModalEl = document.getElementById("cookieConsentModal");
cookieConsentModalEl.addEventListener("shown.bs.modal", () => {
initialiseSelected();
});
$(window).on("scroll", function() {
const consentBar = $("#cookieConsentBar");
const langmenu = $("#changelanguage");
const wrapper = $("#wrapper");
if( langmenu ) {
const height = langmenu.height();
if( $(window).scrollTop() >= wrapper.offset().top + wrapper.outerHeight() - window.innerHeight ) {
consentBar.css("bottom", height);
} else {
consentBar.css("bottom", 0);
}
};
});
// Initialise existing consent based on local storage
function getExistingConsent() {
existingConsent = localStorage.getItem('cookieConsent') ?
localStorage.getItem('cookieConsent') :
[];
}
function showConsentBar() {
const consentBar = $('#cookieConsentBar');
consentBar.attr('aria-hidden', 'false');
consentBar.css("display", "flex");
}
function hideConsentBar() {
const consentBar = $('#cookieConsentBar');
consentBar.attr('aria-hidden', 'true');
consentBar.hide();
}
// Hides the appropriate consent container, depending on what
// is currently visible
function hideContainer() {
if ( $(cookieConsentModalEl).is(":visible") ){
cookieConsentModal.hide();
} else {
hideConsentBar();
}
}
// Show the unauthenticated user's "Your cookies" button
function showYourCookies() {
// If the user is unauthenticated, there will be a
// cookieConsentsButton element in the DOM. The user
// has previously consented, so we need to display this
// button
if ($('#cookieConsentButton').length > 0) {
$('#cookieConsentDivider').show().attr('aria-hidden', 'false');
$('#cookieConsentLi').show().attr('aria-hidden', 'false');
}
}
// Initialise our state of selected item and enable/disable
// the "Accept selected" button appropriately
function initialiseSelected() {
selected = [];
$('.consentCheckbox').each(function () {
const val = $(this).val();
if (existingConsent.indexOf(val) > -1 ) {
$(this).prop('checked', true);
selected.push(val);
} else {
$(this).prop('checked', false);
}
});
enableDisableSelectedButton();
}
// Maintain our state of selected items and enable/disable
// the "Accept selected" button appropriately
function maintainSelected() {
selected = [];
$('.consentCheckbox:checked').each(function () {
selected.push($(this).val());
});
enableDisableSelectedButton();
}
// Set the enabled / disabled state of the
// "Accept selected button based on the checkbox
// states
function enableDisableSelectedButton() {
$('#consentAcceptSelected').prop(
'disabled',
selected.length === 0
);
}
function runConsentedCode() {
getExistingConsent();
$('.consentCode').each(function () {
// The user has explicitly consented to this code, or the
// code doesn't require consent in the OPAC
if (
existingConsent.indexOf($(this).data('consent-id')) > -1 ||
!$(this).data('requires-consent')
) {
const code = atob($(this).data('consent-code'));
const func = Function(code);
func();
} else {
// This code doesn't have consent to run, we may need to remove
// any cookies it has previously set
const matchPattern = $(this).data('consent-match-pattern');
const cookieDomain = $(this).data('consent-cookie-domain');
const cookiePath = $(this).data('consent-cookie-path');
if (matchPattern.length > 0) {
const regex = new RegExp(matchPattern);
const allCookies = document.cookie.split('; ');
allCookies.forEach(function (cookie) {
const name = cookie.split('=')[0];
if (regex.test(name)) {
document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT; domain=' + cookieDomain +'; path=' + cookiePath;
}
});
}
}
});
}
function addButtonHandlers() {
// "Accept all" handler
$('.consentAcceptAll').on('click', function(e) {
e.preventDefault();
let toSave = [];
$('.consentCheckbox').each(function () {
const val = $(this).val();
toSave.push(val);
});
localStorage.setItem('cookieConsent', toSave);
hideContainer();
runConsentedCode();
showYourCookies();
});
// "Accept essential" handler
$('.consentAcceptEssential').on('click', function(e) {
e.preventDefault();
localStorage.setItem('cookieConsent', []);
hideContainer();
runConsentedCode();
showYourCookies();
});
// "Accept selected" handler
$('#consentAcceptSelected').on('click', function(e) {
e.preventDefault();
const toSave = selected.length > 0 ? selected : [];
localStorage.setItem('cookieConsent', toSave);
hideContainer();
runConsentedCode();
showYourCookies();
});
// "Cancel" handler
$('.consentCloseModal').on('click', function(e) {
e.preventDefault();
hideContainer();
showConsentBar();
});
// "More information" handler
$('#consentMoreInfo, #cookieConsentFooter, #cookieConsentButton').on(
'click',
function (e) {
e.preventDefault();
hideConsentBar();
// Ensure we're up to date with the existing consent
getExistingConsent();
cookieConsentModal.show();
}
);
$('.consentCheckbox').on('click', function () {
maintainSelected();
});
}
// On page load, run any code that has been given consent
runConsentedCode();
})();