| 1 | function post(url, dataObj, success) { |
| 2 | // Create a FormData object |
| 3 | const formData = new FormData(); |
| 4 | |
| 5 | console.log(dataObj); |
| 6 | if (dataObj !== undefined) { |
| 7 | // Populate the FormData object with the object entries |
| 8 | Object.entries(dataObj).forEach(([key, value]) => { |
| 9 | formData.append(key, value); |
| 10 | }); |
| 11 | } |
| 12 | |
| 13 | // Send the POST request with the FormData object |
| 14 | fetch(url, { |
| 15 | method: "POST", |
| 16 | body: formData, |
| 17 | }) |
| 18 | .then((response) => { |
| 19 | /* |
| 20 | if (!response.ok) { |
| 21 | throw new Error("Network response was not ok"); |
| 22 | } |
| 23 | */ |
| 24 | return response.json(); // or .text() if the response is not in JSON format |
| 25 | }) |
| 26 | .then((data) => { |
| 27 | if (success !== undefined) { |
| 28 | //const json_data = JSON.parse(data); |
| 29 | success(data); |
| 30 | //success(json_data); |
| 31 | } |
| 32 | //console.log("Success:", data); |
| 33 | }) |
| 34 | .catch((error) => { |
| 35 | console.error("Error:", error); |
| 36 | }); |
| 37 | } |
| 38 | |
| 39 | |
| 40 | function change_lang(x) { |
| 41 | var y = document.getElementById("select_lang"); |
| 42 | post('/change_lang/' + y.value, {}, () => { |
| 43 | window.location.reload(); |
| 44 | } ) |
| 45 | } |
| 46 | |
| 47 | function initPrFilesTree() { |
| 48 | const input = document.querySelector("[data-pr-files-filter]"); |
| 49 | const tree = document.querySelector("[data-pr-files-tree]"); |
| 50 | if (!input || !tree) { |
| 51 | return; |
| 52 | } |
| 53 | |
| 54 | const clearButton = document.querySelector("[data-pr-files-filter-clear]"); |
| 55 | const countEl = document.querySelector("[data-pr-files-count]"); |
| 56 | const emptyEl = document.querySelector("[data-pr-files-filter-empty]"); |
| 57 | const rows = Array.from(tree.querySelectorAll(".r, [data-pr-tree-row]")); |
| 58 | const fileRows = rows.filter((row) => row.hasAttribute("p") || row.hasAttribute("data-file-path")); |
| 59 | const diffEls = Array.from(document.querySelectorAll("[data-diff-path]")); |
| 60 | const totalFiles = fileRows.length; |
| 61 | const collapsedDirs = new Set(); |
| 62 | |
| 63 | function pathForRow(row) { |
| 64 | return row.getAttribute("p") || row.getAttribute("q") || row.getAttribute("data-file-path") || row.getAttribute("data-dir-path") || ""; |
| 65 | } |
| 66 | |
| 67 | function addParentDirs(path, visibleDirs) { |
| 68 | const parts = path.split("/"); |
| 69 | let current = ""; |
| 70 | for (let i = 0; i < parts.length - 1; i++) { |
| 71 | current = current === "" ? parts[i] : current + "/" + parts[i]; |
| 72 | visibleDirs.add(current); |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | function isUnderCollapsed(path) { |
| 77 | for (const dir of collapsedDirs) { |
| 78 | if (path !== dir && path.indexOf(dir + "/") === 0) { |
| 79 | return true; |
| 80 | } |
| 81 | } |
| 82 | return false; |
| 83 | } |
| 84 | |
| 85 | function applyPrFilesFilter() { |
| 86 | const query = input.value.trim().toLowerCase(); |
| 87 | const visibleDirs = new Set(); |
| 88 | let visibleFileCount = 0; |
| 89 | |
| 90 | for (const row of fileRows) { |
| 91 | const path = row.getAttribute("p") || row.getAttribute("data-file-path") || ""; |
| 92 | if (query === "" || path.toLowerCase().indexOf(query) !== -1) { |
| 93 | visibleFileCount++; |
| 94 | addParentDirs(path, visibleDirs); |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | for (const row of rows) { |
| 99 | const filePath = row.getAttribute("p") || row.getAttribute("data-file-path"); |
| 100 | const dirPath = row.getAttribute("q") || row.getAttribute("data-dir-path"); |
| 101 | let visible = true; |
| 102 | |
| 103 | if (filePath) { |
| 104 | visible = query === "" || filePath.toLowerCase().indexOf(query) !== -1; |
| 105 | } else if (dirPath) { |
| 106 | visible = query === "" || visibleDirs.has(dirPath); |
| 107 | } |
| 108 | |
| 109 | if (visible && query === "" && isUnderCollapsed(pathForRow(row))) { |
| 110 | visible = false; |
| 111 | } |
| 112 | row.hidden = !visible; |
| 113 | } |
| 114 | |
| 115 | for (const diffEl of diffEls) { |
| 116 | const path = diffEl.getAttribute("data-diff-path") || ""; |
| 117 | diffEl.hidden = query !== "" && path.toLowerCase().indexOf(query) === -1; |
| 118 | } |
| 119 | |
| 120 | if (countEl) { |
| 121 | countEl.textContent = query === "" ? String(totalFiles) : visibleFileCount + " / " + totalFiles; |
| 122 | } |
| 123 | if (emptyEl) { |
| 124 | emptyEl.hidden = query === "" || visibleFileCount > 0; |
| 125 | } |
| 126 | if (clearButton) { |
| 127 | clearButton.hidden = input.value === ""; |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | for (const row of rows) { |
| 132 | if (!row.hasAttribute("q") && !row.hasAttribute("data-dir-path")) { |
| 133 | continue; |
| 134 | } |
| 135 | row.addEventListener("click", () => { |
| 136 | const path = row.getAttribute("q") || row.getAttribute("data-dir-path"); |
| 137 | if (!path) { |
| 138 | return; |
| 139 | } |
| 140 | if (collapsedDirs.has(path)) { |
| 141 | collapsedDirs.delete(path); |
| 142 | row.setAttribute("aria-expanded", "true"); |
| 143 | } else { |
| 144 | collapsedDirs.add(path); |
| 145 | row.setAttribute("aria-expanded", "false"); |
| 146 | } |
| 147 | applyPrFilesFilter(); |
| 148 | }); |
| 149 | } |
| 150 | |
| 151 | input.addEventListener("input", applyPrFilesFilter); |
| 152 | input.addEventListener("keydown", (event) => { |
| 153 | if (event.key === "Enter") { |
| 154 | event.preventDefault(); |
| 155 | } |
| 156 | }); |
| 157 | |
| 158 | if (clearButton) { |
| 159 | clearButton.addEventListener("click", () => { |
| 160 | input.value = ""; |
| 161 | input.focus(); |
| 162 | applyPrFilesFilter(); |
| 163 | }); |
| 164 | } |
| 165 | |
| 166 | applyPrFilesFilter(); |
| 167 | } |
| 168 | |
| 169 | function initPrReviewCommentBoxes() { |
| 170 | const root = document.querySelector(".pr-files-diffs"); |
| 171 | if (!root) { |
| 172 | return; |
| 173 | } |
| 174 | const placeholder = root.getAttribute("data-line-comment-placeholder") || ""; |
| 175 | |
| 176 | function ensureBox(row) { |
| 177 | if (!row || !row.hasAttribute("s") || !row.hasAttribute("l")) { |
| 178 | return null; |
| 179 | } |
| 180 | const next = row.nextElementSibling; |
| 181 | if (next && next.classList.contains("m")) { |
| 182 | return next; |
| 183 | } |
| 184 | const diff = row.closest("[data-diff-path]"); |
| 185 | const path = diff ? diff.getAttribute("data-diff-path") : ""; |
| 186 | const side = row.getAttribute("s") === "n" ? "new" : "old"; |
| 187 | const line = row.getAttribute("l") || ""; |
| 188 | if (!path || !line) { |
| 189 | return null; |
| 190 | } |
| 191 | const wrap = document.createElement("p"); |
| 192 | wrap.className = "m"; |
| 193 | const textarea = document.createElement("textarea"); |
| 194 | textarea.name = "rc::" + path + "::" + side + "::" + line; |
| 195 | textarea.rows = 2; |
| 196 | if (placeholder) { |
| 197 | textarea.placeholder = placeholder; |
| 198 | } |
| 199 | wrap.appendChild(textarea); |
| 200 | row.insertAdjacentElement("afterend", wrap); |
| 201 | return wrap; |
| 202 | } |
| 203 | |
| 204 | function rowFromEvent(event) { |
| 205 | const target = event.target instanceof Element ? event.target : null; |
| 206 | return target ? target.closest(".pr-diff__table > p[s][l]") : null; |
| 207 | } |
| 208 | |
| 209 | root.addEventListener("mouseover", (event) => { |
| 210 | ensureBox(rowFromEvent(event)); |
| 211 | }); |
| 212 | root.addEventListener("focusin", (event) => { |
| 213 | ensureBox(rowFromEvent(event)); |
| 214 | }); |
| 215 | root.addEventListener("click", (event) => { |
| 216 | const box = ensureBox(rowFromEvent(event)); |
| 217 | const textarea = box ? box.querySelector("textarea") : null; |
| 218 | if (textarea) { |
| 219 | textarea.focus(); |
| 220 | } |
| 221 | }); |
| 222 | } |
| 223 | |
| 224 | document.addEventListener("DOMContentLoaded", () => { |
| 225 | initPrFilesTree(); |
| 226 | initPrReviewCommentBoxes(); |
| 227 | }); |
| 228 | |