let amendments; var baseRec = document.createElement("html"); function wrap(el, wrapper) { if (el.tagName === "DIV" || el.tagName === "SECTION" || el.tagName === "P" || el.tagName === "DT" || el.tagName === "DD" || el.tagName === "LI") { wrapChildren(el, wrapper); } else { wrapElement(el, wrapper); } } function wrapElement(el, wrapper) { el.parentNode.insertBefore(wrapper, el); wrapper.appendChild(el); } function wrapChildren(parent, wrapper) { const children = [...parent.childNodes]; if (children && children.length) { parent.insertBefore(wrapper, children[0]); for (let i in children) { wrapper.appendChild(children[i]); } } } function containerFromId(id) { const container = baseRec.querySelector('#' + id); if (!container) { throw new Error(`Unknown element with id ${id} in Recommendation used as basis, see https://github.com/w3c/webrtc-pc/blob/main/amendments.md for amendments management`); } return container; } function titleFromId(id) { const container = baseRec.querySelector('#' + id); if (!container) return id; return container.closest("section").querySelector("h1,h2,h3,h4,h5,h6").textContent; } function listPRs(pr) { const span = document.createElement("span"); span.appendChild(document.createTextNode(" (")); pr = Array.isArray(pr) ? pr : [pr]; for (let i in pr) { const number = pr[i]; const url = respecConfig.github.repoURL + "pull/" + number; const a = document.createElement("a"); a.href = url; a.textContent = `PR #${number}`; span.appendChild(a); if (i < pr.length - 1) { span.appendChild(document.createTextNode(", ")); } } span.appendChild(document.createTextNode(")")); return span; } function listTestUpdates(updates) { const s = document.createElement("span"); if (updates === "not-testable") { s.textContent = " (not testable)"; } else if (updates === "already-tested") { s.textContent = " (no change needed in tests)"; } else if (Array.isArray(updates)) { s.textContent = " - Changes to Web Platform Tests: "; updates.forEach(u => { const link = document.createElement("a"); link.href = "https://github.com/web-platform-tests/wpt/pull/" + u.split("#")[1]; link.textContent = "#" + u.split("#")[1]; s.append(link); s.append(" "); }); } return s; } const capitalize = s => s[0].toUpperCase() + s.slice(1); async function listAmendments() { amendments = await fetch("amendments.json").then(r => r.json()); baseRec.innerHTML = await fetch("base-rec.html").then(r => r.text()); for (let id of Object.keys(amendments)) { } let m; let i = 0; let consolidatedAmendments = {}; for (let id of Object.keys(amendments)) { // validate that an amendment is not embedded in another const container = containerFromId(id); if (amendments[id][0].difftype !== 'append') { const embedded = Object.keys(amendments).filter(iid => iid !== id).find(iid => container.querySelector("#" + iid)); if (embedded) { throw new Error(`The container with id ${id} marked as amended cannot embed the other container of amendment ${embedded}, see https://github.com/w3c/webrtc-pc/blob/main/amendments.md for amendments management`); } } // validate that a section has only one difftype, one amendment type, one amendemnt status if (amendments[id].some(a => a.difftype && a.difftype !== amendments[id][0].difftype)) { throw new Error(`Amendments in container with id ${id} are mixing "modification" and "append" difftypes, see https://github.com/w3c/webrtc-pc/blob/main/amendments.md for amendments management`); } if (amendments[id].some(a => a.type !== amendments[id][0].type)) { //throw new Error(`Amendments in container with id ${id} are mixing "corrections" and "addition" types`); } if (amendments[id].some(a => a.status !== amendments[id][0].status)) { throw new Error(`Amendments in container with id ${id} are mixing "candidate" and "proposed" amendments, see https://github.com/w3c/webrtc-pc/blob/main/amendments.md for amendments management`); } // Group by candidate id for listing in the appendix for (let amendment of amendments[id]) { if (!consolidatedAmendments[amendment.id]) { consolidatedAmendments[amendment.id] = []; } consolidatedAmendments[amendment.id].push({...amendment, section: id}); } } if (document.getElementById("changes")) { const ul = document.createElement("ul"); Object.values(consolidatedAmendments).forEach((amendment) => { const {status, id, type} = amendment[0]; const li = document.createElement("li"); const entriesUl = document.createElement("ul"); li.appendChild(document.createTextNode(`${capitalize(status)} ${capitalize(type)} ${id}: `)); amendment.forEach(({description, section, pr, testUpdates}, i) => { const entryLi = document.createElement("li"); entryLi.innerHTML = description; const link = document.createElement("a"); entryLi.appendChild(document.createTextNode(" - ")); link.href = "#" + section; link.textContent = `section ${titleFromId(section)}`; entryLi.appendChild(link); entryLi.appendChild(listPRs(pr)); entryLi.appendChild(listTestUpdates(testUpdates)); entriesUl.appendChild(entryLi); }); li.appendChild(entriesUl); ul.appendChild(li); }); document.getElementById("changes").appendChild(ul); } } function showAmendments() { for (let section of Object.keys(amendments)) { const target = document.getElementById(section); let wrapper = document.createElement("div"); if (amendments[section][0].difftype !== "append") { if (["LI", "DD"].includes(target?.tagName)) { wrapper = document.createElement(target.tagName); wrapper.className = "skip"; } } else { if (["DL"].includes(target?.tagName)) { wrapper = document.createElement("dt"); } } wrapper.id = section + "-change-wrapper"; const annotations = []; for (let {description, id, difftype, status, type, pr} of amendments[section]) { // integrate the annotations for candidate/proposed amendments // only when Status = REC // (but keep them all in for other statuses of changes) if (respecConfig.specStatus !== "REC" && (["correction", "addition"].includes(type) || ["candidate", "proposed"].includes(status))) { continue; } const amendmentDiv = document.createElement("div"); amendmentDiv.className = type; const marker = document.createElement("span"); marker.className = "marker"; marker.textContent = `${capitalize(status)} ${capitalize(type)} ${id}:`; const title = document.createElement("span"); title.innerHTML = description; amendmentDiv.appendChild(marker); amendmentDiv.appendChild(title); amendmentDiv.appendChild(listPRs(pr)); annotations.push(amendmentDiv); } for (let div of annotations) { wrapper.appendChild(div); } if (annotations.length) { const amendmentTitle = `${capitalize(amendments[section][0].status)} ${capitalize(amendments[section][0].type)}${amendments[section].length > 1 ? "s" : ""} ${amendments[section].map(a => `${a.id}`).join(', ')}`; const ui = document.createElement("fieldset"); ui.className = "diff-ui"; ui.innerHTML = ``; wrapper.appendChild(ui); if (amendments[section][0].difftype === "modify" || !amendments[section][0].difftype) { ui.querySelectorAll('input[type="radio"]').forEach(inp => { inp.setAttribute("aria-controls", `${section} ${section}-new`); }); ui.classList.add("modify"); let containerOld = containerFromId(section); containerOld = containerOld.cloneNode(true); containerOld.classList.add("diff-old", "exclude"); containerOld.setAttribute("aria-label", `Deletion from ${amendmentTitle}`); // clean up ids to avoid duplicates, but not for headings since they're required by pubrules containerOld.querySelectorAll("*:not(:is(h2,h3,h4,h5,h6))[id]").forEach(el => el.removeAttribute("id")); const containerNew = document.getElementById(section); if (!containerNew) throw new Error(`No element with id ${section} in editors draft, see https://github.com/w3c/webrtc-pc/blob/main/amendments.md for amendments management`); containerNew.classList.add("diff-new"); containerNew.id += "-new"; containerNew.setAttribute("aria-label", `Addition from ${amendmentTitle}`); containerNew.parentNode.insertBefore(containerOld, containerNew); containerNew.parentNode.insertBefore(wrapper, containerOld); wrap(containerOld, document.createElement("del")); wrap(containerNew, document.createElement("ins")); } else if (amendments[section][0].difftype === "append") { ui.classList.add("append"); const appendBase = document.getElementById(section); appendBase.appendChild(wrapper); const controlledIds = []; document.querySelectorAll(`.add-to-${section}`).forEach((el,i) => { el.setAttribute("aria-label", `Addition from ${amendmentTitle}`); el.classList.add('diff-new'); el.id = `${section}-new-${i}`; controlledIds.push(el.id); wrap(el, document.createElement("ins")); }); ui.querySelectorAll('input[type="radio"]').forEach(inp => { inp.setAttribute("aria-controls", `${section} ${controlledIds.join(" ")}`); }); } } } // We clean up any remaining duplicate ids that might be left const elements = [...document.querySelectorAll('[id]')]; const ids = []; const dups = []; elements.forEach(el => ids.includes(el.id) ? dups.push(el) : ids.push(el.id)); dups.forEach((el, i) => el.id = el.id + "-dedup-" + i); }