1/** 2 * Privacy Management API 3 * 4 * This API is used to manage the privacy settings of a website. 5 */ 6class PrivacyMgmt { 7 constructor() { 8 this.tracking_items = []; 9 this.listeners = { 10 change: [], 11 }; 12 } 13 14 PREFERENCE_COOKIE_NAME = "django_privacy_mgmt_preferences"; 15 16 CATEGORIES = { 17 ESSENTIAL: { 18 required: true, 19 default: true, 20 }, 21 STATISTICS: { 22 required: false, 23 default: false, 24 }, 25 MARKETING: { 26 required: false, 27 default: false, 28 }, 29 SOCIAL_MEDIA: { 30 required: false, 31 default: false, 32 }, 33 MISCELLANEOUS: { 34 required: false, 35 default: false, 36 }, 37 }; 38 39 initModal() { 40 const privacyModal = $("#privacysettings"); 41 42 privacyModal.on("show.bs.modal", (e) => { 43 const checkboxes = document.querySelectorAll( 44 'input[data-js="privacy-check"]', 45 ); 46 if (checkboxes) { 47 checkboxes.forEach((checkbox) => { 48 const name = checkbox.getAttribute("name"); 49 const category = checkbox.getAttribute("data-category"); 50 checkbox.checked = 51 this.getPreference(name) || category === "ESSENTIAL"; 52 }); 53 } 54 }); 55 56 const saveButton = document.querySelector( 57 '[data-js="privacy-save-settings"]', 58 ); 59 if (saveButton) { 60 saveButton.addEventListener("click", (e) => { 61 e.preventDefault(); 62 const checkboxes = document.querySelectorAll( 63 'input[data-js="privacy-check"]', 64 ); 65 const preferences = {}; 66 checkboxes.forEach((checkbox) => { 67 const name = checkbox.getAttribute("name"); 68 preferences[name] = checkbox.checked; 69 }); 70 this.setPreferences(preferences); 71 72 privacyModal.modal("hide"); 73 }); 74 } 75 76 const infoToggles = document.querySelectorAll( 77 '[data-js="privacy-info-toggle"]', 78 ); 79 if (infoToggles) { 80 infoToggles.forEach((infoToggle) => { 81 infoToggle.addEventListener("click", (e) => { 82 e.preventDefault(); 83 const target = infoToggle.getAttribute("data-target"); 84 const info = document.getElementById(target); 85 info.style.maxHeight = 86 info.style.maxHeight && info.style.maxHeight !== "0px" 87 ? "0px" 88 : info.scrollHeight + "px"; 89 info.parentNode.classList.toggle("privacy-item--show"); 90 }); 91 }); 92 } 93 94 const categoryToggles = document.querySelectorAll( 95 'input[data-js="privacy-check"]', 96 ); 97 if (categoryToggles) { 98 categoryToggles.forEach((categoryToggle) => { 99 categoryToggle.addEventListener("change", (e) => { 100 // toggle all checkboxes in the category 101 const category = e.target.getAttribute("name"); 102 if (this.CATEGORIES.hasOwnProperty(category)) { 103 const categoryCheckboxes = document.querySelectorAll( 104 `input[data-category="${category}"]`, 105 ); 106 categoryCheckboxes.forEach((checkbox) => { 107 checkbox.checked = e.target.checked; 108 }); 109 } 110 }); 111 }); 112 } 113 114 return privacyModal; 115 } 116 117 initTrackingItems() { 118 this.tracking_items = JSON.parse( 119 document.getElementById("tracking_items").textContent, 120 ); 121 } 122 123 init() { 124 this.initTrackingItems(); 125 126 const privacyModal = this.initModal(); 127 128 const settingsButton = document.querySelector( 129 '[data-js="privacy-settings"]', 130 ); 131 if (settingsButton) { 132 settingsButton.addEventListener("click", (e) => { 133 e.preventDefault(); 134 this.showSettings(); 135 }); 136 } 137 138 const acceptAllButton = document.querySelector( 139 '[data-js="privacy-accept-all"]', 140 ); 141 if (acceptAllButton) { 142 acceptAllButton.addEventListener("click", (e) => { 143 e.preventDefault(); 144 this.setAcceptAll(); 145 privacyModal.modal("hide"); 146 }); 147 } 148 149 const rejectAllButton = document.querySelector( 150 '[data-js="privacy-reject-all"]', 151 ); 152 if (rejectAllButton) { 153 rejectAllButton.addEventListener("click", (e) => { 154 e.preventDefault(); 155 this.setRejectAll(); 156 privacyModal.modal("hide"); 157 }); 158 } 159 } 160 161 setPreference(name, value) { 162 const preferences = this._getPreferences(); 163 preferences[name] = value; 164 165 const tracking_item = this.tracking_items.find( 166 (item) => item.slug === name, 167 ); 168 if (tracking_item) { 169 preferences[tracking_item.id] = value; 170 } 171 172 if (this.CATEGORIES.hasOwnProperty(name)) { 173 // If it's a category, set all items in the category 174 for (const item of this.tracking_items) { 175 if (item.category === name) { 176 preferences[item.id] = value; 177 } 178 } 179 } 180 181 this.setPreferences(preferences); 182 } 183 184 setPreferences(preferences) { 185 const oldPreferences = this._getPreferences(); 186 187 Cookies.set(this.PREFERENCE_COOKIE_NAME, JSON.stringify(preferences), { 188 expires: 180, 189 }); 190 this.dispatchEvent("change", preferences); 191 192 // If preferences were removed, reload the page 193 for (const key in oldPreferences) { 194 if (oldPreferences[key] && !preferences[key]) { 195 location.reload(); 196 break; 197 } 198 } 199 } 200 201 setAcceptAll() { 202 const preferences = {}; 203 for (const category in this.CATEGORIES) { 204 preferences[category] = true; 205 } 206 for (const item of this.tracking_items) { 207 preferences[item.id] = true; 208 } 209 this.setPreferences(preferences); 210 } 211 212 setRejectAll() { 213 const preferences = {}; 214 this.setPreferences(preferences); 215 } 216 217 showSettings() { 218 $("#privacysettings").modal("show"); 219 } 220 221 _getPreferences() { 222 let preferences = Cookies.get(this.PREFERENCE_COOKIE_NAME); 223 try { 224 preferences = JSON.parse(preferences); 225 } catch (e) { 226 preferences = {}; 227 } 228 return preferences; 229 } 230 231 getPreference(name) { 232 this.initTrackingItems(); // Just to be sure 233 const preferences = this._getPreferences(); 234 235 if (preferences.hasOwnProperty(name)) { 236 return Boolean(preferences[name]); 237 } else { 238 // Is slug of a tracking item 239 const tracking_item = this.tracking_items.find( 240 (item) => item.slug === name, 241 ); 242 if (tracking_item && preferences.hasOwnProperty(tracking_item.id)) { 243 return Boolean(preferences[tracking_item.id]); 244 } 245 246 // Is category 247 if (this.CATEGORIES.hasOwnProperty(name)) { 248 return this.CATEGORIES[name]["default"]; 249 } else { 250 return false;
251 } 252 } 253 } 254 255 addListener(eventName, callback, name = null) { 256 // Ignore invalid names 257 if (this.listeners.hasOwnProperty(eventName)) { 258 this.listeners[eventName].push({ 259 callback: callback, 260 name: name, 261 }); 262 } 263 } 264 265 removeListener(eventName, callback, name = null) { 266 // Ignore invalid names 267 if (this.listeners.hasOwnProperty(eventName)) { 268 const listeners = this.listeners[eventName]; 269 for (let index in listeners) { 270 if ( 271 listeners[index].name === name && 272 listeners[index].callback === callback 273 ) { 274 this.listeners[eventName].splice(index, 1); 275 break; 276 } 277 } 278 } 279 } 280 281 dispatchEvent(eventName, preferences) { 282 // Ignore invalid names 283 for (let listener of this.listeners[eventName]) { 284 if (listener.name) { 285 const name = listener.name; 286 if (preferences.hasOwnProperty(name)) { 287 listener.callback(preferences[name]); 288 } 289 // Is slug of a tracking item 290 const tracking_item = this.tracking_items.find( 291 (item) => item.slug === name, 292 ); 293 294 if (tracking_item && preferences.hasOwnProperty(tracking_item.id)) { 295 listener.callback(preferences[tracking_item.id]); 296 } 297 } else { 298 listener.callback(preferences); 299 } 300 } 301 } 302} 303 304window.django_privacy_mgmt = new PrivacyMgmt(); 305window.addEventListener("DOMContentLoaded", (event) => { 306 window.django_privacy_mgmt.init(); 307});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.