Last active
March 15, 2018 07:17
-
-
Save gbrian/99d2403441b0d3c4b59c2ff5b1b4f0c7 to your computer and use it in GitHub Desktop.
Trello gamification
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
/** | |
* REFERENCES | |
* - https://www.cssscript.com/demo/pure-css-circular-percentage-bar/ | |
* - http://game-icons.net | |
* - https://developers.trello.com/reference/ | |
*/ | |
Array.prototype.do = function(cb){ | |
return this.map(function(){ | |
var args = [].slice.call(arguments); | |
cb.apply(this, args); | |
return args[0]; | |
}); | |
} | |
function TrelloBoard(options) { | |
this.options = Object.assign({ | |
baseUrl : "https://trello.com/1/boards/", | |
agile:{ | |
backlog: "Backlog", | |
ongoing: "Ongoing", | |
test: "Test", | |
done: "Ready for Deploy", | |
release: "Deployed", | |
impediment: "Impeeded" | |
} | |
}, options); | |
return this; | |
} | |
TrelloBoard.prototype.G_PostEvent = function(name, data){ | |
$(window).trigger(name, data); | |
}; | |
TrelloBoard.prototype.G_SubscribeEvent = function(name, cb){ | |
$(window).on(name, cb); | |
}; | |
TrelloBoard.prototype.extend = function(target, url, key){ | |
return $.getJSON(url) | |
.then(data => { | |
if(key) target[key] = data; | |
else Object.assign(target, data); | |
return target; | |
}); | |
} | |
TrelloBoard.prototype.buildAgileLists = function(board){ | |
board.agile = { | |
getWorkingCards: function(user){ | |
return this.ongoing | |
.concat(this.test) | |
.filter(c => !user || | |
((!c.idMembers.length && !user.id) // Anonymous | |
|| c.idMembers.indexOf(user.id) !== -1)); | |
} | |
}; | |
var ids = Object.keys(this.options.agile) | |
.map(k => ({key: k, name: this.options.agile[k]})) | |
.map(kv => ({key: kv.key, list: board.lists.filter(l => l.name === kv.name)[0]})) | |
.filter(l => l) | |
.do(kv => board.agile[kv.key] = board.cards.filter(c => c.idList === kv.list.id)) | |
.map(kv => kv.list.id); | |
// Remove cards thar are not on the agile list | |
board.cards = board.cards.filter(c => ids.indexOf(c.idList) !== -1); | |
return board; | |
}; | |
TrelloBoard.prototype.enrichCards = function(board){ | |
board.cards | |
.do(c => c.labels.map(l => l.set = (c.idLabels.indexOf(l.id) !== -1))) | |
.do(c => c.list = board.lists.filter(l => l.id === c.idList)[0].name); | |
return board; | |
}; | |
TrelloBoard.prototype.getCards = function(list){ | |
return this.cards.filter(c => c.list === list); | |
} | |
/** | |
* Loads board members, cards, profiles and latest activity | |
*/ | |
TrelloBoard.prototype.load = function () { | |
var oThis = this; | |
// Base info | |
return this.extend(oThis, oThis.options.baseUrl + oThis.options.token) | |
// Board cards | |
.then(board => oThis.extend(board, oThis.options.baseUrl + oThis.id + "/cards", 'cards')) | |
// Board lists | |
.then(board => oThis.extend(board, oThis.options.baseUrl + oThis.id + "/lists", 'lists')) | |
.then(board => oThis.buildAgileLists(board)) | |
.then(board => oThis.enrichCards(board)) | |
// Board members | |
.then(board => oThis.extend(board, oThis.options.baseUrl + oThis.id + "/members", 'members')) | |
// Members profile | |
.then(board => board.members | |
.map(m => board.extend(m, "https://trello.com/1/members/"+m.id) | |
.then(m => { | |
m.getProfilePic = function(){ | |
if(this.avatarHash) | |
return '<img src="https://trello-avatars.s3.amazonaws.com/'+this.avatarHash+'/30.png"/>'; | |
return '<span class="member-initials member" title="'+''+'">'+this.initials+'</span>'; | |
}; | |
m.history = []; | |
m.references = []; | |
m.team = m.idOrganizations.indexOf(board.options.idOrganization) !== -1 ? "pigs": "chickens"; | |
return m; | |
}))) | |
.then(promises => $.when.apply($, promises).then(() => oThis)) | |
// Cards activity | |
.then(board => board.cards | |
.map(c => board.extend(c, "https://trello.com/1/cards/"+c.id+"/actions?filter=all", 'history') | |
.then(c => c.idMemberCreator = | |
(c.history.filter(h => h.type === "createCard")[0]||{}).idMemberCreator))) | |
.then(promises => $.when.apply($, promises).then(() => oThis)) | |
// Members activity | |
.then(board => { | |
var userRef = board.members.map(m =>({user:m, ref: "@"+m.username})); | |
var history = board.cards.map(c => c.history).reduce((a,b) => a.concat(b)); | |
var refs = history.filter(h => h.type === "commentCard") | |
.map(h => userRef.filter(ur => h.data.text.indexOf(ur.ref) !== -1) | |
.map(ur => Object.assign(h, { | |
idMemberCreator: ur.user.id, | |
type: "memberReferenced" | |
}))).reduce((a,b) => a.concat(b)); | |
history | |
.concat(refs) | |
.filter((value, index, self) => self.find(v => v.id === value.id).date >= value.date) | |
.map(a => (board.members.filter(m => m.id === a.idMemberCreator)[0]||{history:[]}).history.push(a)); | |
return board; | |
}) | |
// Anonymous | |
.then(board => { | |
board.members.push({ | |
id:null, | |
fullName: "Anonymous", | |
initials: "??", | |
getProfilePic : function(){ | |
return '<img src="https://www.shareicon.net/data/128x128/2016/02/19/721756_people_512x512.png"/>'; | |
}, | |
history:[], | |
idOrganizations:[board.options.idOrganization] | |
}); | |
return board; | |
}); | |
}; | |
/** | |
* Badges section | |
* http://game-icons.net | |
*/ | |
function TrelloBadges(){ | |
this.BadgesImages = { | |
Backlog: "http://game-icons.net/icons/faithtoken/originals/svg/card-draw.svg", | |
Released: "http://game-icons.net/icons/lorc/originals/svg/octopus.svg", | |
Tested: "http://game-icons.net/icons/lorc/originals/svg/lightning-arc.svg", | |
Done: "http://game-icons.net/icons/delapouite/gui/svg/checklist.svg", | |
BugKiller: "http://game-icons.net/icons/skoll/originals/svg/spotted-bug.svg", | |
King: "http://game-icons.net/icons/delapouite/originals/svg/throne-king.svg", | |
Impediment: "http://game-icons.net/icons/delapouite/originals/svg/handcuffed.svg", | |
Create: "http://game-icons.net/icons/quoting/originals/svg/card-play.svg", | |
Comment: "http://game-icons.net/icons/skoll/originals/svg/talk.svg", | |
Update: "http://game-icons.net/icons/delapouite/originals/svg/upgrade.svg", | |
Attachment: "http://game-icons.net/icons/delapouite/originals/svg/paper-clip.svg", | |
Reference: "http://game-icons.net/icons/lorc/originals/svg/psychic-waves.svg", | |
Uncertain: "http://game-icons.net/icons/lorc/originals/svg/surprised-skull.svg" | |
}; | |
}; | |
function TrelloBadge(data){ | |
this.data = data; | |
} | |
TrelloBadge.prototype.render = function(){ | |
return $('<div class="badge '+this.data.type+ ' ' + this.data.labels + | |
'" title="'+this.data.title.replace(/"/gm, "")+ | |
'">'+this.data.html+'</div>'); | |
}; | |
TrelloBadges.prototype.distinctActions = function(entries){ | |
return entries.reverse() | |
.filter((value, index, self) => !self.slice(0, index).find(a => a.data.card.name === value.data.card.name)) | |
.reverse(); | |
}; | |
TrelloBadges.prototype.agileBadge = function(user, list){ | |
if(!user.history) console.log("no history", user); | |
return this.distinctActions(user.history.filter(a => (a.data.listAfter||{}).name === list)); | |
} | |
TrelloBadges.prototype.createCardsBadge = function(settings){ | |
var cardNames = settings.entries.map(e => (e.date||e.dateLastActivity).replace(/[TZ]/mg, " ") + ": " + (e.name||e.data.card.name).replace(/"/gm, "")).join("\r\n"); | |
var bad = settings.score < 0; | |
return new TrelloBadge(Object.assign(settings, | |
{ | |
type: 'cards', | |
html: '<img src="'+settings.image+'" title="'+settings.title+"\r\n"+cardNames+ | |
'"/>' + (bad || settings.score > 1 ? '<span>'+ settings.score +'</span>':'') | |
})); | |
} | |
TrelloBadges.prototype.createProgressBadge = function(title, total, current, labels){ | |
var p = parseInt(100 / total * current); | |
return new TrelloBadge({ | |
type: 'progress', | |
labels: labels, | |
title: title, | |
score: current, | |
html: '<div class="c100 p'+p+' small">'+ | |
'<span>'+p+'%</span>'+ | |
'<div class="slice">'+ | |
'<div class="bar"></div>'+ | |
'<div class="fill"></div>'+ | |
'</div>'+ | |
'</div>' | |
}); | |
} | |
// Convection: ttttBadge_XXXX calculates a badge from a user, where tttt is the user's team | |
TrelloBadges.prototype.pigsBadge_Released = function(user, trelloBoard){ | |
var entries = this.agileBadge(user, trelloBoard.options.agile.release); | |
if(entries.length === 0) return; | |
return this.createCardsBadge({ | |
title: 'You released ' + entries.length + ' cards!', | |
entries: entries, | |
image: this.BadgesImages.Released, | |
labels: 'release', | |
score: entries.length | |
}); | |
} | |
TrelloBadges.prototype.pigsBadge_Tested = function(user, trelloBoard){ | |
var entries = this.agileBadge(user, trelloBoard.options.agile.test); | |
if(entries.length === 0) return; | |
return this.createCardsBadge({ | |
title: 'You tested ' + entries.length + ' cards!', | |
entries: entries, | |
image: this.BadgesImages.Tested, | |
labels: 'test', | |
score: entries.length | |
}); | |
} | |
TrelloBadges.prototype.pigsBadge_Developed = function(user, trelloBoard){ | |
var entries = this.agileBadge(user, trelloBoard.options.agile.done); | |
if(entries.length === 0) return; | |
return this.createCardsBadge({ | |
title: 'You developed ' + entries.length + ' cards!', | |
entries: entries, | |
image: this.BadgesImages.Done, | |
labels: 'done', | |
score: entries.length | |
}); | |
} | |
TrelloBadges.prototype.pigsBadge_BugKiller = function(user, trelloBoard){ | |
var entries = this.agileBadge(user, trelloBoard.options.agile.done) | |
.map(e => ({e: e, _card: trelloBoard.cards.filter(c => c.id === e.data.card.id)[0]})) | |
.filter(e => e._card && | |
e._card.labels.filter(l => l.set && l.name.toLowerCase() === "bug")) | |
.map(e => e.e); | |
if(entries.length === 0) return; | |
return this.createCardsBadge({ | |
title: 'You killed ' + entries.length + ' bugs!', | |
entries: entries, | |
image: this.BadgesImages.BugKiller, | |
labels: 'bug', | |
score: entries.length | |
}); | |
} | |
TrelloBadges.prototype.pigsBadge_Impediment = function(user, trelloBoard){ | |
var impedimentCardIds = trelloBoard.getCards(trelloBoard.options.agile.impediment) | |
.map(c => c.id); | |
var entries = this.agileBadge(user, trelloBoard.options.agile.impediment) | |
.filter(a => impedimentCardIds.indexOf(a.data.card.id) !== -1); | |
if(entries.length === 0) return; | |
return this.createCardsBadge({ | |
title: 'Hurry up! You have ' + entries.length + ' impediment!', | |
entries: entries, | |
image: this.BadgesImages.Impediment, | |
labels: 'impediment', | |
score: -1*entries.length | |
}); | |
} | |
/*TrelloBadges.prototype.pigsBadge_King = function(user, trelloBoard){ | |
var entries = this.agileBadge(user, trelloBoard.options.agile.release); | |
if(entries.length === 0) return; | |
return this.createCardsBadge({ | |
title: 'Congrats, you are the king now!', | |
entries: [], | |
image: this.BadgesImages.King, | |
labels: 'king', | |
score: 0 | |
}); | |
}*/ | |
TrelloBadges.prototype.chickensBadge_Creator = function(user, trelloBoard){ | |
var entries = this.distinctActions(user.history.filter(h => h.type.startsWith("create"))); | |
if(entries.length === 0) return; | |
return this.createCardsBadge({ | |
title: 'You created ' + entries.length + ' cards!', | |
entries: entries, | |
image: this.BadgesImages.Create, | |
labels: 'create', | |
score: entries.length | |
}); | |
} | |
TrelloBadges.prototype.chickensBadge_Comment = function(user, trelloBoard){ | |
var entries = this.distinctActions(user.history.filter(h => h.type.startsWith("comment"))); | |
if(entries.length === 0) return; | |
return this.createCardsBadge({ | |
title: 'You commented on ' + entries.length + ' cards!', | |
entries: entries, | |
image: this.BadgesImages.Comment, | |
labels: 'comment', | |
score: entries.length | |
}); | |
} | |
TrelloBadges.prototype.chickensBadge_Update = function(user, trelloBoard){ | |
var entries = this.distinctActions(user.history.filter(h => h.type.startsWith("update"))); | |
if(entries.length === 0) return; | |
return this.createCardsBadge({ | |
title: 'You edited ' + entries.length + ' cards!', | |
entries: entries, | |
image: this.BadgesImages.Update, | |
labels: 'update', | |
score: entries.length | |
}); | |
} | |
TrelloBadges.prototype.chickensBadge_Attachemnt = function(user, trelloBoard){ | |
var entries = this.distinctActions(user.history.filter(h => h.type.startsWith("addAttachment"))); | |
if(entries.length === 0) return; | |
return this.createCardsBadge({ | |
title: 'You added attachments to ' + entries.length + ' cards!', | |
entries: entries, | |
image: this.BadgesImages.Attachment, | |
labels: 'attachment', | |
score: entries.length | |
}); | |
} | |
TrelloBadges.prototype.chickensBadge_References = function(user, trelloBoard){ | |
var entries = this.distinctActions(user.history.filter(h => h.type.startsWith("memberReferenced"))); | |
if(entries.length === 0) return; | |
return this.createCardsBadge({ | |
title: 'You have been named in ' + entries.length + ' cards!', | |
entries: entries, | |
image: this.BadgesImages.Reference, | |
labels: 'reference', | |
score: entries.length | |
}); | |
} | |
TrelloBadges.prototype.chickensBadge_References = function(user, trelloBoard){ | |
var entries = trelloBoard.cards | |
.filter(c => c.idMemberCreator === user.id) | |
.map(c => ({ | |
c:c, | |
chars: c.desc.length + c.name.length, | |
comments: c.history.filter(h => h.type === "memberReferenced") | |
})) | |
.filter(metrics => metrics.chars < 50 || | |
metrics.comments > 10) | |
.map(a => a.c); | |
if(entries.length === 0) return; | |
return this.createCardsBadge({ | |
title: 'Don\'t know Rick, those ' + entries.length + ' cards look unclear!', | |
entries: entries, | |
image: this.BadgesImages.Uncertain, | |
labels: 'uncertain', | |
score: -1*entries.length | |
}); | |
} | |
TrelloBadges.prototype.calculateBoardBage = function(trelloBoard){ | |
var badges = []; | |
var agileCards = []; | |
var backLog = trelloBoard.getCards(trelloBoard.options.agile.backlog); | |
agileCards.push(backLog); | |
badges.push(this.createCardsBadge({ | |
title: backLog.length + ' cards waiting on your backlog!', | |
entries: backLog, | |
image: this.BadgesImages.Backlog, | |
score: backLog.length | |
})); | |
var entries = trelloBoard.getCards(trelloBoard.options.agile.ongoing); | |
agileCards.push(entries); | |
badges.push(this.createCardsBadge({ | |
title: 'Working on ' + entries.length + ' cards. Keep going!', | |
entries: entries, | |
image: this.BadgesImages.Done, | |
score: entries.length | |
})); | |
entries = trelloBoard.getCards(trelloBoard.options.agile.test); | |
agileCards.push(entries); | |
badges.push(this.createCardsBadge({ | |
title: 'Testing ' + entries.length + ' cards.', | |
entries: entries, | |
image: this.BadgesImages.Tested, | |
score: entries.length | |
})); | |
entries = trelloBoard.getCards(trelloBoard.options.agile.impediment); | |
agileCards.push(entries); | |
badges.push(this.createCardsBadge({ | |
title: 'Hurry up!!' + entries.length + ' impediments.', | |
entries: entries, | |
image: this.BadgesImages.Impediment, | |
score: entries.length | |
})); | |
var releasedCards = entries = trelloBoard.getCards(trelloBoard.options.agile.release); | |
agileCards.push(entries); | |
badges.push(this.createCardsBadge({ | |
title: entries.length + ' released. WOW, KEEP IT GOING!', | |
entries: entries, | |
image: this.BadgesImages.Released, | |
score: entries.length | |
})); | |
agileCards = agileCards.reduce((a,b) => a.concat(b)); | |
entries = agileCards.filter(c => c.labels.filter(l => l.set && l.name.toLowerCase() === "bug").length !== 0); | |
badges.push(this.createCardsBadge({ | |
title: entries.length + ' dammit bugs!!', | |
entries: entries, | |
image: this.BadgesImages.BugKiller, | |
score: entries.length | |
})); | |
badges.push(this.createProgressBadge('Sprint progress', | |
agileCards.length, | |
releasedCards.length, | |
'sprint')); | |
trelloBoard.badges = badges; | |
}; | |
TrelloBadges.prototype.calculateBadges = function(trelloBoard){ | |
trelloBoard.members.map(user => this.calculateBadge(user, trelloBoard)); | |
this.calculateBoardBage(trelloBoard); | |
return trelloBoard; | |
}; | |
TrelloBadges.prototype.calculateBadge = function(user, trelloBoard){ | |
var oThis = this; | |
user.badges = Object.keys(TrelloBadges.prototype) | |
.filter(k => k.startsWith(user.team + "Badge_")) | |
.map(k => (oThis[k]||console.log).call(oThis, user, trelloBoard, k)) | |
.filter(b => b != undefined); | |
}; | |
function TrelloGamification(options){ | |
this.options = options; | |
}; | |
TrelloGamification.prototype.randomBG = function(){ | |
var imgs = ["https://swarmscblog.files.wordpress.com/2017/10/db70e2875e7fabede0c8ef2b343d3b51-wallpaper-art-wallpaper-backgrounds.jpg", | |
"https://datagame.io/files/2016/07/survey-gamification-examples.png", | |
"http://fistfuloftalent.com/wp-content/uploads/2015/02/gamification-lead-generation-BG20131217141557.jpg", | |
"http://groupvisual.io/designinganalytics/wp-content/uploads/2015/09/Gamification-Post-Header-02-1024x406.png", | |
"http://qode.pro/blog/wp-content/uploads/2015/01/Gamificaci%C3%B3n.jpg", | |
"https://www.amazecraze.com/wp-content/uploads/2016/06/pc-gaming-wallpapers-background-1280x720.jpg", | |
"https://i.imgur.com/JF1f8dGr.jpg", | |
"https://i.imgur.com/2shdwke.jpg", | |
"http://hddesktopwallpapers.in/wp-content/uploads/2015/07/mario-wallpaper-elegant-1080x608.jpg"]; | |
return imgs[Math.floor(Math.random() * imgs.length)]; | |
}; | |
TrelloGamification.prototype.loading = function(){ | |
/** | |
* .overlay { | |
position: fixed; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background-color: #000; | |
filter:alpha(opacity=50); | |
-moz-opacity:0.5; | |
-khtml-opacity: 0.5; | |
opacity: 0.5; | |
z-index: 10000; | |
display: inline block; | |
} | |
.overlay img{ | |
display: block; | |
margin: 0 auto; | |
padding-top:100px; | |
} | |
<div class="overlay"> | |
<img id="my-photo-id" src="http://cdn.sstatic.net/stackexchange/img/logos/so/so-logo.png" alt="Photo" data-photo-overlay="true" /> | |
</div> | |
*/ | |
var img = this.randomBG(); | |
$('html') | |
.css("background-image", 'url("'+img+'")'); | |
$('body').css('opacity',0); | |
return this; | |
}; | |
TrelloGamification.prototype.loadingDone = function(){ | |
var bgimg = $('html').css("background-image"); | |
$('.body-board-view').get(0).style= "background-image: "+bgimg; | |
$('body').css('opacity',1); | |
return this; | |
}; | |
TrelloGamification.prototype.addStyle = function(){ | |
var style ='.trello-gamification .list-header {'+ | |
'margin: 10px 0px 0px 10px;'+ | |
'}'+ | |
'.trello-gamification .list-wrapper {'+ | |
'height: inherit;'+ | |
'float: left;'+ | |
'margin-bottom: 10px;'+ | |
'}'+ | |
'.gameboard {'+ | |
'height: 2000px;'+ | |
'width: 68%;'+ | |
'overflow: hidden;'+ | |
'float: left;'+ | |
'}'+ | |
'.js-list {'+ | |
'width: 250px;'+ | |
'float: left;'+ | |
'margin: 0px 7px 7px 0;'+ | |
'}'+ | |
'.chickens .list {'+ | |
'background-color: rgba(5, 90, 140, 0.79);'+ | |
'color: white;'+ | |
'}'+ | |
'.pigs .list {'+ | |
'background-color: rgba(182, 191, 182, 0.8);'+ | |
'}'+ | |
'.badge img {'+ | |
'width: 32px;'+ | |
'border-radius: 5px;'+ | |
'border: solid 1px #ccc;'+ | |
'}'+ | |
'.badge span {'+ | |
'position: absolute;'+ | |
'right: 0px;'+ | |
'bottom: 0;'+ | |
'color: #000000;'+ | |
'background-color: white;'+ | |
'border-radius: 3px;'+ | |
'font-size: 12px;'+ | |
'padding: 0px 1px 0 2px;'+ | |
'}'+ | |
'.trello-gamification .badge {'+ | |
'width: 34px;'+ | |
'height: 34px;'+ | |
'position: relative;'+ | |
'}'+ | |
'.trello-gamification-badges {'+ | |
'background: rgba(220, 220, 220, 0.4);'+ | |
'font-weight: bold;'+ | |
'color: black;'+ | |
'min-height: 40px;'+ | |
'}'+ | |
'.trello-gamification.board-canvas {'+ | |
'padding: 5px;'+ | |
'}'+ | |
'.game-goals img {'+ | |
'width: 72px;'+ | |
'position: absolute;'+ | |
'}'+ | |
'.trello-gamification .game-goals{'+ | |
'min-height: 82px;'+ | |
'background-color: rgba(118, 212, 255, 0.4);'+ | |
'margin: 0px 9px 8px 0;'+ | |
'padding: 10px;'+ | |
'border-radius: 3px;'+ | |
'}'+ | |
'.game-goals .badge {'+ | |
'width: 73px;'+ | |
'height: 73px;'+ | |
'}'+ | |
'.game-goals h2 {'+ | |
'float: left;'+ | |
'margin-right: 10px;'+ | |
'color: #ffff;'+ | |
'font-size: 2em;'+ | |
'}'+ | |
'.badge.progress {'+ | |
'background-color: white;'+ | |
'border-radius: 3px;'+ | |
'}'+ | |
'.progress .bar {'+ | |
'z-index: 3;'+ | |
'}'+ | |
'.progress span {'+ | |
'background-color: transparent;'+ | |
'}'+ | |
'.c100.small {'+ | |
'font-size: 70px;'+ | |
'margin: 3px;'+ | |
'}'+ | |
'.badge.release img{'+ | |
'filter: invert(0) sepia(1) saturate(100) hue-rotate(322deg);'+ | |
'}'+ | |
'.badge.test img{'+ | |
'filter: invert(0) sepia(1) saturate(100) hue-rotate(157deg);'+ | |
'}'+ | |
'.badge.done img{'+ | |
'filter: invert(0) sepia(1) saturate(100) hue-rotate(41deg);'+ | |
'}'+ | |
'.badge.bug img{'+ | |
'filter: invert(0) sepia(1) saturate(100) hue-rotate(408deg);'+ | |
'}'+ | |
'.badge.impediment img{'+ | |
'invert(0) sepia(10) saturate(100) hue-rotate(178deg);'+ | |
'}'+ | |
'.badge.uncertain img{'+ | |
'filter: invert(0) sepia(1) saturate(100) hue-rotate(322deg);'+ | |
'}'+ | |
'.member img {'+ | |
'width: 30px;'+ | |
'}'+ | |
'.badge.king{'+ | |
'display: none;'+ | |
'}'+ | |
'.master .badge.king{'+ | |
'display: inline;'+ | |
'}'+ | |
'.master .list {'+ | |
'background-color: rgba(176, 50, 165, 0.5);'+ | |
'color: white;'+ | |
'}'+ | |
'.looser .list {'+ | |
'background-color: rgba(0, 0, 0, 0.5);'+ | |
'color: white;'+ | |
'}'+ | |
'.trello-gamification .pigs .list-cards {'+ | |
'height: 78px;'+ | |
'overflow: hidden;'+ | |
'};'+ | |
'.open-card-composer::before {'+ | |
'content: "";'+ | |
'height: 5px;'+ | |
'position: absolute;'+ | |
'left: 0;'+ | |
'top: 0;'+ | |
'background: linear-gradient(#277b84 2px, #ffffff00);'+ | |
'width: 100%;'+ | |
'}'; | |
$('head') | |
.append('<link rel="stylesheet" href="https://www.cssscript.com/demo/pure-css-circular-percentage-bar/css/circle.css"/>') | |
.append('<style>'+style+'</style>'); | |
}; | |
TrelloGamification.prototype.addGoals = function(){ | |
this.board.badges.map(g => this.board_goals.append(g.render())); | |
} | |
TrelloGamification.prototype.cleanBoard = function(){ | |
this.loading(); | |
this.addStyle(); | |
this.board_canvas = $('.board-canvas').hide(); | |
this.trello_gamification_board_canvas = $('<div class="trello-gamification board-canvas"/>'); | |
this.trello_gamification_board_canvas.append( | |
this.trello_gamification_pigs = $('<div class="pigs gameboard"/>')); | |
this.trello_gamification_board_canvas.append( | |
this.trello_gamification_chickens = $('<div class="chickens"/>')); | |
this.board_canvas.parent().append(this.trello_gamification_board_canvas); | |
this.board_goals = $('<div class="game-goals"><h2>Sprint review</h2></div>'); | |
this.trello_gamification_pigs.append(this.board_goals); | |
return this; | |
}; | |
TrelloGamification.prototype.newList = function(data){ | |
var list = $('<div class="js-list '+data.labels.join(" ")+'" id="'+data.id+'"><div class="list js-list-content">'+ | |
'<div class="list-header js-list-header u-clearfix is-menu-shown">'+ | |
'<div class="list-header-target js-editing-target">'+ | |
'<div class="member js-member-on-card-menu">'+ | |
data.getProfilePic()+ | |
'</div>'+ | |
'<h2>'+data.fullName+'</h2>'+ | |
'</div>'+ | |
'</div>'+ | |
'<div class="list-cards u-fancy-scrollbar u-clearfix js-list-cards js-sortable ui-sortable">'+ | |
'</div><div class="open-card-composer trello-gamification-badges"></div></div></div>'); | |
return list; | |
} | |
TrelloGamification.prototype.newCard = function(data){ | |
var card = $('<a class="list-card js-member-droppable aging-level-0 aging-regular ui-droppable" '+ | |
'href="'+data.url+'" data-cardid="'+data.id+'" title="'+data.name.replace(/"/m, "")+ | |
'"><div class="list-card-details"><div class="list-card-labels js-card-labels">'+ | |
data.idLabels.map(l => data.labels.filter(label => label.id === l)[0]) | |
.map(l => '<span class="card-label card-label-'+l.color+ | |
' mod-card-front" title="'+l.name+'">'+l.name+'</span>') | |
.join("")+ | |
'</div>'+ | |
'<span class="list-card-title js-card-name" dir="auto">'+data.name+'</span></div></a>'); | |
return card; | |
}; | |
TrelloGamification.prototype.addUserCards = function(user){ | |
var cardList = user.list.find('.list-cards'); | |
user.cards.map(c => cardList.append(this.newCard(c))); | |
}; | |
TrelloGamification.prototype.addBadges = function(user, container){ | |
user.badges.map(b => container.append(b.render())); | |
}; | |
TrelloGamification.prototype.loadPlayers = function(){ | |
this.board.members | |
.do(m => m.cards = this.board.agile.getWorkingCards(m)) | |
.map(m => m.team) | |
.filter((value, index, self) => self.indexOf(value) === index) // Distinct! | |
.do(team => | |
this.board.members | |
.filter(m => m.team === team && | |
(m.team == "pigs" || m.badges.length)) | |
.do(user => user.score = user.badges.length ? | |
Math.max(user.badges.length, user.badges.map(b => b.data.score||1).reduce((a,b) => a+b)): | |
user.cards.length) | |
.sort((a,b) => a.score >= b.score ? -1: 1) | |
.do(user => user.labels = (user.labels||[])) | |
.do((user, index) => { | |
if(index === 0 && user.score !== 0) user.labels.push("master"); | |
if(user.team == "pigs" && user.badges.length === 0) user.labels.push("looser"); | |
user.labels.push(user.team); | |
}) | |
.do(user => user.list = this.newList(user)) | |
.do(user => user.team === "pigs" && this.addUserCards(user)) | |
.do(user => (user.team === "pigs" ? | |
this.trello_gamification_pigs: | |
this.trello_gamification_chickens).append(user.list)) | |
.do(user => this.addBadges(user, user.list.find('.trello-gamification-badges'))) | |
) | |
return this; | |
}; | |
TrelloGamification.prototype.init = function(){ | |
var _init = () => this.init.call(this); | |
this.options.token = window.location.href.split("/")[4]; | |
this.board = new TrelloBoard(this.options) | |
.load() | |
.then(b => this.board = new TrelloBadges().calculateBadges(b)) | |
.then(() => this.cleanBoard()) | |
.then(b => this.loadPlayers()) | |
.then(() => this.addGoals()) | |
.then(b => this.loadingDone()) | |
.then(() => window.setTimeout(() => _init(), 10*60*1000)); | |
return this; | |
}; | |
var tg = new TrelloGamification({ | |
idOrganization:'5a9a57e3707b7edef82549c6' | |
}); | |
tg.init(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment