diff --git a/src/analytics/doc/analytics.md b/src/analytics/doc/analytics.md index d311db14f..55c7e2092 100644 --- a/src/analytics/doc/analytics.md +++ b/src/analytics/doc/analytics.md @@ -2,7 +2,7 @@ # Analytics > **Note** -> Ajout de la propriété `isActionEnabled` dans la configuration et sur l'objet `window.dsfr.analytics` permettant d'activer l'envoi de l'ensemble des données d'actions des composants. Pour activer l'envoi d'action sur des éléments spécifiques au cas par cas, il est possible d'ajouter l'attribut `data-fr-analytics-action` sur l'élément. +> Ajout de la propriété `isActionEnabled` dans la configuration et sur l'objet `window.dsfr.analytics` permettant d'activer l'envoi de l'ensemble des données d'actions des composants. Pour activer l'envoi d'action sur des éléments spécifiques au cas par cas, il est possible d'ajouter l'attribut `data-fr-analytics-action` sur l'élément. À l'inverse, lorsque l'envoi d'action est activé au global, l'attribut avec la valeur `data-fr-analytics-action="false"` permet de désaciver l'envoi sur un élément. > **Important** > La propriété de configuration `enableRating` a été retirée, celle-ci entraînant des envois de données trop importants. En remplacement, un attribut `data-fr-analytics-rating` peut être ajouté sur un élément dont on veut mesurer spécifiquement le taux de click. diff --git a/src/analytics/doc/analytics/actions.md b/src/analytics/doc/analytics/actions.md index b930d66ad..037b768b3 100644 --- a/src/analytics/doc/analytics/actions.md +++ b/src/analytics/doc/analytics/actions.md @@ -45,6 +45,7 @@ exemple d’actionName : `(click)_titre_niveau_2_›_titre_niveau_3_›_label_de Par défaut, l'envoi des actions est désactivé. Le paramètre de configuration `isActionEnabled` permet de l'activer. (voir [isActionEnabled dans Analytics](collector/analytics.md#isActionEnabled)). Il est possible de d'activer l'envoi sporadiquement sur un élément particulier en utilisant l'attribut `data-fr-analytics-action`, qui permet également de donner une valeur spécifique au title de l'[ActionName](#ActionName). +À l'inverse, il est possible de désactiver l'envoi d'actions sur un élément particulier en utilisant l'attribut `data-fr-analytics-action="false"` lorsque l'envoi d'actions est activé au global. #### Taux d'interaction diff --git a/src/analytics/doc/analytics/collector/analytics.md b/src/analytics/doc/analytics/collector/analytics.md index 484d1fb93..2c94c5142 100644 --- a/src/analytics/doc/analytics/collector/analytics.md +++ b/src/analytics/doc/analytics/collector/analytics.md @@ -120,11 +120,12 @@ _Boolean_ `window.dsfr.analytics.isActionEnabled` -Permet d’activer / désactiver la mesure d'audience des actions. +Permet d’activer / désactiver la mesure d'audience des actions au niveau global. * Par défaut, la mesure d'audience des actions est désactivée. Défini dans la configuration (voir propriété `isActionEnabled` de la [configuration](../installation/configuration.md)) +Voir [Activer les actions](../actions.md#Activer les actions) pour plus d'informations sur l'activation ou la désactivation des actions au cas par cas. * * * diff --git a/src/analytics/example/action/index.ejs b/src/analytics/example/action/index.ejs new file mode 100644 index 000000000..c1a8d267a --- /dev/null +++ b/src/analytics/example/action/index.ejs @@ -0,0 +1,14 @@ +
+
+

action activée

+
+ +
+
+
+

action prévenue

+
+ +
+
+
diff --git a/src/analytics/example/config.ejs b/src/analytics/example/config.ejs index 539b10074..4ecff4a04 100644 --- a/src/analytics/example/config.ejs +++ b/src/analytics/example/config.ejs @@ -5,7 +5,7 @@ analytics: { domain: 'gva.et-gv.fr', // collection: 'manual', // method of collection [manual, load, full, hash] - // isActionEnabled: true, // ensable action tracking + isActionEnabled: true, // enable action tracking cmp: { id: 'tarteaucitron' }, diff --git a/src/analytics/i18n/fr.yml b/src/analytics/i18n/fr.yml index 043956cbe..ed2f3784c 100644 --- a/src/analytics/i18n/fr.yml +++ b/src/analytics/i18n/fr.yml @@ -3,6 +3,7 @@ description: doc: subdir: title: Pages + action: Activation des actions attribute: Attributs component: Composants agnostic: sans framework @@ -76,4 +77,3 @@ subdir: translate: Sélecteur de langue (translate) upload: Ajout de fichier (upload) vue: Vue (vue) - diff --git a/src/analytics/script/analytics/action/action-element.js b/src/analytics/script/analytics/action/action-element.js index 776a20bd9..95a83c401 100644 --- a/src/analytics/script/analytics/action/action-element.js +++ b/src/analytics/script/analytics/action/action-element.js @@ -2,9 +2,10 @@ import api from '../../../api'; import actions from './actions'; import { Hierarchy } from '../utils/hierarchy/hierarchy'; import queue from '../engine/queue'; +import { ActionRegulation } from './action-regulation'; class ActionElement { - constructor (node, type, id, category = '', title = null, parameters = {}, isRating = false, isForced = false) { + constructor (node, type, id, category = '', title = null, parameters = {}, isRating = false, regulation = ActionRegulation.NONE) { this._node = node; this._type = type; this._id = id || this._node.id; @@ -13,7 +14,7 @@ class ActionElement { this._category = category; this._parameters = parameters; this._isRating = isRating; - this._isForced = isForced; + this._regulation = regulation; this._hasBegun = false; // this._init(); @@ -34,7 +35,7 @@ class ActionElement { if (this._type.isSingular) this._action.singularize(); Object.keys(this._parameters).forEach(key => this._action.addParameter(key, this._parameters[key])); this._action.isMuted = this._isMuted; - this._action.isForced = this._isForced; + this._action.regulation = this._regulation; this._action.labels[0] = this._type.id; this._action.labels[1] = this._hierarchy.globalComponent; @@ -57,6 +58,15 @@ class ActionElement { if (this._action) this._action.isMuted = value; } + get regulation () { + return this._regulation; + } + + set regulation (value) { + this._regulation = value; + if (this._action) this._action.regulation = value; + } + get action () { return this._action; } diff --git a/src/analytics/script/analytics/action/action-regulation.js b/src/analytics/script/analytics/action/action-regulation.js new file mode 100644 index 000000000..d63715988 --- /dev/null +++ b/src/analytics/script/analytics/action/action-regulation.js @@ -0,0 +1,5 @@ +export const ActionRegulation = { + ENFORCE: 'enforce', + PREVENT: 'prevent', + NONE: 'none' +}; diff --git a/src/analytics/script/analytics/action/action.js b/src/analytics/script/analytics/action/action.js index d68ae1b32..593dd8192 100644 --- a/src/analytics/script/analytics/action/action.js +++ b/src/analytics/script/analytics/action/action.js @@ -3,6 +3,7 @@ import normalize from '../utils/normalize'; import { ActionMode } from './action-mode'; import { validateString } from '../utils/type-validator'; import { ActionStatus } from './action-status'; +import { ActionRegulation } from './action-regulation'; const getParametersLayer = (data) => { return Object.entries(data).map(([key, value]) => ['actionpname', normalize(key), 'actionpvalue', normalize(value)]).flat(); @@ -11,7 +12,7 @@ const getParametersLayer = (data) => { class Action { constructor (name) { this._isMuted = false; - this._isForced = false; + this._regulation = ActionRegulation.NONE; this._name = name; this._status = ActionStatus.UNSTARTED; this._labels = []; @@ -27,12 +28,12 @@ class Action { this._isMuted = value; } - get isForced () { - return this._isForced; + get regulation () { + return this._regulation; } - set isForced (value) { - this._isForced = value; + set regulation (value) { + if (Object.values(ActionRegulation).includes(value)) this._regulation = value; } get isSingular () { diff --git a/src/analytics/script/analytics/engine/queue.js b/src/analytics/script/analytics/engine/queue.js index 02d7fc0d4..6e943f809 100644 --- a/src/analytics/script/analytics/engine/queue.js +++ b/src/analytics/script/analytics/engine/queue.js @@ -3,6 +3,7 @@ import PushType from '../facade/push-type.js'; import push from '../facade/push.js'; import renderer from './renderer'; import api from '../../../api'; +import { ActionRegulation } from '../action/action-regulation'; const SLICE = 80; @@ -42,23 +43,31 @@ class Queue { this._request(); } - appendStartingAction (action, data) { - if (!this._collector.isActionEnabled && !action.isForced) return; - if (!action || this._startingActions.some(queued => queued.test(action))) { - api.inspector.log('appendStartingAction exists or null', action); - return; + regulate (action, queue) { + if (!action) return false; + if (queue.some(queued => queued.test(action))) { + api.inspector.log('action exists in queue', action); + return false; + } + switch (action.regulation) { + case ActionRegulation.PREVENT: + return false; + case ActionRegulation.ENFORCE: + return true; + default: + return this._collector.isActionEnabled; } + } + + appendStartingAction (action, data) { + if (!this.regulate(action, this._startingActions)) return; const queued = new QueuedAction(action, data); this._startingActions.push(queued); this._request(); } appendEndingAction (action, data) { - if (!this._collector.isActionEnabled && !action.isForced) return; - if (!action || this._endingActions.some(queued => queued.test(action))) { - api.inspector.log('appendEndingAction exists or null', action); - return; - } + if (!this.regulate(action, this._endingActions)) return; const queued = new QueuedAction(action, data); this._endingActions.push(queued); this._request(); diff --git a/src/analytics/script/integration/core/actionee.js b/src/analytics/script/integration/core/actionee.js index 20df4d108..cfbd88b28 100644 --- a/src/analytics/script/integration/core/actionee.js +++ b/src/analytics/script/integration/core/actionee.js @@ -2,6 +2,8 @@ import api from '../../../api.js'; import { Type } from '../../analytics/action/type'; import { ActionElement } from '../../analytics/action/action-element'; import { ActioneeEmission } from './actionee-emission'; +import { ActionRegulation } from '../../analytics/action/action-regulation'; +import normalize from '../../analytics/utils/normalize'; const ActionAttributes = { RATING: api.internals.ns.attr('analytics-rating'), @@ -9,7 +11,7 @@ const ActionAttributes = { }; class Actionee extends api.core.Instance { - constructor (priority = -1, category = '', title = null, isForced = false) { + constructor (priority = -1, category = '', title = null, regulation = ActionRegulation.NONE) { super(); this._type = null; this._priority = priority; @@ -18,7 +20,7 @@ class Actionee extends api.core.Instance { this._parameters = {}; this._data = {}; this._isMuted = false; - this._isForced = isForced; + this._regulation = regulation; } static get instanceClassName () { @@ -66,7 +68,13 @@ class Actionee extends api.core.Instance { return; } - this._actionElement = new ActionElement(this.node, this._type, this.id, this._category, this.getAttribute(ActionAttributes.ACTION) || this._title, this._parameters, this.hasAttribute(ActionAttributes.RATING), this.hasAttribute(ActionAttributes.ACTION) || this._isForced); + const regulation = this.getRegulation(); + this._regulation = regulation !== ActionRegulation.NONE ? regulation : this._regulation; + const actionAttribute = this.getAttribute(ActionAttributes.ACTION); + const title = typeof actionAttribute === 'string' && actionAttribute.toLowerCase() !== 'false' && actionAttribute.toLowerCase() !== 'true' ? normalize(actionAttribute) : this._title; + this._isRating = this.hasAttribute(ActionAttributes.RATING); + + this._actionElement = new ActionElement(this.node, this._type, this.id, this._category, title, this._parameters, this._isRating, this._regulation); if (this._isMuted) this._actionElement.isMuted = true; this.addDescent(ActioneeEmission.REWIND, this.rewind.bind(this)); @@ -74,6 +82,29 @@ class Actionee extends api.core.Instance { this._sort(element); } + getRegulation () { + const actionAttribute = this.getAttribute(ActionAttributes.ACTION); + switch (true) { + case typeof actionAttribute === 'string' && actionAttribute.toLowerCase() === 'false': + return ActionRegulation.PREVENT; + case actionAttribute !== null: + return ActionRegulation.ENFORCE; + default: + return ActionRegulation.NONE; + } + } + + mutate (attributeNames) { + if (attributeNames.includes(ActionAttributes.ACTION)) { + const regulation = this.getRegulation(); + if (this._regulation !== regulation) { + this._regulation = regulation; + if (this._actionElement) this._actionElement.regulation = regulation; + } + } + super.mutate(attributeNames); + } + _sort (element) { const actionees = element.instances.filter(instance => instance.isActionee).sort((a, b) => b.priority - a.priority); if (actionees.length <= 1) return;