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)