Skip to content

Instantly share code, notes, and snippets.

@SomniusTiger
Created July 8, 2018 00:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SomniusTiger/7a6549f3f60a5f6bddf443ac956b3c6a to your computer and use it in GitHub Desktop.
Save SomniusTiger/7a6549f3f60a5f6bddf443ac956b3c6a to your computer and use it in GitHub Desktop.
Met Gala Bracket JavaScript
/*!
* Met Gala
* @author: Eoin Thomas O'Hehir [tom.ohehir@teamaol.com]
* @description: Met Gala page functionality
*/
'use strict';
/**
* Module prototype.
*/
var metGala = exports = module.exports = function(app, sandbox, config) {
return {
config: {
'people': [],
'roundsArray': [],
'rounds': 0,
'matches': 0,
'currRound': 1,
'currMatch': 1, // The current match number out of the total matches available
'displayMatch': 1, // Based on what round it is – changes back to 1 every new round
'matchupString': '',
'matchupDetails': {} // Shows round number, the people in left/right positions and the person chosen
},
init: function init(config) {
var self = this;
if (window.location.href.indexOf("aol.com/lifestyle/met-gala/bracket/") != -1) {
// If on met gala bracket display page
self.getPeople();
} else if (window.location.href.indexOf("aol.com/lifestyle/met-gala/") != -1) {
// If on met gala bracket select page
self.getPeople();
self.updateProgress(0);
}
},
getViewportSize: function getViewportSize() {
var size = {
'height': window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight,
'width' : window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
}
return size;
},
getPeople: function getPeople() {
var self = this,
initialBracket = {};
initialBracket = document.getElementsByClassName('met-gala-person');
// Loop through people and pull out index, title and image
for (var i = 0; i < initialBracket.length; i++) {
var index = initialBracket[i].getAttribute('data-index'),
title = initialBracket[i].getAttribute('data-title'),
image = initialBracket[i].getAttribute('data-image'),
designer = initialBracket[i].getAttribute('data-designer'),
attributes = { 'title': title, 'image': image, 'designer': designer, 'available': true };
self.config.people.push({
'index': index,
'attributes': attributes
});
}
self.calcMatchesPerRound(self.config.people);
},
calcMatchesPerRound: function calcMatchesPerRound(participants) {
var self = this,
count = 1;
self.config.matches = participants.length - 1;
for (var i = (participants.length / 2); i > 1; i = (i / 2) ) {
self.config.roundsArray.push( {'count': count, 'matches': i} );
count++;
}
self.config.roundsArray.push( {'count': count, 'matches': 1} );
self.config.rounds = self.config.roundsArray.length;
if (window.location.href.indexOf("aol.com/lifestyle/met-gala/bracket/") != -1) {
// If on met gala bracket display page
self.calcMatchupDetails();
} else if (window.location.href.indexOf("aol.com/lifestyle/met-gala/") != -1) {
// If on met gala bracket select page
self.generateMatchupsString(self.config.matches);
self.generateSlider();
}
},
generateMatchupsString: function generateMatchupsString(matches) {
var self = this;
// Generates initial matchup string based on how many matches there are
for (var i = matches; i > 0; i--) {
self.config.matchupString += '0';
}
},
generateSlider: function generateSlider() {
var self = this;
$('.met-gala-bracket-slider').slick({
arrows: false,
cssEase: 'cubic-bezier(0.230, 1.000, 0.320, 1.000)',
draggable: false,
ease: 'cubic-bezier(0.230, 1.000, 0.320, 1.000)',
fade: true,
infinite: false,
slidesToScroll: 1,
slidesToShow: 1
});
self.selectPeople();
},
selectPeople: function selectPeople() {
var self = this;
self.bracketClickListener();
$('.met-gala-bracket-slider').on('beforeChange', function(event, slick, currentSlide, nextSlide) {
$('.met-gala-bracket-slider').off('click');
self.updateProgress(nextSlide);
self.currentLocation(nextSlide);
});
$('.met-gala-bracket-slider').on('afterChange', function(event, slick, currentSlide) {
// Wait to reassign click listener until after slide transition
self.bracketClickListener();
});
},
bracketClickListener: function bracketClickListener() {
var self = this;
// Apply selected style to selected choice, remove availability from unselected choice, save selected choice to matchup string and localStorage, navigate to next slide
$('.met-gala-bracket-slider').on('click', function(e) {
var target = $(e.target).parent().parent('.met-gala-bracket-slider-slide-choice');
if ( target.is(':first-child') && $(e.target).hasClass('met-gala-bracket-slider-slide-choice-target') ) {
if ( !target.parent().hasClass('choice-left-selected') && !target.parent().hasClass('choice-right-selected') ) {
target.parent().addClass('choice-left-selected');
var peopleIndex = target.next('.met-gala-bracket-slider-slide-choice').data('index');
self.config.people[peopleIndex - 1]['attributes']['available'] = false;
self.saveChoices();
$('.met-gala-bracket-slider').slick('slickNext');
}
} else if ( $(e.target).hasClass('met-gala-bracket-slider-slide-choice-target') ) {
if ( !target.parent().hasClass('choice-left-selected') && !target.parent().hasClass('choice-right-selected') ) {
target.parent().addClass('choice-right-selected');
var peopleIndex = target.prev('.met-gala-bracket-slider-slide-choice').data('index');
self.config.people[peopleIndex - 1]['attributes']['available'] = false;
self.saveChoices();
$('.met-gala-bracket-slider').slick('slickNext');
}
}
});
},
updateProgress: function updateProgress(upcomingSlide) {
var self = this;
// Update width of progress bar depending on how far along the user is in the matchups
var currentPosition = upcomingSlide + 1;
var totalMatchups = self.config.matches;
$('.met-gala-header-progress-bar').css({ width: ( (currentPosition / totalMatchups) * 100) + '%' });
},
currentLocation: function currentLocation(upcomingSlide) {
var self = this;
// Before navigating every slide, calculate the the upcoming round number and upcoming match number the user is located on, then update the numbers in header to reflect that.
var currentMatch = upcomingSlide + 1;
self.config.currMatch = upcomingSlide + 1;
self.config.displayMatch++;
if (self.config.displayMatch < 10) {
self.config.displayMatch = '0' + self.config.displayMatch;
}
// Update current match number
$('.matchup-current').text(self.config.displayMatch);
},
saveChoices: function saveChoices() {
var self = this;
// Loop through slides, see which slides are selected and edit matchup string based on that. Then, save string to localStorage.
// 0 means unselected, 1 means the left choice is selected, 2 means the right choice is selected.
// This returns a value of "newRound" if the newRound function is triggered.
var slides = document.querySelectorAll('.met-gala-bracket-slider-slide');
var slidesNum = slides.length;
for (var i = 0; i < slidesNum; i++ ) {
if ( $(slides[i]).hasClass('choice-left-selected') ) {
self.config.matchupString = self.config.matchupString.substr(0, i) + '1' + self.config.matchupString.substr(i + 1);
} else if ( $(slides[i]).hasClass('choice-right-selected') ) {
self.config.matchupString = self.config.matchupString.substr(0, i) + '2' + self.config.matchupString.substr(i + 1);
}
}
localStorage.setItem( 'aol-met-gala-matchups', self.config.matchupString );
localStorage.getItem( 'aol-met-gala-matchups' );
self.newRound(self.config.matchupString);
},
newRound: function newRound(matchupString) {
var self = this;
// If user has made selections for every single item up to the current round, advance to next round with new selections
var currRound = self.config.currRound;
var currentMaxMatches = 0;
// Find the maximum number of matches possible, given current round
for (var i = 0; i < currRound; i++) {
var totalMatchesInRound = self.config.roundsArray[i]['matches'];
currentMaxMatches = currentMaxMatches + totalMatchesInRound;
}
// Perform indexOf on matchupString to find first instance of 0, to see if user has entered a response for all possible matchups so far
var firstZero = matchupString.indexOf('0');
// If user has entered all possible responses so far, increment round number, display correct match number and match total, then add choices still available as new slides in slider
if (firstZero == currentMaxMatches) {
self.config.currRound++;
$('.round-number').text(self.config.currRound);
var newMatchTotal = self.config.roundsArray[self.config.currRound - 1]['matches'];
if (newMatchTotal < 10) {
newMatchTotal = '0' + newMatchTotal;
}
// Subtract previous round's match total from displayMatch to show proper display match number
self.config.displayMatch = self.config.displayMatch - self.config.roundsArray[self.config.currRound - 2]['matches'];
$('.matchup-total').text(newMatchTotal);
self.addNewRoundChoices();
} else if (currentMaxMatches == self.config.matches && firstZero == -1) {
// If all possible responses are given for all matchups, navigate to bracket display page
var matchupString = localStorage.getItem( 'aol-met-gala-matchups' );
// If on met gala page, send user to bracket display page
if (window.location.href.indexOf("aol.com/lifestyle/met-gala") != -1) {
window.location.href = './bracket/' + matchupString;
}
}
},
addNewRoundChoices: function addNewRoundChoices() {
var self = this,
availablePeople = [],
slidesString = '';
// Only run if user has future rounds to advance to
if (self.config.currRound <= self.config.rounds) {
// Get remaining available choices
for (var i = 0; i < self.config.people.length; i++) {
if (self.config.people[i]['attributes']['available'] === true) {
availablePeople.push( self.config.people[i] );
}
}
// Loop through remaining available choices and add those slides to slider
for (var i = 0; i < availablePeople.length; i++) {
if (i % 2 == 0) { // If index is even, add opening slide div tag
slidesString += '<div class="met-gala-bracket-slider-slide">';
}
slidesString += '<div class="met-gala-bracket-slider-slide-choice" data-index="' + availablePeople[i]['index'] + '">' +
'<div class="content">' +
'<div class="met-gala-bracket-slider-slide-choice-target"></div>' +
'<h3 class="met-gala-bracket-slider-slide-choice-title">' + availablePeople[i]['attributes']['title'] + '<br><span class="designer">'+ availablePeople[i]['attributes']['designer'] +'</span></h3>' +
'<div class="met-gala-bracket-slider-slide-choice-image" style="background-image: url(' + availablePeople[i]['attributes']['image'] + ');"></div>' +
'</div>' +
'</div>';
if (i % 2 != 0) { // If index is odd, add vs circle and closing slide div tag
slidesString += '<div class="met-gala-bracket-slider-slide-vs">' +
'<div class="met-gala-bracket-slider-slide-vs-text">' +
'<span class="vs">VS</span>' +
'<span class="navicon navicon-heart"></span>' +
'</div>' +
'</div>'+
'</div>';
}
}
$('.met-gala-bracket-slider').slick('slickAdd', slidesString);
$('.met-gala-bracket-slider').slick('slickNext');
}
},
calcMatchupDetails: function calcMatchupDetails() {
var self = this;
// Calculates matchup details - round, people in matchup, person chosen in matchup - based on matchupString
var tempPeople = self.config.people;
var matchupSelections = $('.met-gala-people').data('selected').toString();
var userMatchups = {};
var matchupOffset = 0;
var matchupCount = 0;
var errorMessage = '<h3 class="met-gala-final-bracket-header-text-title">Something went wrong. Please go back and try again.</h3>'
if ( matchupSelections.length != self.config.matches || matchupSelections.search(/([\D]|[3-9]|[0])+/i) != -1 ) {
$('.met-gala-final-bracket-display').html(errorMessage);
return false;
}
// Round Loop
for (var i = 0; i < self.config.rounds; i++) {
// Match Loop
for (var j = 0; j < self.config.roundsArray[i]['matches']; j++) {
var leftOrRight = matchupSelections.charAt(matchupCount);
var leftPerson = tempPeople[matchupOffset];
var rightPerson = tempPeople[matchupOffset + 1];
var chosenPerson;
if (leftOrRight == 1) {
// Left is chosen
chosenPerson = leftPerson;
// Right is removed
tempPeople.splice(matchupOffset + 1, 1);
} else if (leftOrRight == 2) {
// Right is chosen
chosenPerson = rightPerson;
// Left is removed
tempPeople.splice(matchupOffset, 1);
}
userMatchups[ (matchupCount) ] = {};
userMatchups[ (matchupCount) ]['round'] = i+1;
userMatchups[ (matchupCount) ]['match'] = j+1;
userMatchups[ (matchupCount) ]['left'] = leftPerson;
userMatchups[ (matchupCount) ]['right'] = rightPerson;
userMatchups[ (matchupCount) ]['chosen'] = chosenPerson;
matchupOffset++;
matchupCount++;
}
matchupOffset = 0;
}
self.config.matchupDetails = userMatchups;
self.writeBracket();
},
writeBracket: function writeBracket() {
var self = this,
htmlString = '',
roundCount = self.config.rounds + 1,
matchupDetails = self.config.matchupDetails;
for (var i = (self.config.matches - 1); i >= 0; i--) {
var currRound = matchupDetails[i]['round'];
if (currRound < roundCount) {
if (roundCount != self.config.rounds + 1) {
htmlString += '</div>';
}
if (currRound == self.config.rounds) {
htmlString += '<div class="round round'+ (currRound) +' round-final">';
htmlString += '<h3 class="round-title">Your Top Pick</h3>';
} else {
htmlString += '<div class="round round'+ (currRound) +'">';
htmlString += '<h3 class="round-title">Round '+ currRound +'</h3>';
}
roundCount = currRound;
}
htmlString += '<div class="match">' +
'<div class="vs"><span class="vs-text">VS</span></div>';
if (matchupDetails[i]['left'] == matchupDetails[i]['chosen']) {
htmlString += '<div class="left chosen">';
} else {
htmlString += '<div class="left">';
}
htmlString += '<img class="image" src="'+ matchupDetails[i]['left']['attributes']['image'] +'" alt=""/>' +
'<div class="title">'+ matchupDetails[i]['left']['attributes']['title'] +'</div>' +
'</div>' ;
if (matchupDetails[i]['right'] == matchupDetails[i]['chosen']) {
htmlString += '<div class="right chosen">';
} else {
htmlString += '<div class="right">';
}
htmlString += '<img class="image" src="'+ matchupDetails[i]['right']['attributes']['image'] +'" alt=""/>' +
'<div class="title">'+ matchupDetails[i]['right']['attributes']['title'] +'</div>' +
'</div>' +
'</div>';
if (i == 0) {
htmlString += '</div>';
}
}
$('.met-gala-final-bracket-display').html(htmlString);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment