Change Stash's default avatar to username initials
If you are using Atlassian's Stash at work, you must be annoyed by so many co-workers using the default avatar, which makes it so different to recognize different users. And you just couldn't ask them all to upload an avatar!
So here I write a small tampermonkey script to change the default avatar to their name initials.
const styleEl = document.createElement('style');
document.head.appendChild(styleEl);
styleEl.sheet.insertRule('.aui-avatar-inner { background-color: lightgray; color: white; font-weight: 700; line-height: 32px; }', 0);
styleEl.sheet.insertRule('.aui-avatar-small .aui-avatar-inner { line-height: 24px; }', 0);
const observer = new MutationObserver(function(mutations) {
document.querySelectorAll('img[src^="https://secure.gravatar.com"]').forEach((img) => {
const parent = img.parentElement;
const initials = img.alt.split(' ').map(s=>s[0]).join('');
parent.textContent = initials;
})
})
observer.observe(document, { childList: true, subtree: true });
Surely it would be much better if we could just use css without javascript. However, :has()
pseudo-class is still can not be used within stylesheets but only with functions like document.querySelector().
And the MutationObserver
used here is much faster than the conventional DOMNodeInserted
event. Just a reminder, in real life, a proper debounce to the callback is much appropriate here!
Update:
Just saw a brilliant way to detect DOM Node Insertion without using MutationObserver: Detect DOM Node Insertions with JavaScript and CSS Animations. So I updated the script as this:
let insertionObserver = function(selector, callback) {
const styleEl = document.createElement('style');
document.head.appendChild(styleEl);
const KeyframeName = 'insertionObserver';
const keyframesRule = `@keyframes ${KeyframeName} { from { opacity: 0.99; } to { opacity: 1; } }`;
const styleRule = `${selector} { animation-duration: 0.001s; animation-name: ${KeyframeName}; }`;
styleEl.sheet.insertRule(keyframesRule);
styleEl.sheet.insertRule(styleRule);
document.addEventListener('animationstart', (event) => {
if (event.animationName === KeyframeName) {
callback(event);
}
}, false);
}
insertionObserver('.aui-avatar-inner img[src^="https://secure.gravatar.com"]', (event) => {
let img = event.target;
const parent = img.parentElement;
const initials = img.alt.split(' ').map(s=>s[0]).join('');
const height = getComputedStyle(parent).height;
parent.setAttribute("style", `background-color: lightgray; color: white; line-height: ${height}`);
parent.textContent = initials;
});
Maybe it's time to create a repo to for these little helper functions, as my arsenal..