Add cookie banner (#6627)

* Add cookie banner

Co-authored-by: Alf Eaton <alf.eaton@overleaf.com>
Co-authored-by: Miguel Serrano <mserranom@users.noreply.github.com>
GitOrigin-RevId: a3625d4e6357ff58c7c47532901c382bedbe07e0
This commit is contained in:
Thomas 2022-03-29 14:12:10 +02:00 committed by Copybot
parent a5e09a6200
commit 76beba4393
10 changed files with 148 additions and 47 deletions

View file

@ -277,16 +277,6 @@ module.exports = function (webRouter, privateApiRouter, publicApiRouter) {
next() next()
}) })
webRouter.use(function (req, res, next) {
res.locals.gaToken =
Settings.analytics && Settings.analytics.ga && Settings.analytics.ga.token
res.locals.gaTokenV4 =
Settings.analytics &&
Settings.analytics.ga &&
Settings.analytics.ga.tokenV4
next()
})
webRouter.use(function (req, res, next) { webRouter.use(function (req, res, next) {
res.locals.getReqQueryParam = field => res.locals.getReqQueryParam = field =>
req.query != null ? req.query[field] : undefined req.query != null ? req.query[field] : undefined
@ -387,6 +377,15 @@ module.exports = function (webRouter, privateApiRouter, publicApiRouter) {
sentryEnvironment: Settings.sentry.environment, sentryEnvironment: Settings.sentry.environment,
sentryRelease: Settings.sentry.release, sentryRelease: Settings.sentry.release,
enableSubscriptions: Settings.enableSubscriptions, enableSubscriptions: Settings.enableSubscriptions,
gaToken:
Settings.analytics &&
Settings.analytics.ga &&
Settings.analytics.ga.token,
gaTokenV4:
Settings.analytics &&
Settings.analytics.ga &&
Settings.analytics.ga.tokenV4,
cookieDomain: Settings.cookieDomain,
} }
next() next()
}) })

View file

@ -0,0 +1,5 @@
.cookie-banner.hidden-print.hidden
.cookie-banner-content We only use cookies for essential purposes and to improve your experience on our site. You can find out more in our <a href="/legal#Cookies">cookie policy</a>.
.cookie-banner-actions
button(type="button" class="btn btn-link btn-sm" data-ol-cookie-banner-set-consent="essential") Essential cookies only
button(type="button" class="btn btn-info btn-sm" data-ol-cookie-banner-set-consent="all") Accept all cookies

View file

@ -0,0 +1,50 @@
if (typeof(ExposedSettings.gaTokenV4) != "undefined" || typeof(ExposedSettings.gaToken) != "undefined")
script(type="text/javascript", nonce=scriptNonce, id="ga-loader" data-ga-token=ExposedSettings.gaToken data-ga-token-v4=ExposedSettings.gaTokenV4 data-cookie-domain=ExposedSettings.cookieDomain).
var gaSettings = document.querySelector('#ga-loader').dataset;
var gaid = gaSettings.gaTokenV4;
var gaToken = gaSettings.gaToken;
var cookieDomain = gaSettings.cookieDomain;
if(gaid) {
window.dataLayer = window.dataLayer || [];
function gtag(){
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', gaid, { 'anonymize_ip': true });
}
if (gaToken) {
window.ga = window.ga || function () {
(window.ga.q = window.ga.q || []).push(arguments);
}, window.ga.l = 1 * new Date();
}
var loadGA = window.olLoadGA = function() {
if (gaid) {
var s = document.createElement('script');
s.setAttribute('async', 'async');
s.setAttribute('src', 'https://www.googletagmanager.com/gtag/js?id=' + gaid);
document.querySelector('head').append(s);
}
if (gaToken) {
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', gaToken, cookieDomain.replace(/^\./, ""));
ga('set', 'anonymizeIp', true);
ga('send', 'pageview');
}
};
// Check if consent given (features/cookie-banner)
var oaCookie = document.cookie.split('; ').find(function(cookie) {
return cookie.startsWith('oa=');
});
if(oaCookie) {
var oaCookieValue = oaCookie.split('=')[1];
if(oaCookieValue === '1') {
loadGA();
}
}
else
script(type="text/javascript", nonce=scriptNonce).
window.ga = function() { console.log("would send to GA", arguments) };
window.gtag = function() { console.log("would send to GA4", arguments) };

View file

@ -25,43 +25,7 @@ html(
link(rel="alternate", href=subdomainDetails.url+currentUrl, hreflang=subdomainDetails.lngCode) link(rel="alternate", href=subdomainDetails.url+currentUrl, hreflang=subdomainDetails.lngCode)
//- Scripts //- Scripts
include _google_analytics
//- Google Analytics
if (typeof(gaToken) != "undefined")
script(type="text/javascript", nonce=scriptNonce).
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
script(type="text/javascript", nonce=scriptNonce).
ga('create', '#{gaToken}', '#{settings.cookieDomain.replace(/^\./, "")}');
ga('set', 'anonymizeIp', true);
ga('send', 'pageview');
try {
ga.isBlocked = localStorage.getItem('gaBlocked') === 'true'
if (!ga.isBlocked) {
window.addEventListener('load', function () {
setTimeout(function () {
if (!ga.loaded) localStorage.setItem('gaBlocked', 'true')
}, 4000)
})
}
} catch (e) {}
else
script(type="text/javascript", nonce=scriptNonce).
window.ga = function() { console.log("would send to GA", arguments) };
if (typeof(gaTokenV4) != "undefined")
script(async, nonce=scriptNonce, src='https://www.googletagmanager.com/gtag/js?id=' + gaTokenV4)
script(type="text/javascript", nonce=scriptNonce).
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '#{gaTokenV4}');
else
script(type = "text/javascript", nonce = scriptNonce).
window.gtag = function() { console.log("would send to GA4", arguments) };
block meta block meta
meta(name="ol-csrfToken" content=csrfToken) meta(name="ol-csrfToken" content=csrfToken)

View file

@ -17,4 +17,6 @@ block body
else else
include layout/fat-footer include layout/fat-footer
include _cookie_banner
!= moduleIncludes("contactModal-marketing", locals) != moduleIncludes("contactModal-marketing", locals)

View file

@ -15,4 +15,6 @@ block body
else else
include layout/fat-footer include layout/fat-footer
include _cookie_banner
!= moduleIncludes("contactModal", locals) != moduleIncludes("contactModal", locals)

View file

@ -0,0 +1,43 @@
function loadGA() {
if (window.olLoadGA) {
window.olLoadGA()
}
}
function setConsent(value) {
document.querySelector('.cookie-banner').classList.add('hidden')
const cookieDomain = window.ExposedSettings.cookieDomain
const oneYearInSeconds = 60 * 60 * 24 * 365
const cookieAttributes =
'; domain=' +
cookieDomain +
'; max-age=' +
oneYearInSeconds +
'; SameSite=Lax; Secure'
if (value === 'all') {
document.cookie = 'oa=1' + cookieAttributes
loadGA()
} else {
document.cookie = 'oa=0' + cookieAttributes
}
}
if (window.ExposedSettings.gaToken || window.ExposedSettings.gaTokenV4) {
document
.querySelectorAll('[data-ol-cookie-banner-set-consent]')
.forEach(el => {
el.addEventListener('click', function (e) {
e.preventDefault()
const consentType = el.getAttribute('data-ol-cookie-banner-set-consent')
setConsent(consentType)
})
})
const oaCookie = document.cookie.split('; ').find(c => c.startsWith('oa='))
if (!oaCookie) {
const cookieBannerEl = document.querySelector('.cookie-banner')
if (cookieBannerEl) {
cookieBannerEl.classList.remove('hidden')
}
}
}

View file

@ -51,6 +51,7 @@ import './services/queued-http'
import './services/validateCaptcha' import './services/validateCaptcha'
import './services/validateCaptchaV3' import './services/validateCaptchaV3'
import './filters/formatDate' import './filters/formatDate'
import './features/cookie-banner'
import '../../modules/modules-main.js' import '../../modules/modules-main.js'
import './cdn-load-test' import './cdn-load-test'
angular.module('SharelatexApp').config(function ($locationProvider) { angular.module('SharelatexApp').config(function ($locationProvider) {

View file

@ -10,6 +10,7 @@ import './features/contact-form'
import './features/event-tracking' import './features/event-tracking'
import './features/fallback-image' import './features/fallback-image'
import './features/multi-submit' import './features/multi-submit'
import './features/cookie-banner'
$('[data-ol-lang-selector-tooltip]').tooltip({ trigger: 'hover' }) $('[data-ol-lang-selector-tooltip]').tooltip({ trigger: 'hover' })
$('[data-toggle="tooltip"]').tooltip() $('[data-toggle="tooltip"]').tooltip()

View file

@ -262,3 +262,37 @@ footer.site-footer {
} }
} }
} }
.cookie-banner {
display: flex;
align-items: center;
flex-wrap: wrap;
padding: 10px 20px;
font-size: 0.9rem;
line-height: 1;
position: fixed;
bottom: 0px;
left: 0;
right: 0;
z-index: 100;
color: @text-color;
background: @ol-blue-gray-0;
box-shadow: 0 -2px 1px 0px #2c36455c;
a {
color: @footer-link-color;
&:hover,
&:focus {
color: @footer-link-hover-color;
}
}
}
.cookie-banner-content {
flex: 1;
}
.cookie-banner-actions {
flex-shrink: 0;
white-space: nowrap;
}