Bugzilla – Attachment 151739 Details for
Bug 27378
Enable compliance with EU Cookie Legislation via cookie consent
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 27378: Add cookie consent display to staff UI
Bug-27378-Add-cookie-consent-display-to-staff-UI.patch (text/plain), 12.69 KB, created by
Matt Blenkinsop
on 2023-05-26 12:18:15 UTC
(
hide
)
Description:
Bug 27378: Add cookie consent display to staff UI
Filename:
MIME Type:
Creator:
Matt Blenkinsop
Created:
2023-05-26 12:18:15 UTC
Size:
12.69 KB
patch
obsolete
>From a8f4b608c3d3ff296cc00d47ff6e04b234170ee2 Mon Sep 17 00:00:00 2001 >From: Andrew Isherwood <andrew.isherwood@ptfs-europe.com> >Date: Wed, 20 Jan 2021 09:26:27 +0000 >Subject: [PATCH] Bug 27378: Add cookie consent display to staff UI > >This commit adds the display of the cookie consent bar and modal to the >staff interface: > >- Adds a new cookieconsent.js script that drives the display and >functionality of the cookie consent bar and modal >- Adds styles for the cookie consent bar and modal >- Adds the creation and population of the cookie consent bar and modal, >if appropriate > >Signed-ff-by: Barry Cannon <bc@interleaf.ie> >(cherry picked from commit 40d4b094420ea1495996976434d250b15ee78c1b) >--- > .../prog/css/src/staff-global.scss | 49 ++++++ > .../prog/en/includes/intranet-bottom.inc | 69 ++++++++ > .../intranet-tmpl/prog/js/cookieconsent.js | 165 ++++++++++++++++++ > 3 files changed, 283 insertions(+) > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/cookieconsent.js > >diff --git a/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss b/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss >index 6c0b7b9524..9f576aae56 100644 >--- a/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss >+++ b/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss >@@ -4350,6 +4350,55 @@ div .suggestion_note { > } > } > >+/* Cookie consent bar */ >+#cookieConsentBar { >+ display: none; >+ padding: 20px; >+ position: fixed; >+ bottom: 0; >+ left: 0; >+ right: 0; >+ background: rgba(0,0,0,0.7); >+ color: rgba(255,255,255,0.9); >+ z-index: 1; >+ a:link, a:visited { >+ color: #d7ebff; >+ } >+ #consentButtons { >+ margin-top: 10px; >+ text-align: right; >+ } >+ button:not(:last-child) { >+ margin-right: 10px; >+ } >+} >+ >+/* Cookie consent modal */ >+#cookieConsentModal { >+ .modal-dialog { >+ width: 700px; >+ } >+ .consentModalItem { >+ display: flex; >+ align-items: center; >+ border: 1px solid #ccc; >+ padding: 10px 20px; >+ border-radius: 5px; >+ } >+ .consentModalItem:not(:last-child) { >+ margin-bottom: 20px; >+ } >+ .consentItemCheckbox { >+ padding-right: 20px; >+ } >+ .consentItemName { >+ font-weight: bold; >+ } >+ #cookieConsentPopupText { >+ margin: 20px 0; >+ } >+} >+ > @import "header"; > @import "toolbar"; > @import "forms"; >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/intranet-bottom.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/intranet-bottom.inc >index 27ba415943..5a94f7d53a 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/intranet-bottom.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/intranet-bottom.inc >@@ -1,6 +1,10 @@ > [% USE raw %] > [% USE Koha %] > [% USE KohaPlugins %] >+[% USE Asset %] >+[% IF Koha.Preference( 'CookieConsent' ) %] >+ [% USE JSConsents %] >+[% END %] > </div> > [% IF ( ( languages_loop ) && ( ! popup_window ) && ( Koha.Preference('StaffLangSelectorMode') == 'both' || Koha.Preference('StaffLangSelectorMode') == 'footer') ) %] > [% UNLESS ( one_language_enabled ) %] >@@ -74,5 +78,70 @@ > [% END %] > [% KohaPlugins.get_plugins_intranet_js | $raw %] > >+ <!-- Cookie consent --> >+ [% IF Koha.Preference( 'CookieConsent' ) %] >+ <!-- Cookie consent bar --> >+ <div id="cookieConsentBar" aria-hidden="true"> >+ [% Koha.Preference( 'CookieConsentBar' ) | $raw %] >+ <div id="consentButtons"> >+ <button type="button" class="btn btn-primary consentAcceptAll">Accept all cookies</button> >+ [% IF ( Koha.Preference( 'ConsentJS' ).length > 0 ) %] >+ <button type="button" class="btn btn-primary consentAcceptEssential">Accept only essential cookies</button> >+ <button type="button" class="btn btn-info" id="consentMoreInfo">More information</button> >+ [% END %] >+ </div> >+ </div> <!-- /#cookieConsentBar --> >+ <!-- Cookie consent modal --> >+ <div id="cookieConsentModal" class="modal" tabindex="-1" role="dialog" aria-labelledby="cookieConsentModalLabel" aria-hidden="true"> >+ <div class="modal-dialog"> >+ <div class="modal-content"> >+ <div class="modal-header"> >+ <h2 class="modal-title" id="cookieConsentModalLabel">Cookie consent</h2> >+ </div> >+ <div class="modal-body"> >+ [% IF Koha.Preference( 'CookieConsentPopup' ) %] >+ <div id="cookieConsentPopupText"> >+ [% Koha.Preference( 'CookieConsentPopup' ) | $raw %] >+ </div> >+ [% END %] >+ <div id="consentCookieList"> >+ [% consents = JSConsents.all() %] >+ [% FOREACH consent IN consents %] >+ <div class="consentModalItem"> >+ <div class="consentItemCheckbox"> >+ <input class="consentCheckbox" type="checkbox" name="consentCheckbox" value="[% consent.id %]"> >+ </div> >+ <div class="consentItemMeta"> >+ <div class="consentItemName">[% consent.name | html %]</div> >+ <div class="consentItemDescription">[% consent.description | html %]</div> >+ </div> >+ </div> >+ [% END %] >+ </div> >+ </div> >+ <div class="modal-footer"> >+ <div id="consentButtons"> >+ <button type="button" class="btn btn-primary consentAcceptAll">Accept all cookies</button> >+ [% IF ( Koha.Preference( 'ConsentJS' ).length > 0 ) %] >+ <button type="button" class="btn btn-primary consentAcceptEssential">Accept only essential cookies</button> >+ <button type="button" class="btn btn-warning" id="consentAcceptSelected">Accept selected non-essential cookies</button> >+ [% END %] >+ </div> >+ </div> >+ </div> <!-- /.modal-content --> >+ </div> <!-- /.modal-dialog --> >+ </div> <!-- /#cookieConsentModal --> >+ [% END %] >+ <!-- ConsentJS code that may run --> >+ [% IF Koha.Preference( 'CookieConsent' ) && Koha.Preference( 'ConsentJS' ).length > 0 %] >+ [% consents = JSConsents.all() %] >+ [% FOREACH consent IN consents %] >+ <div class="consentCode" style="display:none" aria-hidden="true" data-consent-id="[% consent.id %]" data-consent-code="[% consent.code %]" data-requires-consent="[% consent.staffConsent ? 'true' : 'false' %]"></div> >+ [% END %] >+ [% END %] >+ [% IF Koha.Preference( 'CookieConsent' ) %] >+ [% Asset.js("js/cookieconsent.js") | $raw %] >+ [% END %] >+ > </body> > </html> >diff --git a/koha-tmpl/intranet-tmpl/prog/js/cookieconsent.js b/koha-tmpl/intranet-tmpl/prog/js/cookieconsent.js >new file mode 100644 >index 0000000000..c718c73e39 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/cookieconsent.js >@@ -0,0 +1,165 @@ >+(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(); >+ } >+ 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'); >+ 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('in')) { >+ $('#cookieConsentModal').modal('hide'); >+ } else { >+ hideConsentBar(); >+ } >+ } >+ >+ // 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 staff view >+ if ( >+ existingConsent.indexOf($(this).data('consent-id')) > -1 || >+ !$(this).data('requires-consent') >+ ) { >+ const code = atob($(this).data('consent-code')); >+ const func = Function(code); >+ func(); >+ } >+ }); >+ } >+ >+ 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(); >+ }); >+ >+ // "Accept essential" handler >+ $('.consentAcceptEssential').on('click', function(e) { >+ e.preventDefault(); >+ localStorage.setItem('cookieConsent', []); >+ hideContainer(); >+ }); >+ >+ // "Accept selected" handler >+ $('#consentAcceptSelected').on('click', function(e) { >+ e.preventDefault(); >+ const toSave = selected.length > 0 ? selected : []; >+ localStorage.setItem('cookieConsent', toSave); >+ hideContainer(); >+ runConsentedCode(); >+ }); >+ >+ // "More information" handler >+ $('#consentMoreInfo').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(); >+})(); >-- >2.37.1 (Apple Git-137.1)
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 27378
:
115544
|
115545
|
115546
|
115547
|
115548
|
115756
|
116397
|
116398
|
116399
|
116400
|
116401
|
116402
|
116403
|
116416
|
116417
|
116418
|
116419
|
116420
|
116421
|
116422
|
116423
|
116978
|
116979
|
116980
|
116981
|
116982
|
116983
|
116984
|
116985
|
116986
|
121728
|
121729
|
121730
|
121731
|
121732
|
121733
|
121734
|
121735
|
121995
|
121996
|
121997
|
121998
|
121999
|
122000
|
122001
|
122002
|
122635
|
122636
|
122637
|
122638
|
122639
|
122640
|
122641
|
122642
|
124957
|
124958
|
124959
|
124960
|
124961
|
124962
|
124963
|
124964
|
124965
|
130072
|
130073
|
130074
|
130075
|
130076
|
130077
|
130078
|
130079
|
130080
|
135309
|
135310
|
135311
|
135312
|
135313
|
135314
|
135315
|
135316
|
135317
|
135318
|
151735
|
151736
|
151737
|
151738
|
151739
|
151740
|
151741
|
151742
|
151743
|
151744
|
151745
|
151746
|
151747
|
151748
|
151749
|
151750
|
151751
|
151752
|
151753
|
151826
|
151827
|
151828
|
151829
|
151830
|
151831
|
151832
|
151833
|
151834
|
151835
|
151836
|
151837
|
151838
|
151839
|
151840
|
151841
|
151842
|
151843
|
151844
|
153326
|
153327
|
153328
|
153329
|
153330
|
153331
|
153332
|
153333
|
153334
|
153335
|
153336
|
154015
|
154016
|
154017
|
154018
|
154019
|
154020
|
154021
|
154022
|
154023
|
154024
|
154025
|
154093
|
154264
|
154265
|
154266
|
154267
|
154268
|
154269
|
154270
|
154271
|
154272
|
154273
|
154274
|
154275
|
154276