From ad0c6c3993ac419409cad691d4eafd457682939b Mon Sep 17 00:00:00 2001 From: jels Date: Mon, 8 Jul 2019 11:08:33 +0200 Subject: [PATCH 1/3] TV2DK-2494: add advanced_settings_purposes_preserve --- src/scripts/core/core_config.js | 4 ++++ src/scripts/core/core_constants.js | 1 + test/fixtures/config/full.config.html | 1 + test/specs/core/core_config.spec.js | 4 ++++ 4 files changed, 10 insertions(+) diff --git a/src/scripts/core/core_config.js b/src/scripts/core/core_config.js index 84735973..53a85a78 100644 --- a/src/scripts/core/core_config.js +++ b/src/scripts/core/core_config.js @@ -235,6 +235,10 @@ export function getAdvancedSettingsPurposesDefault() { return getConfigValue(OIL_CONFIG.ATTR_ADVANCED_SETTINGS_PURPOSES_DEFAULT, false); } +export function getAdvancedSettingsPurposesPreserve() { + return getConfigValue(OIL_CONFIG.ATTR_ADVANCED_SETTINGS_PURPOSES_PRESERVE, false); +} + export function getDefaultToOptin() { return getConfigValue(OIL_CONFIG.ATTR_DEFAULT_TO_OPTIN, false); } diff --git a/src/scripts/core/core_constants.js b/src/scripts/core/core_constants.js index d98fc641..2582513f 100644 --- a/src/scripts/core/core_constants.js +++ b/src/scripts/core/core_constants.js @@ -30,6 +30,7 @@ export const OIL_CONFIG = { ATTR_IAB_VENDOR_WHITELIST: 'iabVendorWhitelist', ATTR_SHOW_LIMITED_VENDORS_ONLY: 'show_limited_vendors_only', ATTR_ADVANCED_SETTINGS_PURPOSES_DEFAULT: 'advanced_settings_purposes_default', + ATTR_ADVANCED_SETTINGS_PURPOSES_PRESERVE: 'advanced_settings_purposes_preserve', ATTR_DEFAULT_TO_OPTIN: 'default_to_optin', ATTR_GDPR_APPLIES_GLOBALLY: 'gdpr_applies_globally', ATTR_GDPR_APPLIES: 'gdpr_applies', diff --git a/test/fixtures/config/full.config.html b/test/fixtures/config/full.config.html index b592820c..b65891a2 100644 --- a/test/fixtures/config/full.config.html +++ b/test/fixtures/config/full.config.html @@ -8,6 +8,7 @@ "iabVendorBlacklist": true, "iabVendorWhitelist": true, "advanced_settings_purposes_default": true, + "advanced_settings_purposes_preserve": true, "default_to_optin": true, "poi_group_name": true, "privacy_page_url": true, diff --git a/test/specs/core/core_config.spec.js b/test/specs/core/core_config.spec.js index 51a1a4e2..3bd4e75b 100644 --- a/test/specs/core/core_config.spec.js +++ b/test/specs/core/core_config.spec.js @@ -1,6 +1,7 @@ import { gdprApplies, getAdvancedSettingsPurposesDefault, + getAdvancedSettingsPurposesPreserve, getConfigValue, getCookieExpireInDays, getCustomPurposes, @@ -124,6 +125,7 @@ describe('core_config', () => { const DEFAULT_COOKIE_EXPIRES_IN = 31; const DEFAULT_ADVANCED_SETTINGS_PURPOSES_DEFAULT = false; + const DEFAULT_ADVANCED_SETTINGS_PURPOSES_PRESERVE = false; const DEFAULT_DEFAULT_TO_OPTIN = false; const DEFAULT_POI_GROUP = 'default'; const DEFAULT_CUSTOM_PURPOSES = []; @@ -137,6 +139,7 @@ describe('core_config', () => { expect(getIabVendorBlacklist()).toEqual(true); expect(getDefaultToOptin()).toEqual(true); expect(getAdvancedSettingsPurposesDefault()).toEqual(true); + expect(getAdvancedSettingsPurposesPreserve()).toEqual(true); expect(getCustomPurposes()).toEqual(true); expect(getLocaleUrl()).toEqual(true); expect(getCookieExpireInDays()).toEqual(true); @@ -151,6 +154,7 @@ describe('core_config', () => { expect(getIabVendorBlacklist()).toBeFalsy(); expect(getDefaultToOptin()).toEqual(DEFAULT_DEFAULT_TO_OPTIN); expect(getAdvancedSettingsPurposesDefault()).toEqual(DEFAULT_ADVANCED_SETTINGS_PURPOSES_DEFAULT); + expect(getAdvancedSettingsPurposesPreserve()).toEqual(DEFAULT_ADVANCED_SETTINGS_PURPOSES_PRESERVE); expect(getCustomPurposes()).toEqual(DEFAULT_CUSTOM_PURPOSES); expect(getLocaleUrl()).toBeUndefined(); expect(getCookieExpireInDays()).toEqual(DEFAULT_COOKIE_EXPIRES_IN); From 49f9ef60a126c19815bc7d52014b2e698c4ef952 Mon Sep 17 00:00:00 2001 From: jels Date: Mon, 8 Jul 2019 13:00:00 +0200 Subject: [PATCH 2/3] TVDK-2494: preserve pending purposes between screens --- etc/appConfig.js | 12 +++ src/demos/cpc-custom-purposes-preserve.html | 87 +++++++++++++++++++ src/scripts/core/core_pending_purposes.js | 36 ++++++++ src/scripts/userview/userview_modal.js | 6 +- src/scripts/userview/userview_privacy.js | 23 ++++- .../view/oil.advanced.settings.standard.js | 17 +++- 6 files changed, 175 insertions(+), 6 deletions(-) create mode 100644 src/demos/cpc-custom-purposes-preserve.html create mode 100644 src/scripts/core/core_pending_purposes.js diff --git a/etc/appConfig.js b/etc/appConfig.js index 287b2937..23e9f4e7 100755 --- a/etc/appConfig.js +++ b/etc/appConfig.js @@ -75,6 +75,18 @@ module.exports = { chunks: ['oilstub', 'oil'], chunksSortMode: 'dependency', inject: 'head' + }, { + filename: 'demos/cpc-custom-purposes-default.html', + template: path.resolve(sourcePath, 'demos', 'cpc-custom-purposes-default.html'), + chunks: ['oilstub', 'oil'], + chunksSortMode: 'dependency', + inject: 'head' + }, { + filename: 'demos/cpc-custom-purposes-preserve.html', + template: path.resolve(sourcePath, 'demos', 'cpc-custom-purposes-preserve.html'), + chunks: ['oilstub', 'oil'], + chunksSortMode: 'dependency', + inject: 'head' }, { filename: 'demos/english-version.html', template: path.resolve(sourcePath, 'demos', 'english-version.html'), diff --git a/src/demos/cpc-custom-purposes-preserve.html b/src/demos/cpc-custom-purposes-preserve.html new file mode 100644 index 00000000..3b2128ce --- /dev/null +++ b/src/demos/cpc-custom-purposes-preserve.html @@ -0,0 +1,87 @@ + + + + + + Test Page + + + + + + + + +
Group A Site A
+ + diff --git a/src/scripts/core/core_pending_purposes.js b/src/scripts/core/core_pending_purposes.js new file mode 100644 index 00000000..d26795f2 --- /dev/null +++ b/src/scripts/core/core_pending_purposes.js @@ -0,0 +1,36 @@ +import { logInfo } from './core_log'; + +export let pendingPurposes = false; + +export function getPendingPurposes() { + return pendingPurposes; +} + +export function setPendingPurposes(purposes) { + pendingPurposes = purposes; + logInfo('set pending purposes', pendingPurposes) +} + +export function addPendingPurpose(Id) { + const id = parseInt(Id, 10); + if (pendingPurposes.indexOf(id) === -1) { + pendingPurposes.push(id); + logInfo('add pending purpose', id) + } +} + +export function removePendingPurpose(Id) { + const id = parseInt(Id, 10); + if (pendingPurposes.indexOf(id) !== -1) { + pendingPurposes = pendingPurposes.filter(i => i !== id); + logInfo('remove pending purpose', id) + } +} + +export function setPendingPurpose(Id, value) { + if(value) { + addPendingPurpose(Id); + } else { + removePendingPurpose(Id); + } +} diff --git a/src/scripts/userview/userview_modal.js b/src/scripts/userview/userview_modal.js index c18247d3..7f2eceb5 100644 --- a/src/scripts/userview/userview_modal.js +++ b/src/scripts/userview/userview_modal.js @@ -25,12 +25,13 @@ import * as AdvancedSettingsStandard from './view/oil.advanced.settings.standard import * as AdvancedSettingsTabs from './view/oil.advanced.settings.tabs'; import { logError, logInfo } from '../core/core_log'; import { getCpcType, getTheme, getTimeOutValue, isOptoutConfirmRequired, isPersistMinimumTracking } from './userview_config'; -import { gdprApplies, getAdvancedSettingsPurposesDefault, isPoiActive, getCustomPurposeIds } from '../core/core_config'; +import { gdprApplies, getAdvancedSettingsPurposesDefault, isPoiActive, getCustomPurposeIds, getAdvancedSettingsPurposesPreserve } from '../core/core_config'; import { applyPrivacySettings, getPrivacySettings, getSoiConsentData } from './userview_privacy'; import { activateOptoutConfirm } from './userview_optout_confirm'; import { getPurposeIds, loadVendorListAndCustomVendorList } from '../core/core_vendor_lists'; import { manageDomElementActivation } from '../core/core_tag_management'; import { sendConsentInformationToCustomVendors } from '../core/core_custom_vendors'; +import { getPendingPurposes, setPendingPurposes } from '../core/core_pending_purposes'; // Initialize our Oil wrapper and save it ... @@ -98,6 +99,9 @@ export function oilShowPreferenceCenter() { } else { currentPrivacySettings = getAdvancedSettingsPurposesDefault() ? [...getPurposeIds(), ...getCustomPurposeIds()] : []; } + if (!getPendingPurposes() && getAdvancedSettingsPurposesPreserve()) { + setPendingPurposes(currentPrivacySettings); + } applyPrivacySettings(currentPrivacySettings); }); }); diff --git a/src/scripts/userview/userview_privacy.js b/src/scripts/userview/userview_privacy.js index 351d3004..252365a2 100644 --- a/src/scripts/userview/userview_privacy.js +++ b/src/scripts/userview/userview_privacy.js @@ -2,7 +2,9 @@ import {getSoiCookie} from '../core/core_cookies'; import {PRIVACY_FULL_TRACKING} from '../core/core_constants'; import {logInfo} from '../core/core_log'; import {forEach} from './userview_modal'; -import {getPurposes} from '../core/core_vendor_lists'; +import {getPurposes, getPurposeIds} from '../core/core_vendor_lists'; +import {getAdvancedSettingsPurposesPreserve, getCustomPurposeIds} from '../core/core_config'; +import {getPendingPurposes} from '../core/core_pending_purposes'; export function getSoiConsentData() { let soiCookie = getSoiCookie(); @@ -19,6 +21,7 @@ export function getSoiConsentData() { * "{}": if there are multiple checkboxes */ export function getPrivacySettings() { + const pendingPurposes = getPendingPurposes(); if (document.querySelector('.as-js-purpose-slider')) { let result = {}; forEach(document.querySelectorAll('.as-js-purpose-slider'), (element) => { @@ -26,14 +29,28 @@ export function getPrivacySettings() { result[element_id] = element.checked; }, this); return result; + } else if (pendingPurposes && getAdvancedSettingsPurposesPreserve()) { + const result = {}; + [...getPurposeIds(), ...getCustomPurposeIds()].forEach((id) => { + result[id] = pendingPurposes.indexOf(id) !== -1; + }); + return result; } return PRIVACY_FULL_TRACKING; } export function applyPrivacySettings(allowedPurposes) { - logInfo('Apply privacy settings from cookie', allowedPurposes); + logInfo('Apply privacy settings', allowedPurposes, getPendingPurposes() ); + const pendingPurposes = getPendingPurposes(); - if (allowedPurposes === 1) { + if (pendingPurposes && getAdvancedSettingsPurposesPreserve()) { + forEach(document.querySelectorAll('.as-js-purpose-slider'), (domNode) => { + if (domNode) { + const id = parseInt(domNode.getAttribute('data-id'), 10); + domNode.checked = pendingPurposes.indexOf(id) !== -1; + } + }); + } else if (allowedPurposes === 1) { forEach(document.querySelectorAll('.as-js-purpose-slider'), (domNode) => { domNode && (domNode.checked = true); }); diff --git a/src/scripts/userview/view/oil.advanced.settings.standard.js b/src/scripts/userview/view/oil.advanced.settings.standard.js index 20785de2..ec813d7c 100644 --- a/src/scripts/userview/view/oil.advanced.settings.standard.js +++ b/src/scripts/userview/view/oil.advanced.settings.standard.js @@ -2,12 +2,12 @@ import '../../../styles/cpc_standard.scss'; import { OIL_LABELS } from '../userview_constants'; import { forEach } from '../userview_modal'; import { getLabel, getLabelWithDefault, getTheme } from '../userview_config'; -import { getCustomPurposes, getCustomVendorListUrl } from '../../core/core_config'; +import { getCustomPurposes, getCustomVendorListUrl, getAdvancedSettingsPurposesPreserve } from '../../core/core_config'; import { JS_CLASS_BUTTON_OPTIN, OIL_GLOBAL_OBJECT_NAME } from '../../core/core_constants'; import { setGlobalOilObject } from '../../core/core_utils'; import { getCustomVendorList, getPurposes, getVendorList, getVendorsToDisplay } from '../../core/core_vendor_lists'; import { BackButton, YesButton } from './components/oil.buttons'; - +import { setPendingPurpose } from '../../core/core_pending_purposes'; const CLASS_NAME_FOR_ACTIVE_MENU_SECTION = 'as-oil-cpc__category-link--active'; @@ -39,6 +39,11 @@ export function attachCpcHandlers() { forEach(document.querySelectorAll('.as-js-btn-deactivate-all'), (domNode) => { domNode && domNode.addEventListener('click', deactivateAll, false); }); + if (getAdvancedSettingsPurposesPreserve()) { + forEach(document.querySelectorAll('.as-js-purpose-slider'), (domNode) => { + domNode && domNode.addEventListener('click', handleToggle, false); + }); + } } @@ -204,6 +209,14 @@ export function deactivateAll() { }); } +function handleToggle(event) { + if (event && event.target) { + const val = event.target.checked || false; + const id = event.target.getAttribute('data-id') || 0; + setPendingPurpose(id, val); + } +} + function switchLeftMenuClass(element) { let allElementsInMenu = element.parentNode.children; From 6f3f58bd2fcebbaf7e5070e645ae9d5c530cb2f0 Mon Sep 17 00:00:00 2001 From: jels Date: Mon, 8 Jul 2019 13:26:33 +0200 Subject: [PATCH 3/3] TV2DK-2494: update naming --- src/scripts/core/core_pending_purposes.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scripts/core/core_pending_purposes.js b/src/scripts/core/core_pending_purposes.js index d26795f2..8bcbf631 100644 --- a/src/scripts/core/core_pending_purposes.js +++ b/src/scripts/core/core_pending_purposes.js @@ -11,16 +11,16 @@ export function setPendingPurposes(purposes) { logInfo('set pending purposes', pendingPurposes) } -export function addPendingPurpose(Id) { - const id = parseInt(Id, 10); +export function addPendingPurpose(str) { + const id = parseInt(str, 10); if (pendingPurposes.indexOf(id) === -1) { pendingPurposes.push(id); logInfo('add pending purpose', id) } } -export function removePendingPurpose(Id) { - const id = parseInt(Id, 10); +export function removePendingPurpose(str) { + const id = parseInt(str, 10); if (pendingPurposes.indexOf(id) !== -1) { pendingPurposes = pendingPurposes.filter(i => i !== id); logInfo('remove pending purpose', id)