Koha/koha-tmpl/opac-tmpl/bootstrap/js/cookieconsent.js
Matt Blenkinsop 49bfb9ff39
Bug 27378: Introduce cookie consent to OPAC and staff client
To avoid confusion around commit messages and the content of this enhancement, this first commit is a squashed commit of all the original code submited to this bug. Following a few years of inactivity, it has been rebased and re-submitted with some fixes and concept changes contained in the more recent commits.

Signed-ff-by: Barry Cannon <bc@interleaf.ie>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>

Bug 27378: (follow-up) Add missing filters

(cherry picked from commit 6b8565b949b62269f6d850e6d412458d0dbcfb37)
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>

Bug 27378: Fix accessibility issues

Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>

Bug 27378: Update to new atomicupdate structure

This patch consolidates the previous 4 database update files into one atomicupdate file in line with the new structure

Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>

Bug 27378: Change ConsentJS to CookieConsentedJS

This patch updates the name of the ConsentJS syspref to CookieConsentedJS and amends the description to be more clear what the syspref is for

Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>

Bug 27378: Stop the codemirror editor and delete confirmation from duplicating

Previously, if the "Add new code button" was clicked in the CookieConsentedJS editor, the original entry would have duplicated CodeMirror editors.
This was exponential, i.e adding two new lines would result in three codemirror editors appearing on the first entry, two on the second and so on.
The click event was not being applied properly and was being applied to every element with the .expand-textarea class, rather than specifically the new elements being created. The addExpandHandler function now loops through each element individually and decides whether to apply the click event handler.

Similarly, the delete confirmation was dupliacting for the same reason. This has also been resolved.

Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>

Bug 27378: Remove two sysprefs and replace with html customisations

Currently there are two sysprefs - CookieConsentBar and CookieConsentPopup. These allow the user to select what text they would like to see in the consent bar and modal. These have been removed and replaced with HTML customisations to allow more flexible customisations and different languages.

Sponsored by: PTFS-Europe

Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>

Bug 27378: (QA follow-up) Small fixes and tidy-ups

This patch does the following:
- Realphabetizes the lines in sysprefs.sql
- Fixes a formatting error in patrons.pref
- Adjusts the position of the cookie consent bar if the language selector is visible
- Fixes translatability on the syspref modal

Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>

Bug 27378: (QA follow-up) Allow staff to view their cookie consents

This patch allows staff to view their cookie consents through a link in the dropdown menu in the navbar. Previously staff had no way of accessing their cookie consents

Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>

Bug 27378: (QA follow-up) Add cancel button to cookie modal

This patch adds a cancel button to the modal for reviewing cookie consents. Previously there was no way to exit without selecting one of the cookie options

Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>

Bug 27378: (QA follow-up) Add filtering for OPAC only and staff only cookies

This patch fixes an issue where cookies selected as OPAC only would still show in the staff client and vise versa. The cookies are now filtered and only the correct cookies will be used in the OPAC and staff client

Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>

Bug 27378: (QA follow-up) Fix tests and character encoding

This patch fixes an encoding issue when using diacritics. It also fixes a failing test, corrects the format of the "Cancel" links in the modal and perltidy has been used on all relevant files

Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
2023-09-12 09:45:07 -03:00

211 lines
7.2 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;
}
if (hasStoredConsent === null) {
showConsentBar();
} else {
showYourCookies();
}
addButtonHandlers();
// When the modal is opened, populate our state based on currently
// selected values
$('#cookieConsentModal').on('shown.bs.modal', function () {
initialiseSelected();
});
// Initialise existing consent based on local storage
function getExistingConsent() {
existingConsent = localStorage.getItem('cookieConsent') ?
localStorage.getItem('cookieConsent') :
[];
}
function showConsentBar() {
const consentBar = $('#cookieConsentBar');
const langmenu = $('#changelanguage');
if(langmenu) {
const height = langmenu.height();
consentBar.css('bottom', height);
};
consentBar.attr('aria-hidden', 'false');
consentBar.show();
}
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 ($('#cookieConsentModal').hasClass('show')) {
$('#cookieConsentModal').modal('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, #cookieConsentButton, #viewCookieConsents').on(
'click',
function (e) {
e.preventDefault();
hideConsentBar();
// Ensure we're up to date with the existing consent
getExistingConsent();
// Prevent the modal from being closed with anything
// but the buttons
$('#cookieConsentModal')
.modal({
backdrop: 'static',
keyboard: false,
focus: true,
show: true
});
}
);
$('.consentCheckbox').on('click', function () {
maintainSelected();
});
}
// On page load, run any code that has been given consent
runConsentedCode();
})();