Last active
September 28, 2022 08:59
-
-
Save medoingthings/53bbdf9203fd6e02569ef64ef4f741a0 to your computer and use it in GitHub Desktop.
Calculate Average Storypoints on http://storypoint.poker/
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
javascript:var id%3D"53bbdf9203fd6e02569ef64ef4f741a0"%2Cfile%3D"storypoint-avg.js"%2Cuser%3D"medoingthings"%2Cxhr%3Dnew XMLHttpRequest%3Bxhr.overrideMimeType("application%2Fjson")%3Bxhr.open("GET"%2C"https%3A%2F%2Fgist.githubusercontent.com%2F"%2Buser%2B"%2F"%2Bid%2B"%2Fraw%2F"%2Bfile%2B"%3F"%2BMath.random())%3Bxhr.onreadystatechange%3Dfunction()%7Bif(4%3D%3D%3Dxhr.readyState)if(200%3D%3D%3Dxhr.status)console.log("Successfully loaded gist%3A"%2C%7Bid%3Aid%2Cfile%3Afile%2Cuser%3Auser%2Cresponse%3Axhr.responseText%7D)%2C(0%2Ceval)(xhr.responseText)%3Belse%7Bvar a%3D"GitHub Gist file did not load successfully and instead returned a status code of "%2Bxhr.status%2B"."%3Bconsole.error(a%2C%7Bid%3Aid%2Cfile%3Afile%2Cuser%3Auser%7D)%3Balert(a)%7D%7D%3Bxhr.send(null)%3Bvoid+0 |
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
/* | |
* Show average of planning poker cards when using https://storypoint.poker | |
* | |
* USAGE: | |
* 1) Save the `bookmarklet.txt` content (see above) from this Gist as a bookmark | |
* 2) Navigate to your estimation session on https://storypoint.poker | |
* 3) Click on the previously saved bookmarklet | |
* | |
* That’s it – the average will automatically be shown and updated | |
*/ | |
{ | |
const playersRootEl = document.querySelector('.MuiGrid-root.MuiGrid-container.MuiGrid-spacing-xs-1'); | |
const observerConfig = { | |
childList: true, | |
attributes: false, | |
characterData: false, | |
subtree: true | |
}; | |
/** | |
* Calculate average from array of numbers | |
* | |
* @param arr Array of integers to get the average from | |
* @returns Integer | |
*/ | |
const calculateAverage = function (array) { | |
const sum = array.reduce((a, b) => a + b, 0); | |
const avg = (sum / array.length) || 0; | |
// Max. 2 decimals | |
return avg % 1 ? avg.toFixed(2) : avg; | |
}; | |
/** | |
* Check DOM for valid votes | |
* | |
* @return Array [{ | |
* vote: Integer | |
* el: Node | |
* }, ...] | |
*/ | |
const getValidVotes = function () { | |
const allVotesElements = getVoteElements(); | |
const allValidVotesArr = []; | |
// Iterate over NodeList | |
[].forEach.call(allVotesElements, function (el) { | |
const input = el.innerText; | |
if (input && !isNaN(input)) { | |
allValidVotesArr.push({ | |
vote: parseFloat(input), | |
el: el | |
}); | |
} | |
}); | |
return allValidVotesArr; | |
}; | |
/** | |
* Get all elements that can contain votes | |
* | |
* @returns Array | |
*/ | |
const getVoteElements = function () { | |
return playersRootEl.querySelectorAll('.MuiGrid-root.MuiGrid-container.MuiGrid-spacing-xs-1 > .MuiGrid-root.MuiGrid-item.MuiGrid-grid-xs-1'); | |
}; | |
/** | |
* Updates the DOM according to the voting state | |
* | |
* @param state Array | |
*/ | |
const updateDOMState = function (state) { | |
const headlineEl = document.querySelector('.MuiGrid-root.MuiGrid-item.MuiGrid-grid-xs-12 > h6.MuiTypography-h6'); | |
const estimations = []; | |
if (state && state.length) { | |
state.forEach(item => { | |
item.el.style.backgroundColor = '#acbdc5'; | |
estimations.push(item.vote); | |
}); | |
headlineEl.innerText = `Average: ${calculateAverage(estimations)}`; | |
} else { | |
headlineEl.innerText = `Waiting ⏳`; | |
} | |
}; | |
/** | |
* Reset the DOM from earlier styling changes | |
*/ | |
const resetStyle = function () { | |
const allVotesElements = getVoteElements(); | |
[].forEach.call(allVotesElements, function (el) { | |
el.style.backgroundColor = ''; | |
}); | |
}; | |
/** | |
* Kick off DOM change detection | |
*/ | |
const init = function () { | |
window.ignitionStarted = true; | |
const observer = new MutationObserver(function () { | |
// Avoid detecting changes | |
this.disconnect(); | |
// Update DOM | |
resetStyle(); | |
updateDOMState(getValidVotes()); | |
// Continue observing | |
this.observe(playersRootEl, observerConfig); | |
}); | |
updateDOMState(getValidVotes()); | |
observer.observe(playersRootEl, observerConfig); | |
}; | |
// Prevent multiple instances of this script | |
if (!window.ignitionStarted) { | |
init(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment