Last active
April 14, 2020 08:39
-
-
Save poke/1fc94f494893b05b39c8446da0979446 to your computer and use it in GitHub Desktop.
[User script] StackExchange: Close hammer warning
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @id stackexchange-hammer-warning@poke | |
// @name StackExchange: Close hammer warning | |
// @description Show a warning when attempting to close a question as duplicate and you have no gold badge to hammer the question. | |
// @namespace poke | |
// @version 1.2.0 | |
// @author Patrick Westerhoff | |
// @include *://*.stackexchange.com/questions/* | |
// @include *://*.stackexchange.com/review/close/* | |
// @include *://meta.serverfault.com/questions/* | |
// @include *://meta.serverfault.com/review/close/* | |
// @include *://meta.stackoverflow.com/questions/* | |
// @include *://meta.stackoverflow.com/review/close/* | |
// @include *://meta.superuser.com/questions/* | |
// @include *://meta.superuser.com/review/close/* | |
// @include *://serverfault.com/questions/* | |
// @include *://serverfault.com/review/close/* | |
// @include *://stackoverflow.com/questions/* | |
// @include *://stackoverflow.com/review/close/* | |
// @include *://superuser.com/questions/* | |
// @include *://superuser.com/review/close/* | |
// @homepageURL https://gist.github.com/poke/1fc94f494893b05b39c8446da0979446 | |
// @updateURL https://gist.github.com/poke/1fc94f494893b05b39c8446da0979446/raw/stackexchange-hammer-warning.user.js | |
// @run-at document-end | |
// ==/UserScript== | |
const getUserBadges = (function () { | |
function fetchUserBadges () { | |
const userId = document.querySelector('.my-profile, .profile-me').href.match(/\/users\/(\d+)\//)[1]; | |
return fetch(new URL(`/ajax/users/tab/${userId}?tab=badges&sort=class`, window.location).href) | |
.then(result => result.text()) | |
.then(responseText => { | |
const doc = new DOMParser().parseFromString(responseText, 'text/html'); | |
const badges = new Set(); | |
for (const badge of doc.querySelectorAll('.user-badges .badge-tag .badge1')) { | |
badges.add(badge.parentNode.innerText.trim()); | |
} | |
return badges; | |
}); | |
} | |
let userBadges = null; | |
return async () => { | |
if (!userBadges) { | |
userBadges = await fetchUserBadges(); | |
} | |
return userBadges; | |
}; | |
})(); | |
function initializeQuestion() { | |
const closeLink = document.querySelector('.close-question-link'); | |
if (!closeLink) { | |
return; | |
} | |
const observer = new MutationObserver(mutations => { | |
const mutation = mutations.find(m => m.addedNodes.length === 1 && m.addedNodes[0].id === 'popup-close-question'); | |
if (!mutation) { | |
return; | |
} | |
const closePopup = mutation.addedNodes[0]; | |
const duplicateOption = closePopup.querySelector('input[name="closeReasonId"][value="Duplicate"]'); | |
if (!duplicateOption) { | |
return; | |
} | |
const hammerIcon = createHammerIcon(); | |
hammerIcon.setAttribute('class', 'hammer-icon'); | |
const duplicateOptionDescription = duplicateOption.closest('li').querySelector('.s-description'); | |
duplicateOptionDescription.parentNode.insertBefore(hammerIcon, duplicateOptionDescription); | |
const questionTags = Array.prototype.map.call(document.querySelectorAll('.post-taglist .post-tag'), | |
tag => decodeURIComponent(tag.href.match(/\/([^\/]+)$/)[1])); | |
// get user badges to check whether the question can be hammered | |
getUserBadges().then(badges => { | |
const duplicatePane = closePopup.querySelector('.close-as-duplicate-pane'); | |
const canHammer = questionTags.some(t => badges.has(t)); | |
hammerIcon.setAttribute('class', canHammer ? 'hammer-icon yes' : 'hammer-icon no'); | |
duplicateOption.closest('li').title = canHammer ? 'You can hammer this question' : 'You cannot hammer this question'; | |
if (canHammer) { | |
const submitButton = closePopup.querySelector('.js-popup-submit'); | |
const paneObserver = new MutationObserver(() => { | |
submitButton.textContent = duplicatePane.classList.contains('popup-active-pane') ? 'Close question' : 'Vote to close'; | |
}); | |
paneObserver.observe(duplicatePane, { attributes: true, attributeFilter: ['class'] }); | |
} else { | |
const hammerWarning = document.createElement('div'); | |
hammerWarning.className = 'hammer-warning'; | |
hammerWarning.appendChild(createHammerIcon()); | |
hammerWarning.appendChild(document.createElement('strong')).appendChild(document.createTextNode('Heads-up: ')); | |
hammerWarning.appendChild(document.createTextNode('This question cannot be hammered because you do not have a gold badge for any of the question’s tags.')); | |
duplicatePane.insertBefore(hammerWarning, duplicatePane.firstChild); | |
} | |
}); | |
}); | |
observer.observe(closeLink.parentNode, { childList: true }); | |
} | |
function createHammerIcon () { | |
const hammer = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); | |
hammer.setAttribute('viewBox', '0 0 32 32'); | |
hammer.innerHTML = '<path d="M14.4 13c.8-.7 2-2 2-3.2l3.2-2c.5-.4.4-1.3 0-1.8L13.8.4c-.6-.5-1.5-.5-2 0l-2 3.2c-1.5.2-2.4 1.2-4 2.7-1.4 1.5-2 2-2.4 3.8L.4 12c-.5.4-.5 1.5 0 2L6 19.6c.5.5 1.4.5 1.8 0l2-3.3c1.4 0 2.6-1 3.3-2l15.6 17.3c.5.5 1.2.5 1.6 0l1.5-1.5c.4-.3.4-1 0-1.4L14.3 13z"/>'; | |
return hammer; | |
} | |
// initialize | |
const reviewContent = document.querySelector('.review-content'); | |
if (reviewContent) { | |
const reviewObserver = new MutationObserver(mutations => { | |
if (mutations.some(m => Array.prototype.find.call(m.addedNodes, x => x.className === 'mainbar-full'))) { | |
initializeQuestion(); | |
} | |
}); | |
reviewObserver.observe(reviewContent, { childList: true }); | |
} | |
else { | |
initializeQuestion(); | |
} | |
const style = document.createElement('style'); | |
style.textContent = ` | |
.hammer-icon { | |
fill: #CCC; | |
width: 1.1em; | |
height: 1.1em; | |
position: absolute; | |
margin-left: .5em; | |
margin-top: .1em; | |
} | |
.hammer-icon.yes { | |
fill: #090; | |
} | |
.hammer-icon.no { | |
fill: #900; | |
} | |
.hammer-warning { | |
margin-bottom: 10px; | |
padding: 8px; | |
background: #FDD; | |
border: 1px solid #900; | |
border-left-width: 5px; | |
} | |
.hammer-warning > svg { | |
width: 16px; | |
height: 16px; | |
float: left; | |
margin-right: .5em; | |
} | |
`; | |
document.getElementsByTagName('head')[0].appendChild(style); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment