aboutPolicies.js (12610B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { XPCOMUtils } = ChromeUtils.importESModule( 8 "resource://gre/modules/XPCOMUtils.sys.mjs" 9 ); 10 11 ChromeUtils.defineESModuleGetters(this, { 12 schema: "resource:///modules/policies/schema.sys.mjs", 13 }); 14 15 function col(text, className) { 16 let column = document.createElement("td"); 17 if (className) { 18 column.classList.add(className); 19 } 20 let content = document.createTextNode(text); 21 column.appendChild(content); 22 return column; 23 } 24 25 function link(text) { 26 let column = document.createElement("td"); 27 let a = document.createElement("a"); 28 a.href = "https://mozilla.github.io/policy-templates/#" + text.toLowerCase(); 29 a.target = "_blank"; 30 let content = document.createTextNode(text); 31 a.appendChild(content); 32 column.appendChild(a); 33 return column; 34 } 35 36 function addMissingColumns() { 37 const table = document.getElementById("activeContent"); 38 let maxColumns = 0; 39 40 // count the number of columns per row and set the max number of columns 41 for (let i = 0, length = table.rows.length; i < length; i++) { 42 if (maxColumns < table.rows[i].cells.length) { 43 maxColumns = table.rows[i].cells.length; 44 } 45 } 46 47 // add the missing columns 48 for (let i = 0, length = table.rows.length; i < length; i++) { 49 const rowLength = table.rows[i].cells.length; 50 51 if (rowLength < maxColumns) { 52 let missingColumns = maxColumns - rowLength; 53 54 while (missingColumns > 0) { 55 table.rows[i].insertCell(); 56 missingColumns--; 57 } 58 } 59 } 60 } 61 62 /* 63 * This function generates the Active Policies content to be displayed by calling 64 * a recursive function called generatePolicy() according to the policy schema. 65 */ 66 67 function generateActivePolicies(data) { 68 let new_cont = document.getElementById("activeContent"); 69 new_cont.classList.add("active-policies"); 70 71 let policy_count = 0; 72 73 for (let policyName in data) { 74 const color_class = ++policy_count % 2 === 0 ? "even" : "odd"; 75 76 if (schema.properties[policyName].type == "array") { 77 for (let count in data[policyName]) { 78 let isFirstRow = count == 0; 79 let isLastRow = count == data[policyName].length - 1; 80 let row = document.createElement("tr"); 81 row.classList.add(color_class); 82 row.appendChild(col(isFirstRow ? policyName : "")); 83 generatePolicy( 84 data[policyName][count], 85 row, 86 1, 87 new_cont, 88 isLastRow, 89 data[policyName].length > 1 90 ); 91 } 92 } else if (schema.properties[policyName].type == "object") { 93 let count = 0; 94 for (let obj in data[policyName]) { 95 let isFirstRow = count == 0; 96 let isLastRow = count == Object.keys(data[policyName]).length - 1; 97 let row = document.createElement("tr"); 98 row.classList.add(color_class); 99 row.appendChild(col(isFirstRow ? policyName : "")); 100 row.appendChild(col(obj)); 101 generatePolicy( 102 data[policyName][obj], 103 row, 104 2, 105 new_cont, 106 isLastRow, 107 true 108 ); 109 count++; 110 } 111 } else { 112 let row = document.createElement("tr"); 113 row.appendChild(col(policyName)); 114 row.appendChild(col(JSON.stringify(data[policyName]))); 115 row.classList.add(color_class, "last_row"); 116 new_cont.appendChild(row); 117 } 118 } 119 120 if (policy_count < 1) { 121 let current_tab = document.querySelector(".active"); 122 if (Services.policies.status == Services.policies.ACTIVE) { 123 current_tab.classList.add("no-specified-policies"); 124 } else { 125 current_tab.classList.add("inactive-service"); 126 } 127 } 128 129 addMissingColumns(); 130 } 131 132 /* 133 * This is a helper recursive function that iterates levels of each 134 * policy and formats the content to be displayed accordingly. 135 */ 136 137 function generatePolicy(data, row, depth, new_cont, islast, arr_sep = false) { 138 const color_class = row.classList.contains("odd") ? "odd" : "even"; 139 140 if (Array.isArray(data)) { 141 for (let count in data) { 142 if (count == 0) { 143 if (count == data.length - 1) { 144 generatePolicy( 145 data[count], 146 row, 147 depth + 1, 148 new_cont, 149 islast ? islast : false, 150 true 151 ); 152 } else { 153 generatePolicy(data[count], row, depth + 1, new_cont, false, false); 154 } 155 } else if (count == data.length - 1) { 156 let last_row = document.createElement("tr"); 157 last_row.classList.add(color_class, "arr_sep"); 158 159 for (let i = 0; i < depth; i++) { 160 last_row.appendChild(col("")); 161 } 162 163 generatePolicy( 164 data[count], 165 last_row, 166 depth + 1, 167 new_cont, 168 islast ? islast : false, 169 arr_sep 170 ); 171 } else { 172 let new_row = document.createElement("tr"); 173 new_row.classList.add(color_class); 174 175 for (let i = 0; i < depth; i++) { 176 new_row.appendChild(col("")); 177 } 178 179 generatePolicy(data[count], new_row, depth + 1, new_cont, false, false); 180 } 181 } 182 } else if (typeof data == "object" && Object.keys(data).length) { 183 let count = 0; 184 for (let obj in data) { 185 if (count == 0) { 186 row.appendChild(col(obj)); 187 if (count == Object.keys(data).length - 1) { 188 generatePolicy( 189 data[obj], 190 row, 191 depth + 1, 192 new_cont, 193 islast ? islast : false, 194 arr_sep 195 ); 196 } else { 197 generatePolicy(data[obj], row, depth + 1, new_cont, false, false); 198 } 199 } else if (count == Object.keys(data).length - 1) { 200 let last_row = document.createElement("tr"); 201 for (let i = 0; i < depth; i++) { 202 last_row.appendChild(col("")); 203 } 204 205 last_row.appendChild(col(obj)); 206 last_row.classList.add(color_class); 207 208 if (arr_sep) { 209 last_row.classList.add("arr_sep"); 210 } 211 212 generatePolicy( 213 data[obj], 214 last_row, 215 depth + 1, 216 new_cont, 217 islast ? islast : false, 218 false 219 ); 220 } else { 221 let new_row = document.createElement("tr"); 222 new_row.classList.add(color_class); 223 224 for (let i = 0; i < depth; i++) { 225 new_row.appendChild(col("")); 226 } 227 228 new_row.appendChild(col(obj)); 229 generatePolicy(data[obj], new_row, depth + 1, new_cont, false, false); 230 } 231 count++; 232 } 233 } else { 234 row.appendChild(col(JSON.stringify(data))); 235 236 if (arr_sep) { 237 row.classList.add("arr_sep"); 238 } 239 if (islast) { 240 row.classList.add("last_row"); 241 } 242 new_cont.appendChild(row); 243 } 244 } 245 246 function generateErrors() { 247 const consoleStorage = Cc["@mozilla.org/consoleAPI-storage;1"]; 248 const storage = consoleStorage.getService(Ci.nsIConsoleAPIStorage); 249 const consoleEvents = storage.getEvents(); 250 const prefixes = [ 251 "Enterprise Policies", 252 "JsonSchemaValidator", 253 "Policies", 254 "WindowsGPOParser", 255 "Enterprise Policies Child", 256 "BookmarksPolicies", 257 "ProxyPolicies", 258 "WebsiteFilter Policy", 259 "macOSPoliciesParser", 260 ]; 261 262 let new_cont = document.getElementById("errorsContent"); 263 new_cont.classList.add("errors"); 264 265 let flag = false; 266 for (let err of consoleEvents) { 267 if (prefixes.includes(err.prefix)) { 268 flag = true; 269 let row = document.createElement("tr"); 270 row.appendChild(col(err.arguments[0])); 271 new_cont.appendChild(row); 272 } 273 } 274 if (!flag) { 275 let errors_tab = document.getElementById("category-errors"); 276 errors_tab.hidden = true; 277 } 278 } 279 280 function generateDocumentation() { 281 let new_cont = document.getElementById("documentationContent"); 282 new_cont.setAttribute("id", "documentationContent"); 283 284 // map specific policies to a different string ID, to allow updates to 285 // existing descriptions 286 let string_mapping = { 287 BackgroundAppUpdate: "BackgroundAppUpdate2", 288 Certificates: "CertificatesDescription", 289 DisableFirefoxAccounts: "DisableFirefoxAccounts1", 290 DisableMasterPasswordCreation: "DisablePrimaryPasswordCreation", 291 DisableSetDesktopBackground: "DisableSetAsDesktopBackground", 292 FirefoxHome: "FirefoxHome2", 293 Permissions: "Permissions2", 294 PopupBlocking: "PopupBlocking2", 295 SanitizeOnShutdown: "SanitizeOnShutdown2", 296 SecurityDevices: "SecurityDevices2", 297 SkipTermsOfUse: "SkipTermsOfUse2", 298 WindowsSSO: "Windows10SSO", 299 BrowserDataBackup: "Backup", 300 }; 301 let deprecated_policies = ["DisablePocket"]; 302 303 for (let policyName in schema.properties) { 304 if (deprecated_policies.includes(policyName)) { 305 continue; 306 } 307 let main_tbody = document.createElement("tbody"); 308 main_tbody.classList.add("collapsible"); 309 main_tbody.addEventListener("click", function () { 310 let content = this.nextElementSibling; 311 content.classList.toggle("content"); 312 }); 313 let row = document.createElement("tr"); 314 row.appendChild(link(policyName)); 315 let descriptionColumn = col(""); 316 let stringID = string_mapping[policyName] || policyName; 317 document.l10n.setAttributes(descriptionColumn, `policy-${stringID}`); 318 row.appendChild(descriptionColumn); 319 main_tbody.appendChild(row); 320 let sec_tbody = document.createElement("tbody"); 321 sec_tbody.classList.add("content"); 322 sec_tbody.classList.add("content-style"); 323 let schema_row = document.createElement("tr"); 324 if (schema.properties[policyName].properties) { 325 let column = col( 326 JSON.stringify(schema.properties[policyName].properties, null, 1), 327 "schema" 328 ); 329 column.colSpan = "2"; 330 schema_row.appendChild(column); 331 sec_tbody.appendChild(schema_row); 332 } else if (schema.properties[policyName].items) { 333 let column = col( 334 JSON.stringify(schema.properties[policyName], null, 1), 335 "schema" 336 ); 337 column.colSpan = "2"; 338 schema_row.appendChild(column); 339 sec_tbody.appendChild(schema_row); 340 } else { 341 let column = col("type: " + schema.properties[policyName].type, "schema"); 342 column.colSpan = "2"; 343 schema_row.appendChild(column); 344 sec_tbody.appendChild(schema_row); 345 if (schema.properties[policyName].enum) { 346 let enum_row = document.createElement("tr"); 347 column = col( 348 "enum: " + 349 JSON.stringify(schema.properties[policyName].enum, null, 1), 350 "schema" 351 ); 352 column.colSpan = "2"; 353 enum_row.appendChild(column); 354 sec_tbody.appendChild(enum_row); 355 } 356 } 357 new_cont.appendChild(main_tbody); 358 new_cont.appendChild(sec_tbody); 359 } 360 } 361 362 let gInited = false; 363 window.onload = function () { 364 if (gInited) { 365 return; 366 } 367 gInited = true; 368 369 let data = Services.policies.getActivePolicies(); 370 generateActivePolicies(data); 371 generateErrors(); 372 generateDocumentation(); 373 374 // Event delegation on #categories-nav element 375 let menu = document.getElementById("categories-nav"); 376 menu.addEventListener("change-view", e => show(e.target)); 377 378 if (location.hash) { 379 let sectionButton = document.getElementById( 380 "category-" + location.hash.substring(1) 381 ); 382 if (sectionButton) { 383 sectionButton.click(); 384 } 385 } 386 387 window.addEventListener("hashchange", function () { 388 if (location.hash) { 389 let sectionButton = document.getElementById( 390 "category-" + location.hash.substring(1) 391 ); 392 sectionButton.click(); 393 } 394 }); 395 }; 396 397 function show(button) { 398 let current_tab = document.querySelector(".active"); 399 let category = button.getAttribute("id").substring("category-".length); 400 let content = document.getElementById(category); 401 if (current_tab == content) { 402 return; 403 } 404 saveScrollPosition(current_tab.id); 405 current_tab.classList.remove("active"); 406 current_tab.hidden = true; 407 content.classList.add("active"); 408 content.hidden = false; 409 410 let title = document.getElementById("sectionTitle"); 411 title.textContent = button.textContent; 412 location.hash = category; 413 restoreScrollPosition(category); 414 } 415 416 const scrollPositions = {}; 417 function saveScrollPosition(category) { 418 const mainContent = document.querySelector(".main-content"); 419 scrollPositions[category] = mainContent.scrollTop; 420 } 421 422 function restoreScrollPosition(category) { 423 const scrollY = scrollPositions[category] || 0; 424 const mainContent = document.querySelector(".main-content"); 425 mainContent.scrollTo(0, scrollY); 426 }