Thread viewer for Bluesky

refactoring

Changed files
+41 -68
+41 -68
posting_stats_page.js
··· 18 18 this.submitButton = $(this.pageElement.querySelector('input[type="submit"]'), HTMLInputElement); 19 19 this.progressBar = $(this.pageElement.querySelector('input[type=submit] + progress'), HTMLProgressElement); 20 20 this.table = $(this.pageElement.querySelector('table.scan-result')); 21 + this.tableHead = $(this.table.querySelector('thead')); 22 + this.tableBody = $(this.table.querySelector('tbody')); 23 + this.listSelect = $(this.pageElement.querySelector('.list-choice select'), HTMLSelectElement); 24 + this.scanInfo = $(this.pageElement.querySelector('.scan-info')); 25 + this.scanType = this.form.elements['scan_type']; 21 26 22 27 this.setupEvents(); 23 28 ··· 26 31 } 27 32 28 33 setupEvents() { 29 - $(this.pageElement.querySelector('form')).addEventListener('submit', (e) => { 34 + this.form.addEventListener('submit', (e) => { 30 35 e.preventDefault(); 31 36 32 37 if (!this.scanStartTime) { ··· 38 43 39 44 this.rangeInput.addEventListener('input', (e) => { 40 45 let days = parseInt(this.rangeInput.value, 10); 41 - this.configurePostingStats({ days }); 46 + let label = $(this.pageElement.querySelector('input[type=range] + label')); 47 + label.innerText = (days == 1) ? '1 day' : `${days} days`; 42 48 }); 43 49 44 - this.pageElement.querySelectorAll('input[type="radio"]').forEach(r => { 50 + this.scanType.forEach(r => { 45 51 r.addEventListener('click', (e) => { 46 52 let value = $(r, HTMLInputElement).value; 47 53 ··· 67 73 /** @returns {Promise<void>} */ 68 74 69 75 async fetchLists() { 70 - let select = $(this.pageElement.querySelector('.list-choice select')); 71 76 let lists = await accountAPI.loadUserLists(); 72 77 73 78 let sorted = lists.sort((a, b) => { ··· 78 83 }); 79 84 80 85 for (let list of lists) { 81 - let opt = $tag('option', { value: list.uri, text: list.name + ' ' }); 82 - select.append(opt); 83 - } 84 - } 85 - 86 - /** @param {{ days: number }} args */ 87 - 88 - configurePostingStats(args) { 89 - if (args.days) { 90 - let label = $(this.pageElement.querySelector('input[type=range] + label')); 91 - label.innerText = (args.days == 1) ? '1 day' : `${args.days} days`; 86 + this.listSelect.append( 87 + $tag('option', { value: list.uri, text: list.name + ' ' }) 88 + ); 92 89 } 93 90 } 94 91 95 92 /** @returns {Promise<void>} */ 96 93 97 94 async scanPostingStats() { 98 - this.submitButton.value = 'Cancel'; 99 - 95 + let startTime = new Date().getTime(); 100 96 let requestedDays = this.selectedDaysRange(); 101 - 102 - this.progressBar.max = requestedDays; 103 - this.progressBar.value = 0; 104 - this.progressBar.style.display = 'inline'; 105 - 106 - this.table.style.display = 'none'; 97 + let scanType = this.scanType.value; 107 98 108 - let tbody = $(this.table.querySelector('tbody')); 109 - tbody.innerHTML = ''; 110 - 111 - let thead = $(this.table.querySelector('thead')); 112 - thead.innerHTML = ''; 113 - 114 - let startTime = new Date().getTime(); 115 - this.scanStartTime = startTime; 116 - 117 - let scanInfo = $(this.pageElement.querySelector('.scan-info')); 118 - scanInfo.style.display = 'none'; 99 + this.startScan(startTime, requestedDays); 119 100 120 101 /** @type {FetchAllOnPageLoad} */ 121 102 let onPageLoad = (data) => { ··· 126 107 this.updateProgress(data, startTime); 127 108 }; 128 109 129 - let scanType = this.form.elements['scan_type'].value; 130 - 131 110 if (scanType == 'home') { 132 111 let items = await accountAPI.loadHomeTimeline(requestedDays, { 133 112 onPageLoad: onPageLoad, 134 113 keepLastPage: true 135 114 }); 136 - 137 - if (this.scanStartTime != startTime) { 138 - return; 139 - } 140 115 141 116 this.updateResultsTable(items, startTime, requestedDays); 142 117 } else if (scanType == 'list') { 143 - let select = $(this.pageElement.querySelector('.list-choice select'), HTMLSelectElement); 144 - let list = select.value; 118 + let list = this.listSelect.value; 145 119 let items = await accountAPI.loadListTimeline(list, requestedDays, { 146 120 onPageLoad: onPageLoad, 147 121 keepLastPage: true 148 122 }); 149 - 150 - if (this.scanStartTime != startTime) { 151 - return; 152 - } 153 123 154 124 this.updateResultsTable(items, startTime, requestedDays, { showReposts: false }); 155 125 } else if (scanType == 'users') { ··· 172 142 })); 173 143 174 144 let datasets = await Promise.all(requests); 175 - 176 - if (this.scanStartTime != startTime) { 177 - return; 178 - } 179 - 180 145 let items = datasets.flat(); 181 146 182 147 this.updateResultsTable(items, startTime, requestedDays, { ··· 189 154 keepLastPage: true 190 155 }); 191 156 192 - if (this.scanStartTime != startTime) { 193 - return; 194 - } 195 - 196 157 this.updateResultsTable(items, startTime, requestedDays, { showTotal: false, showPercentages: false }); 197 158 } 198 159 } ··· 209 170 210 171 this.progressBar.value = daysBack; 211 172 } 212 - 213 173 214 174 /** @param {string[]} dids */ 215 175 ··· 265 225 */ 266 226 267 227 updateResultsTable(items, startTime, requestedDays, options = {}) { 228 + if (this.scanStartTime != startTime) { 229 + return; 230 + } 231 + 268 232 let users = {}; 269 233 let total = 0; 270 234 let allReposts = 0; ··· 284 248 let fetchedDays = (startTime - lastDate) / 86400 / 1000; 285 249 286 250 if (Math.ceil(fetchedDays) < requestedDays) { 287 - let scanInfo = $(this.pageElement.querySelector('.scan-info')); 288 - scanInfo.innerText = `🕓 Showing data from ${Math.round(fetchedDays)} days (the timeline only goes that far):`; 289 - scanInfo.style.display = 'block'; 251 + this.scanInfo.innerText = `🕓 Showing data from ${Math.round(fetchedDays)} days (the timeline only goes that far):`; 252 + this.scanInfo.style.display = 'block'; 290 253 } 291 254 292 255 daysBack = Math.min(requestedDays, fetchedDays); ··· 314 277 } 315 278 } 316 279 317 - let thead = $(this.table.querySelector('thead')); 318 280 let headRow = $tag('tr'); 319 281 320 282 if (options.showReposts !== false) { ··· 337 299 headRow.append($tag('th', { text: '% of all' })); 338 300 } 339 301 340 - thead.append(headRow); 341 - 342 - let tbody = $(this.table.querySelector('tbody')); 302 + this.tableHead.append(headRow); 343 303 344 304 if (options.showTotal !== false) { 345 305 let tr = $tag('tr.total'); ··· 361 321 tr.append($tag('td.percent', { text: '' })); 362 322 } 363 323 364 - tbody.append(tr); 324 + this.tableBody.append(tr); 365 325 } 366 326 367 327 let sorted = Object.values(users).sort(this.sortUserRows); ··· 390 350 tr.append($tag('td.percent', { text: ((user.own + user.reposts) * 100 / total).toFixed(1) + '%' })); 391 351 } 392 352 393 - tbody.append(tr); 353 + this.tableBody.append(tr); 394 354 } 395 355 396 356 this.table.style.display = 'table'; 397 - this.submitButton.value = 'Start scan'; 398 - this.progressBar.style.display = 'none'; 399 - this.scanStartTime = undefined; 357 + this.stopScan(); 358 + } 359 + 360 + startScan(startTime, requestedDays) { 361 + this.submitButton.value = 'Cancel'; 362 + 363 + this.progressBar.max = requestedDays; 364 + this.progressBar.value = 0; 365 + this.progressBar.style.display = 'inline'; 366 + 367 + this.table.style.display = 'none'; 368 + this.tableHead.innerHTML = ''; 369 + this.tableBody.innerHTML = ''; 370 + 371 + this.scanStartTime = startTime; 372 + this.scanInfo.style.display = 'none'; 400 373 } 401 374 402 375 stopScan() {