From 9bf2be5ae932df0c760660a98079bdff80c22211 Mon Sep 17 00:00:00 2001 From: Sage Vaillancourt Date: Mon, 16 Sep 2024 08:52:13 -0400 Subject: [PATCH] Add a simple author filter --- author-filter.js | 152 +++++++++++++++++++++++++++++++++++++++++++++++ manifest.json | 13 ++-- 2 files changed, 159 insertions(+), 6 deletions(-) create mode 100644 author-filter.js diff --git a/author-filter.js b/author-filter.js new file mode 100644 index 0000000..5cdeeab --- /dev/null +++ b/author-filter.js @@ -0,0 +1,152 @@ +const getTbody = () => { + const table = document.querySelector('#commits-table') + if (!table) { + return + } + const tbody = table.getElementsByTagName('tbody')[0] + return { + tbody, + rowNodes: tbody && [...tbody.childNodes] + } +} + +let mutationObserver +let isFiltered = false +const allRowNodes = [] + +const pushNewNodes = rowNodes => { + console.log(`pushNewNodes(${rowNodes.length} nodes) into allRowNodes (length ${allRowNodes.length})`) + let found = true + for (const row of rowNodes) { + if (!allRowNodes.includes(row)) { + found = false + } + if (!found) { + allRowNodes.push(row) + } + } +} + +const filterToAuthorName = (authorName, refreshing) => { + console.log({ authorName, refreshing, isFiltered }) + if (!refreshing && isFiltered) { + console.log('removeFilter redirect') + removeFilter() + return + } + isFiltered = true + const { tbody, rowNodes } = getTbody() + if (!tbody || !rowNodes.length) { + return + } + const badRowNodes = rowNodes.filter(row => !row.innerHTML.includes(authorName)) + badRowNodes.forEach(row => { + try { + tbody.removeChild(row) + } catch (e) { + // Continue removing + } + }) + pushNewNodes(rowNodes) + + // Scroll-event-consuming function: + // function(e) { + // return N !== undefined && N.event.triggered !== e.type ? N.event.dispatch.apply(t, arguments) : void 0 + // } + // document.getElementsByTagName('html')[0].dispatchEvent(new Event('scroll')) + + if (!refreshing) { + console.log('allRowNodes.pop()') + while (allRowNodes.pop()) {} + allRowNodes.push(...rowNodes) + mutationObserver = new MutationObserver((mutationList, observer) => { + addAuthorFilterClicks() + filterToAuthorName(authorName, true) + }) + mutationObserver.observe(tbody, { childList: true }) + } + // console.log('allRowNodes.length', allRowNodes.length) +} + +const removeFilter = () => { + isFiltered = false + const { tbody, rowNodes } = getTbody() + if (!tbody) { + return + } + console.log({ rowNodes, allRowNodes }) + mutationObserver.disconnect() + rowNodes.forEach(row => tbody.removeChild(row)) + allRowNodes.forEach(row => tbody.appendChild(row)) +} + +let notifyClearTimeoutId +let notifyDiv = document.createElement('div') +let hasAppended = false + +const notify = message => { + if (!hasAppended) { + document.getElementsByTagName('body')[0].appendChild(notifyDiv) + hasAppended = true + } + if (notifyClearTimeoutId) { + clearTimeout(notifyClearTimeoutId) + } + + notifyDiv.innerText = message + notifyDiv.style = ` + position: sticky; + min-height: 20px; + min-width: 100px; + background-color: #cad4e3; + z-index: 99; + top: 0; + text-align: center; + padding: 0.5em; + visibility: visible; + ` + + notifyClearTimeoutId = setTimeout(hideNotification, 5000) +} + +const hideNotification = () => { + if (notifyClearTimeoutId) { + clearTimeout(notifyClearTimeoutId) + } + notifyDiv.style.visibility = 'hidden' +} + +const addAuthorFilterClicks = () => { + const { rowNodes } = getTbody() + rowNodes?.forEach(row => { + const clickable = row.getElementsByClassName('aui-avatar-inner')[0] + const authorName = row.getElementsByClassName('name-section')[0]?.title + const clickListener = e => { + e.stopPropagation() + filterToAuthorName(authorName) + } + const mouseOverListener = () => { + notify(`Click to filter by the author '${authorName}'`) + } + clickable?.removeEventListener('click', clickListener) + clickable?.parentNode.removeEventListener('click', clickListener) + clickable?.removeEventListener('mouseenter', mouseOverListener) + clickable?.parentNode.removeEventListener('mouseenter', mouseOverListener) + clickable?.removeEventListener('mouseleave', hideNotification) + clickable?.parentNode.removeEventListener('mouseleave', hideNotification) + + clickable?.addEventListener('click', clickListener) + clickable?.parentNode.addEventListener('click', clickListener) + clickable?.addEventListener('mouseenter', mouseOverListener) + clickable?.parentNode.addEventListener('mouseenter', mouseOverListener) + clickable?.addEventListener('mouseleave', hideNotification) + clickable?.parentNode.addEventListener('mouseleave', hideNotification) + clickable && (clickable.style.cursor = 'pointer') + clickable?.parentNode && (clickable.parentNode.style.cursor = 'pointer') + console.log('clickable.style', clickable?.style) + console.log('clickable?.parentNode.style', clickable?.parentNode.style) + }) +} + +addFix(addAuthorFilterClicks) +setInterval(addAuthorFilterClicks, 5000) \ No newline at end of file diff --git a/manifest.json b/manifest.json index 9e4b682..eab022f 100644 --- a/manifest.json +++ b/manifest.json @@ -25,12 +25,13 @@ { "matches": ["*://git.add123.com/*"], "js": [ - "utils.js", - "backtick-comments.js", - "csharp-quotes.js", - "file-scroll.js", - "repo-search-sorter.js", - "var-highlighter.js" + "utils.js", + "author-filter.js", + "backtick-comments.js", + "csharp-quotes.js", + "file-scroll.js", + "repo-search-sorter.js", + "var-highlighter.js" ], "run_at": "document_start" }