bifurqué depuis cliss21/biohdf
feat(tracking): ajout du tracking utilisateur
Parent
e5c4039eb8
révision
a8fadf1e0a
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* Appel une fonction après que le document est chargé.
|
||||
* @param {Function} fn - La fonction à appeler
|
||||
* @returns {void}
|
||||
*/
|
||||
export default (fn) => {
|
||||
if (typeof fn !== 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
// si le document est déjà chargé, on appel la fonction
|
||||
if (document.readyState === 'interactive' ||
|
||||
document.readyState === 'complete') {
|
||||
fn();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', fn, false);
|
||||
};
|
|
@ -0,0 +1,240 @@
|
|||
import ready from './helpers/ready';
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Constantes
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
const Message = {
|
||||
ACTIVE: 'Votre visite sur ce site est actuellement <b>suivie anonymement</b>.',
|
||||
ACTIVE_HELP: 'Vous pouvez vous opposer au suivi en décochant cette case.',
|
||||
INACTIVE: 'Votre visite sur ce site n\'est actuellement <b>pas suivie</b>.',
|
||||
INACTIVE_HELP: 'Vous pouvez activer le suivi anonyme en cochant cette case afin de nous aider à améliorer notre site.',
|
||||
DONOTTRACK: 'Votre visite sur ce site n\'est <b>pas suivie</b>, conformément aux préférences de votre navigateur.',
|
||||
DONOTTRACK_HELP: 'La fonctionnalité <i>Do Not Track</i> étant activée dans les préférences de votre navigateur, elle prend le dessus sur le contrôle de votre suivi sur ce site.',
|
||||
OLDBROWSER_HELP: 'Votre navigateur semble trop vieux pour vous permettre de contrôler votre suivi. Pour plus de sécurité et de confidentialité, veuillez mettre à jour votre navigateur.'
|
||||
};
|
||||
|
||||
const Default = {
|
||||
key: 'tracking',
|
||||
initial: true
|
||||
};
|
||||
|
||||
const Selector = {
|
||||
CONTAINER: '.tracking-optout',
|
||||
CHECKBOX: 'input[type="checkbox"]',
|
||||
STATE: '.tracking-state',
|
||||
HELP: '.tracking-help'
|
||||
};
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Helpers
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Detects whether localStorage is both supported and available.
|
||||
* @link https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API#Testing_for_availability
|
||||
* @returns {Boolean} `true` if localStorage is usable.
|
||||
*/
|
||||
function hasLocalStorage() {
|
||||
let storage;
|
||||
try {
|
||||
storage = window.localStorage;
|
||||
const x = '__storage_test__';
|
||||
storage.setItem(x, x);
|
||||
storage.removeItem(x);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return e instanceof DOMException && (
|
||||
// everything except Firefox
|
||||
e.code === 22 || // eslint-disable-line no-magic-numbers
|
||||
// Firefox
|
||||
e.code === 1014 || // eslint-disable-line no-magic-numbers
|
||||
// test name field too, because code might not be present
|
||||
// everything except Firefox
|
||||
e.name === 'QuotaExceededError' ||
|
||||
// Firefox
|
||||
e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
|
||||
// acknowledge QuotaExceededError only if there's something already stored
|
||||
(storage && storage.length !== 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the user's do-not-track setting is enabled.
|
||||
* @returns {Boolean} `true` if the user should not be tracked.
|
||||
*/
|
||||
function hasDoNotTrack() {
|
||||
return navigator.doNotTrack === '1' ||
|
||||
navigator.doNotTrack === 'yes' ||
|
||||
navigator.msDoNotTrack === '1' ||
|
||||
window.doNotTrack === '1';
|
||||
}
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Classe
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
class OptedTracking {
|
||||
constructor(fn, config) {
|
||||
if (typeof fn !== 'function') {
|
||||
throw new Error('Une fonction est attendue comme premier argument');
|
||||
}
|
||||
|
||||
this._elements = [];
|
||||
this._config = Object.assign({}, Default, config);
|
||||
|
||||
this._dnt = hasDoNotTrack();
|
||||
this._localStorage = hasLocalStorage();
|
||||
|
||||
this._enabled = this.getState();
|
||||
|
||||
// exécute la fonction dès que possible
|
||||
if (this._enabled) {
|
||||
setTimeout(fn, 0);
|
||||
}
|
||||
|
||||
window.addEventListener('storage', (e) => {
|
||||
if (e.key === this._config.key) {
|
||||
this._refresh();
|
||||
}
|
||||
});
|
||||
|
||||
// attends que la page soit chargée pour initialiser les éléments
|
||||
ready(() => this._initElements());
|
||||
}
|
||||
|
||||
// Méthodes publiques
|
||||
|
||||
getState() {
|
||||
if (this._dnt) {
|
||||
return false;
|
||||
} else if (!this._localStorage) {
|
||||
return this._config.initial;
|
||||
}
|
||||
|
||||
const state = window.localStorage.getItem(this._config.key);
|
||||
|
||||
if (state === 'true') {
|
||||
return true;
|
||||
} else if (state === 'false') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this._config.initial;
|
||||
}
|
||||
|
||||
setState(enabled) {
|
||||
window.localStorage.setItem(this._config.key, enabled ? 'true' : 'false');
|
||||
// l'état étant changé dans ce contexte, il faut rafraichir manuellement
|
||||
this._refresh();
|
||||
}
|
||||
|
||||
// Méthodes privées
|
||||
|
||||
_refresh() {
|
||||
const enabled = this.getState();
|
||||
|
||||
if (this._dnt) {
|
||||
this._adjustElements(
|
||||
Message.DONOTTRACK,
|
||||
Message.DONOTTRACK_HELP,
|
||||
enabled,
|
||||
true
|
||||
);
|
||||
} else if (!this._localStorage) {
|
||||
this._adjustElements(
|
||||
enabled ? Message.ACTIVE : Message.INACTIVE,
|
||||
Message.OLDBROWSER_HELP,
|
||||
enabled,
|
||||
true
|
||||
);
|
||||
} else {
|
||||
this._adjustElements(
|
||||
enabled ? Message.ACTIVE : Message.INACTIVE,
|
||||
enabled ? Message.ACTIVE_HELP : Message.INACTIVE_HELP,
|
||||
enabled,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
// si l'état a changé, il faut recharger la page
|
||||
if (enabled !== this._enabled) {
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
_initElements() {
|
||||
this._elements = [...document.querySelectorAll(Selector.CONTAINER)];
|
||||
|
||||
this._checkboxes = [];
|
||||
this._states = [];
|
||||
this._helps = [];
|
||||
|
||||
// parcours tous les conteneurs et ajoute leurs éléments
|
||||
this._elements.forEach((container) => {
|
||||
const checkbox = container.querySelector(Selector.CHECKBOX);
|
||||
const state = container.querySelector(Selector.STATE);
|
||||
const help = container.querySelector(Selector.HELP);
|
||||
|
||||
if (checkbox) {
|
||||
this._checkboxes.push(checkbox);
|
||||
}
|
||||
if (state) {
|
||||
this._states.push(state);
|
||||
}
|
||||
if (help) {
|
||||
this._helps.push(help);
|
||||
}
|
||||
});
|
||||
|
||||
this._checkboxes.forEach((checkbox) => {
|
||||
checkbox.addEventListener('click', () => this.setState(checkbox.checked));
|
||||
});
|
||||
|
||||
this._refresh();
|
||||
}
|
||||
|
||||
_adjustElements(stateText, helpText, checked, disabled) {
|
||||
if (stateText) {
|
||||
this._states.forEach((el) => {
|
||||
el.innerHTML = stateText;
|
||||
});
|
||||
}
|
||||
|
||||
if (helpText) {
|
||||
this._helps.forEach((el) => {
|
||||
el.innerHTML = helpText;
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof checked === 'boolean') {
|
||||
this._checkboxes.forEach((el) => {
|
||||
el.checked = checked;
|
||||
});
|
||||
}
|
||||
|
||||
if (disabled === true) {
|
||||
this._checkboxes.forEach((el) => el.setAttribute('disabled', ''));
|
||||
} else if (disabled === false) {
|
||||
this._checkboxes.forEach((el) => el.removeAttribute('disabled'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Export
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
export default OptedTracking;
|
||||
|
||||
window.optedtracking = function (fn, config) {
|
||||
return new OptedTracking(fn.bind(window), config);
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
# Generated by Django 2.2.15 on 2020-08-14 15:52
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import wagtail.core.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailcore', '0041_group_collection_permissions_verbose_name_plural'),
|
||||
('base', '0015_bouton_hors_zone_texte'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='MatomoSettings',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('privacy_policy', wagtail.core.fields.RichTextField(blank=True, help_text="Texte expliquant aux visiteurs les données qui sont collectées par le site et comment elles sont utilisées. Il est affiché sur la page <i>Politique de confidentialité</i>, qui permet aussi de s'opposer au suivi si le code est défini.", verbose_name='politique de confidentialité')),
|
||||
('tracking_code', models.TextField(blank=True, help_text='Le code JavaScript à exécuter pour suivre les visiteurs sur le site, sans la balise <code><script></code>.', verbose_name='code de suivi')),
|
||||
('site', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, to='wagtailcore.Site')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Suivi des visiteurs',
|
||||
},
|
||||
),
|
||||
]
|
|
@ -2,13 +2,31 @@ from collections import OrderedDict
|
|||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.models import User
|
||||
from django.http.response import HttpResponseRedirect
|
||||
from django.http.response import HttpResponseRedirect, Http404
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.views import generic
|
||||
|
||||
from taggit.models import Tag
|
||||
|
||||
from biohdf.base import annonces, emails, forms, mixins, models, taxonomy
|
||||
from biohdf.base import annonces, emails, forms, mixins, models, taxonomy, wagtail_hooks
|
||||
|
||||
|
||||
class PrivacyPolicyView(mixins.ThemeMixin, generic.TemplateView):
|
||||
"""
|
||||
Affiche la politique de confidentialité des données.
|
||||
"""
|
||||
|
||||
template_name = 'privacy_policy.html'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
matomo_settings = wagtail_hooks.MatomoSettings.for_site(request.site)
|
||||
if not matomo_settings.privacy_policy:
|
||||
raise Http404("La politique de confidentialité n'est pas définie.")
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
root = models.SitePage.objects.first()
|
||||
return {'page': root}
|
||||
|
||||
|
||||
class CartoView(mixins.ThemeMixin, generic.ListView):
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
from django.db import models
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
import wagtail.admin.rich_text.editors.draftail.features as draftail_features
|
||||
from taggit.models import Tag
|
||||
from wagtail.admin.edit_handlers import PageChooserPanel
|
||||
from wagtail.admin.edit_handlers import PageChooserPanel, FieldPanel, StreamFieldPanel
|
||||
from wagtail.admin.rich_text.converters.html_to_contentstate import (
|
||||
InlineStyleElementHandler,
|
||||
)
|
||||
|
@ -13,6 +14,7 @@ from wagtail.contrib.modeladmin.options import (
|
|||
)
|
||||
from wagtail.contrib.settings.models import BaseSetting, register_setting
|
||||
from wagtail.core import hooks
|
||||
from wagtail.core.fields import RichTextField, StreamField
|
||||
|
||||
from biohdf.base import annonces, taxonomy
|
||||
|
||||
|
@ -33,6 +35,44 @@ class MentionsLegalesSettings(BaseSetting):
|
|||
panels = [PageChooserPanel('page')]
|
||||
|
||||
|
||||
@register_setting
|
||||
class MatomoSettings(BaseSetting):
|
||||
class Meta:
|
||||
verbose_name = "Suivi des visiteurs"
|
||||
|
||||
privacy_policy = RichTextField(
|
||||
"politique de confidentialité",
|
||||
blank=True,
|
||||
features=(
|
||||
'h3',
|
||||
'h4',
|
||||
'bold',
|
||||
'italic',
|
||||
'ol',
|
||||
'ul',
|
||||
'hr',
|
||||
'link',
|
||||
'document-link',
|
||||
),
|
||||
help_text=mark_safe(
|
||||
"Texte expliquant aux visiteurs les données qui sont collectées "
|
||||
"par le site et comment elles sont utilisées. Il est affiché sur "
|
||||
"la page <i>Politique de confidentialité</i>, qui permet aussi "
|
||||
"de s'opposer au suivi si le code est défini."
|
||||
),
|
||||
)
|
||||
tracking_code = models.TextField(
|
||||
"code de suivi",
|
||||
blank=True,
|
||||
help_text=mark_safe(
|
||||
"Le code JavaScript à exécuter pour suivre les visiteurs sur le "
|
||||
"site, sans la balise <code><script></code>."
|
||||
),
|
||||
)
|
||||
|
||||
panels = [FieldPanel('privacy_policy'), FieldPanel('tracking_code')]
|
||||
|
||||
|
||||
# Model Admins
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,395 @@
|
|||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId]) {
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ i: moduleId,
|
||||
/******/ l: false,
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.l = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
/******/
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
/******/
|
||||
/******/ // define getter function for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = function(exports) {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // create a fake namespace object
|
||||
/******/ // mode & 1: value is a module id, require it
|
||||
/******/ // mode & 2: merge all properties of value into the ns
|
||||
/******/ // mode & 4: return value when already ns object
|
||||
/******/ // mode & 8|1: behave like require
|
||||
/******/ __webpack_require__.t = function(value, mode) {
|
||||
/******/ if(mode & 1) value = __webpack_require__(value);
|
||||
/******/ if(mode & 8) return value;
|
||||
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
||||
/******/ var ns = Object.create(null);
|
||||
/******/ __webpack_require__.r(ns);
|
||||
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
||||
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
||||
/******/ return ns;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function getDefault() { return module['default']; } :
|
||||
/******/ function getModuleExports() { return module; };
|
||||
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Object.prototype.hasOwnProperty.call
|
||||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||
/******/
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 0);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ({
|
||||
|
||||
/***/ "./assets/js/helpers/ready.js":
|
||||
/*!************************************!*\
|
||||
!*** ./assets/js/helpers/ready.js ***!
|
||||
\************************************/
|
||||
/*! exports provided: default */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/**
|
||||
* Appel une fonction après que le document est chargé.
|
||||
* @param {Function} fn - La fonction à appeler
|
||||
* @returns {void}
|
||||
*/
|
||||
/* harmony default export */ __webpack_exports__["default"] = (function (fn) {
|
||||
if (typeof fn !== 'function') {
|
||||
return;
|
||||
} // si le document est déjà chargé, on appel la fonction
|
||||
|
||||
|
||||
if (document.readyState === 'interactive' || document.readyState === 'complete') {
|
||||
fn();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', fn, false);
|
||||
});
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./assets/js/opted-tracking.js":
|
||||
/*!*************************************!*\
|
||||
!*** ./assets/js/opted-tracking.js ***!
|
||||
\*************************************/
|
||||
/*! exports provided: default */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var _helpers_ready__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helpers/ready */ "./assets/js/helpers/ready.js");
|
||||
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
|
||||
|
||||
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
|
||||
|
||||
function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
|
||||
|
||||
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
||||
|
||||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
||||
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Constantes
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
var Message = {
|
||||
ACTIVE: 'Votre visite sur ce site est actuellement <b>suivie anonymement</b>.',
|
||||
ACTIVE_HELP: 'Vous pouvez vous opposer au suivi en décochant cette case.',
|
||||
INACTIVE: 'Votre visite sur ce site n\'est actuellement <b>pas suivie</b>.',
|
||||
INACTIVE_HELP: 'Vous pouvez activer le suivi anonyme en cochant cette case afin de nous aider à améliorer notre site.',
|
||||
DONOTTRACK: 'Votre visite sur ce site n\'est <b>pas suivie</b>, conformément aux préférences de votre navigateur.',
|
||||
DONOTTRACK_HELP: 'La fonctionnalité <i>Do Not Track</i> étant activée dans les préférences de votre navigateur, elle prend le dessus sur le contrôle de votre suivi sur ce site.',
|
||||
OLDBROWSER_HELP: 'Votre navigateur semble trop vieux pour vous permettre de contrôler votre suivi. Pour plus de sécurité et de confidentialité, veuillez mettre à jour votre navigateur.'
|
||||
};
|
||||
var Default = {
|
||||
key: 'tracking',
|
||||
initial: true
|
||||
};
|
||||
var Selector = {
|
||||
CONTAINER: '.tracking-optout',
|
||||
CHECKBOX: 'input[type="checkbox"]',
|
||||
STATE: '.tracking-state',
|
||||
HELP: '.tracking-help'
|
||||
};
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Helpers
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Detects whether localStorage is both supported and available.
|
||||
* @link https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API#Testing_for_availability
|
||||
* @returns {Boolean} `true` if localStorage is usable.
|
||||
*/
|
||||
|
||||
function hasLocalStorage() {
|
||||
var storage;
|
||||
|
||||
try {
|
||||
storage = window.localStorage;
|
||||
var x = '__storage_test__';
|
||||
storage.setItem(x, x);
|
||||
storage.removeItem(x);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return e instanceof DOMException && ( // everything except Firefox
|
||||
e.code === 22 || // eslint-disable-line no-magic-numbers
|
||||
// Firefox
|
||||
e.code === 1014 || // eslint-disable-line no-magic-numbers
|
||||
// test name field too, because code might not be present
|
||||
// everything except Firefox
|
||||
e.name === 'QuotaExceededError' || // Firefox
|
||||
e.name === 'NS_ERROR_DOM_QUOTA_REACHED') && // acknowledge QuotaExceededError only if there's something already stored
|
||||
storage && storage.length !== 0;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Checks whether the user's do-not-track setting is enabled.
|
||||
* @returns {Boolean} `true` if the user should not be tracked.
|
||||
*/
|
||||
|
||||
|
||||
function hasDoNotTrack() {
|
||||
return navigator.doNotTrack === '1' || navigator.doNotTrack === 'yes' || navigator.msDoNotTrack === '1' || window.doNotTrack === '1';
|
||||
}
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Classe
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
var OptedTracking =
|
||||
/*#__PURE__*/
|
||||
function () {
|
||||
function OptedTracking(fn, config) {
|
||||
var _this = this;
|
||||
|
||||
_classCallCheck(this, OptedTracking);
|
||||
|
||||
if (typeof fn !== 'function') {
|
||||
throw new Error('Une fonction est attendue comme premier argument');
|
||||
}
|
||||
|
||||
this._elements = [];
|
||||
this._config = Object.assign({}, Default, config);
|
||||
this._dnt = hasDoNotTrack();
|
||||
this._localStorage = hasLocalStorage();
|
||||
this._enabled = this.getState(); // exécute la fonction dès que possible
|
||||
|
||||
if (this._enabled) {
|
||||
setTimeout(fn, 0);
|
||||
}
|
||||
|
||||
window.addEventListener('storage', function (e) {
|
||||
if (e.key === _this._config.key) {
|
||||
_this._refresh();
|
||||
}
|
||||
}); // attends que la page soit chargée pour initialiser les éléments
|
||||
|
||||
Object(_helpers_ready__WEBPACK_IMPORTED_MODULE_0__["default"])(function () {
|
||||
return _this._initElements();
|
||||
});
|
||||
} // Méthodes publiques
|
||||
|
||||
|
||||
_createClass(OptedTracking, [{
|
||||
key: "getState",
|
||||
value: function getState() {
|
||||
if (this._dnt) {
|
||||
return false;
|
||||
} else if (!this._localStorage) {
|
||||
return this._config.initial;
|
||||
}
|
||||
|
||||
var state = window.localStorage.getItem(this._config.key);
|
||||
|
||||
if (state === 'true') {
|
||||
return true;
|
||||
} else if (state === 'false') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this._config.initial;
|
||||
}
|
||||
}, {
|
||||
key: "setState",
|
||||
value: function setState(enabled) {
|
||||
window.localStorage.setItem(this._config.key, enabled ? 'true' : 'false'); // l'état étant changé dans ce contexte, il faut rafraichir manuellement
|
||||
|
||||
this._refresh();
|
||||
} // Méthodes privées
|
||||
|
||||
}, {
|
||||
key: "_refresh",
|
||||
value: function _refresh() {
|
||||
var enabled = this.getState();
|
||||
|
||||
if (this._dnt) {
|
||||
this._adjustElements(Message.DONOTTRACK, Message.DONOTTRACK_HELP, enabled, true);
|
||||
} else if (!this._localStorage) {
|
||||
this._adjustElements(enabled ? Message.ACTIVE : Message.INACTIVE, Message.OLDBROWSER_HELP, enabled, true);
|
||||
} else {
|
||||
this._adjustElements(enabled ? Message.ACTIVE : Message.INACTIVE, enabled ? Message.ACTIVE_HELP : Message.INACTIVE_HELP, enabled, false);
|
||||
} // si l'état a changé, il faut recharger la page
|
||||
|
||||
|
||||
if (enabled !== this._enabled) {
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: "_initElements",
|
||||
value: function _initElements() {
|
||||
var _this2 = this;
|
||||
|
||||
this._elements = _toConsumableArray(document.querySelectorAll(Selector.CONTAINER));
|
||||
this._checkboxes = [];
|
||||
this._states = [];
|
||||
this._helps = []; // parcours tous les conteneurs et ajoute leurs éléments
|
||||
|
||||
this._elements.forEach(function (container) {
|
||||
var checkbox = container.querySelector(Selector.CHECKBOX);
|
||||
var state = container.querySelector(Selector.STATE);
|
||||
var help = container.querySelector(Selector.HELP);
|
||||
|
||||
if (checkbox) {
|
||||
_this2._checkboxes.push(checkbox);
|
||||
}
|
||||
|
||||
if (state) {
|
||||
_this2._states.push(state);
|
||||
}
|
||||
|
||||
if (help) {
|
||||
_this2._helps.push(help);
|
||||
}
|
||||
});
|
||||
|
||||
this._checkboxes.forEach(function (checkbox) {
|
||||
checkbox.addEventListener('click', function () {
|
||||
return _this2.setState(checkbox.checked);
|
||||
});
|
||||
});
|
||||
|
||||
this._refresh();
|
||||
}
|
||||
}, {
|
||||
key: "_adjustElements",
|
||||
value: function _adjustElements(stateText, helpText, checked, disabled) {
|
||||
if (stateText) {
|
||||
this._states.forEach(function (el) {
|
||||
el.innerHTML = stateText;
|
||||
});
|
||||
}
|
||||
|
||||
if (helpText) {
|
||||
this._helps.forEach(function (el) {
|
||||
el.innerHTML = helpText;
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof checked === 'boolean') {
|
||||
this._checkboxes.forEach(function (el) {
|
||||
el.checked = checked;
|
||||
});
|
||||
}
|
||||
|
||||
if (disabled === true) {
|
||||
this._checkboxes.forEach(function (el) {
|
||||
return el.setAttribute('disabled', '');
|
||||
});
|
||||
} else if (disabled === false) {
|
||||
this._checkboxes.forEach(function (el) {
|
||||
return el.removeAttribute('disabled');
|
||||
});
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
return OptedTracking;
|
||||
}();
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Export
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/* harmony default export */ __webpack_exports__["default"] = (OptedTracking);
|
||||
|
||||
window.optedtracking = function (fn, config) {
|
||||
return new OptedTracking(fn.bind(window), config);
|
||||
};
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 0:
|
||||
/*!*******************************************!*\
|
||||
!*** multi ./assets/js/opted-tracking.js ***!
|
||||
\*******************************************/
|
||||
/*! no static exports found */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
module.exports = __webpack_require__(/*! /home/francois/cliss_xxi/bio-hdf/biohdf/assets/js/opted-tracking.js */"./assets/js/opted-tracking.js");
|
||||
|
||||
|
||||
/***/ })
|
||||
|
||||
/******/ });
|
||||
//# sourceMappingURL=opted-tracking.js.map
|
Diff de fichier supprimé car une ou plusieurs lignes sont trop longues
Diff de fichier supprimé car une ou plusieurs lignes sont trop longues
|
@ -1,4 +1,4 @@
|
|||
{% load staticfiles wagtailimages_tags wagtailcore_tags wagtailuserbar minified %}<!DOCTYPE html>
|
||||
{% load staticfiles wagtailimages_tags wagtailcore_tags wagtailsettings_tags wagtailuserbar minified %}<!DOCTYPE html>
|
||||
<html class="no-js" lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
@ -32,7 +32,16 @@
|
|||
<link rel="stylesheet" href="{% minified "css/fork-awesome.css" %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_head %}{% endblock %}
|
||||
{% block extra_head %}
|
||||
{% if settings.base.MatomoSettings.tracking_code %}
|
||||
<script src="{% minified "js/opted-tracking.js" %}"></script>
|
||||
<script type="text/javascript">
|
||||
optedtracking(function() {
|
||||
{{ settings.base.MatomoSettings.tracking_code|safe }}
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% load staticfiles menu_tags wagtailimages_tags wagtailcore_tags wagtailuserbar minified %}
|
||||
{% load staticfiles menu_tags wagtailimages_tags wagtailcore_tags wagtailsettings_tags wagtailuserbar minified %}
|
||||
<!DOCTYPE html>
|
||||
<html class="no-js" lang="fr">
|
||||
<head>
|
||||
|
@ -36,7 +36,16 @@
|
|||
<link rel="stylesheet" href="{% minified "css/fork-awesome.css" %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_head %}{% endblock %}
|
||||
{% block extra_head %}
|
||||
{% if settings.base.MatomoSettings.tracking_code %}
|
||||
<script src="{% minified "js/opted-tracking.js" %}"></script>
|
||||
<script type="text/javascript">
|
||||
optedtracking(function() {
|
||||
{{ settings.base.MatomoSettings.tracking_code|safe }}
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
{% wagtailuserbar %}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
{% extends "./sitepage.html" %}
|
||||
{% load wagtailcore_tags wagtailimages_tags %}
|
||||
|
||||
{% block extra_head %}{% include "./includes/style.html" with color=page.specific.action_color %}{% endblock %}
|
||||
{% block extra_head %}{{ block.super }}
|
||||
{% include "./includes/style.html" with color=page.specific.action_color %}
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}{{ page.title }}{% endblock %}
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
{% extends "./sitepage.html" %}
|
||||
{% load wagtailcore_tags wagtailsettings_tags %}
|
||||
|
||||
{% block extra_head %}{{ block.super }}
|
||||
{% include "./includes/style.html" with color="primary" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}Politique de confidentialité des données{% endblock %}
|
||||
|
||||
{% block inner_content %}
|
||||
<div class="bg-white py-2 px-3">
|
||||
<h2 class="page-title page-title-primary">
|
||||
Politique de confidentialité des données
|
||||
</h2>
|
||||
{% if settings.base.MatomoSettings.privacy_policy %}
|
||||
<div class="p-3 mt-5">
|
||||
{{ settings.base.MatomoSettings.privacy_policy|richtext }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if settings.base.MatomoSettings.tracking_code %}
|
||||
{% if not settings.base.MatomoSettings.privacy_policy %}
|
||||
<div class="bg-white py-2 px-3">
|
||||
<h2 class="mt-5">Suivi de votre visite</h2>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="form-group tracking-optout">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="tracking-optout" disabled>
|
||||
<label class="custom-control-label tracking-state" for="tracking-optout">
|
||||
<noscript>Le code JavaScript étant désactivé dans votre navigateur, votre visite sur ce site n'est <b>pas suivie</b>.</noscript>
|
||||
</label>
|
||||
</div>
|
||||
<div class="small form-text tracking-help"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -3,7 +3,9 @@
|
|||
|
||||
{% block title %}Résultats de votre recherche : « {{ search_query }} »{% endblock %}
|
||||
|
||||
{% block extra_head %}{% include "./includes/style.html" with color="tertiary" %}{% endblock %}
|
||||
{% block extra_head %}{{ block.super }}
|
||||
{% include "./includes/style.html" with color="tertiary" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block search_value %}value="{{ search_query }}"{% endblock %}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
{% extends "./base.html" %}
|
||||
{% load wagtailcore_tags wagtailimages_tags %}
|
||||
|
||||
{% block extra_head %}{% include "./includes/style.html" with color=page.specific.get_theme_color %}{% endblock %}
|
||||
{% block extra_head %}{{ block.super }}
|
||||
{% include "./includes/style.html" with color=page.specific.get_theme_color %}
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}{{ page.get_seo_title }}{% endblock %}
|
||||
|
||||
|
|
|
@ -59,6 +59,11 @@ urlpatterns = [
|
|||
'Sitemap: {}'.format(r.build_absolute_uri('sitemap.xml')),
|
||||
content_type="text/plain",
|
||||
)),
|
||||
|
||||
# Politique de confidentialité
|
||||
path('politique-de-confidentialite/',
|
||||
views.PrivacyPolicyView.as_view(),
|
||||
name='privacy-policy'),
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
|
|
|
@ -44,6 +44,7 @@ const CONFIG = {
|
|||
|
||||
// Paths to JavaScript entries which will be bundled
|
||||
JS_ENTRIES: [
|
||||
'assets/js/opted-tracking.js',
|
||||
'assets/js/app.js'
|
||||
],
|
||||
|
||||
|
|
Chargement…
Référencer dans un nouveau ticket