Vue.config.debug = true; new Vue( { el: "#app", data: { colours: [ { foreground: "#ff0000", background: "#ffffff", character: "R" }, { foreground: "#0000ff", background: "#ffffff", character: "B" }, { foreground: "#00ff00", background: "#ffffff", character: "G" }, { foreground: "#ffff00", background: "#ffffff", character: "Y" }, { foreground: "#7700ff", background: "#ffffff", character: "Pu" }, { foreground: "#ff00ff", background: "#ffffff", character: "Pi" }, { foreground: "#00ffff", background: "#ffffff", character: "C" }, { foreground: "#ff7f00", background: "#ffffff", character: "O" }, ], zoneGrid: "", teams: [], gamesHaveTeams: true, roundTitle: "", roundNotes: "", brackets: [], tab: 'settings', settingsTab: 'grid', printAlertVisible: true, chunkSize: 30, }, computed: { grid() { var result = { byGame: {}, byTeam: {}, }; var games = this.zoneGrid .replace( /^[\s;]*/, '' ) // Remove leading semicolons and space .replace( /[\s;]*$/, '' ) // Remove trailing semicolons and space .split( ';' ); // Break apart by semi-colons for( var gameIndex in games ) { var game = games[ gameIndex ]; var preTeams = game.trim().split( /\s+/ ); var teams = {}; for( var preTeamIndex in preTeams ) { teams[ preTeamIndex ] = preTeams[ preTeamIndex ] - 1; } result.byGame[ gameIndex ] = teams; for( var teamIndex in teams ) { var team = teams[ teamIndex ]; if( !( team in result.byTeam ) ) { result.byTeam[ team ] = {}; } result.byTeam[ team ][ gameIndex ] = teamIndex; } } return result; }, usedTeamIndexes() { var result = []; var grid = this.grid; for( var gameIndex in grid.byGame ) { for( var teamIndex in grid.byGame[ gameIndex ] ) { if( grid.byGame[ gameIndex ][ teamIndex ] >= 0 && !( teamIndex in result ) ) { result.push( teamIndex ); } } } return result; }, chunkedGames() { var grid = this.grid; var byGame = grid.byGame; var keys = Object.keys( byGame ); var result = []; var games = this.games; var chunk = {}; var i = 0; for( var key in keys ) { if( key in games ) { chunk[ key ] = games[ key ]; i+= 1; if( i >= this.chunkSize ) { result.push( chunk ); chunk = {}; i = 0; } } } result.push( chunk ); return result; }, bracketedGames() { var games = this.games; var result = {}; for( var gameIndex in games ) { var game = games[ gameIndex ]; if( !( game.bracket in result ) ) { result[ game.bracket ] = {}; } result[ game.bracket ][ gameIndex ] = game; } return result; }, gridGameCount() { return Object.keys( this.grid.byGame ).length; }, games() { var games = []; var sortedBrackets = this.brackets.sort( function( a, b ) { var aStart = new Date( a.start ); var bStart = new Date( b.start ); return aStart.getTime() - bStart.getTime(); } ); for( var bracketIndex in sortedBrackets ) { var bracket = sortedBrackets[ bracketIndex ]; var stamps = this.getGameTimestampsInBracket( bracket ); for( var stampIndex in stamps ) { games.push( { bracket: bracketIndex, date: new Date( stamps[ stampIndex ] ) } ); // Sanity Limit if( games.length > 1000 ) { return games; } } } return games; } }, mounted() { this.resetColours(); this.populateSampleData(); this.checkCookies(); }, methods: { getPresetZoneGrids() { return { "Team": { 3: "1 2 3;", 4: "1 2 4; 2 3 1; 3 4 2; 4 1 3;", 5: "1 2 4; 2 3 5; 3 4 1; 4 5 2; 5 1 3; 2 4 3; 4 1 5; 1 3 2; 3 5 4; 5 2 1;", 6: "1 2 4; 2 3 5; 3 4 6; 4 5 1; 5 6 2; 6 1 3; 2 3 4; 4 5 6; 6 1 2; 1 3 5;", 7: "1 2 4; 2 3 5; 3 4 6; 4 5 7; 5 6 1; 6 7 2; 7 1 3;", 8: "1 2 3; 4 5 6; 7 8 1; 2 3 4; 5 6 7; 8 1 2; 3 4 5; 6 7 8; \n" + // Block 1 "2 1 4; 3 6 5; 8 7 2; 1 4 3; 6 5 8; 7 2 1; 4 3 6; 5 8 7; \n" + // Block 2 "1 8 3; 2 5 4; 7 6 1; 8 3 2; 5 4 7; 6 1 8; 3 2 5; 4 7 6; \n" + // Block 3 "2 1 5; 6 7 3; 1 4 8; 5 6 2; 8 3 7; 4 1 5; 7 2 6; 3 8 4; \n" + // Block 4 "6 1 5; 2 7 3; 5 8 4; 1 6 2; 4 3 7; 8 5 1; 3 2 6; 7 4 8; \n" + // Block 5 "5 1 3; 6 2 4; 7 3 5; 8 4 6; 1 5 7; 2 6 8; 3 7 1; 4 8 2; \n" + // Block 6 "6 1 3; 7 2 4; 8 3 5; 1 4 6; 2 5 7; 3 6 8; 4 7 1; 5 8 2; \n", // Block 7 } } }, usePresetZoneGrid( key, subKey ) { var grids = this.getPresetZoneGrids(); this.zoneGrid = grids[ key ][ subKey ]; }, getPresetColours() { return [ { foreground: "#ffcccc", background: "#ff3333", character: "R" }, { foreground: "#ccccff", background: "#3030ff", character: "B" }, { foreground: "#ccffcc", background: "#00c000", character: "G" }, { foreground: "#6f6f00", background: "#efef00", character: "Y" }, { foreground: "#efcfff", background: "#af00ff", character: "Pu" }, { foreground: "#ffcfff", background: "#ff66ff", character: "Pi" }, { foreground: "#009999", background: "#00ffff", character: "C" }, { foreground: "#663300", background: "#ffaf00", character: "O" }, ]; }, resetColours() { this.resetForegroundColours(); this.resetBackgroundColours(); this.resetColourCharacters(); }, resetForegroundColours() { var presetColours = this.getPresetColours(); for( var index in this.colours ) { this.colours[ index ].foreground = presetColours[ index ].foreground; } }, resetBackgroundColours() { var presetColours = this.getPresetColours(); for( var index in this.colours ) { this.colours[ index ].background = presetColours[ index ].background; } }, resetColourCharacters() { var presetColours = this.getPresetColours(); for( var index in this.colours ) { this.colours[ index ].character = presetColours[ index ].character; } }, removeTeamAt( index ) { this.teams.splice( index, 1 ); }, insertTeamAt( index ) { this.teams.splice( index, 0, { name: "" } ); this.$nextTick( function() { document.getElementById( 'team-name-' + index ).focus(); } ); }, addTeamOnEnter( e ) { if( e.keyCode == 13 ) { this.insertTeamAt( this.teams.length ); } }, removeBracketAt( index ) { this.brackets.splice( index, 1 ); }, insertBracketAt( index ) { var length = 15; var start = new Date(); var finish = new Date(); finish.setTime( finish.getTime() + (length * 60 * 1000 ) ); var startString = this.convertDateToString( start ); var finishString = this.convertDateToString( finish ); this.brackets.splice( index, 0, { name: "", start: startString, finish: finishString, length: length, } ); }, convertDateToString( date ) { var result = date.getFullYear() + "-" + ( date.getMonth() + 1 ) + "-" + date.getDate() + "T" + date.getHours() + ":" + date.getMinutes(); return result; }, // Bracket dates are created from unzoned strings and are treated as UTC. // Take the date/time parts and put them in a zoned Date object. convertDateStringToZonedDate( dateString ) { var date = new Date( dateString ); var newDate = new Date( date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds() ); return newDate; }, getGameTimestampsInBracket( bracket ) { try { var current = this.convertDateStringToZonedDate( bracket.start ); var length = 15 * 60 * 1000; if( bracket.length && bracket.length > 0 ) { length = parseInt( bracket.length ) * 60 * 1000; } var finish = this.convertDateStringToZonedDate( bracket.finish ); finish = finish.getTime(); var result = []; while( current.getTime() + length <= finish ) { result.push( current.getTime() ); current.setTime( current.getTime() + length ); } return result; } catch( e ) { return []; } }, getGameCountInBracket( bracket ) { try { var start = new Date( bracket.start ).getTime(); var finish = new Date( bracket.finish ).getTime(); var length = 15 * 60 * 1000; if( bracket.length && bracket.length > 0 ) { length = parseInt( bracket.length ) * 60 * 1000; } if( finish < start ) { return 0; } var result = Math.floor( ( finish - start ) / length ); if( isNaN( result ) ) { result = 0; } return result; } catch( e ) { return 0; } }, getChunkBrackets( chunk ) { var result = {}; for( var gameIndex in chunk ) { var game = chunk[ gameIndex ]; if( typeof( game ) === 'undefined' ) { continue; } if( !( game.bracket in result ) ) { var continued = false; if( gameIndex > 0 && this.games[ gameIndex - 1 ].bracket == game.bracket ) { continued = true; } result[ game.bracket ] = { 'width': 0, 'name': this.brackets[ game.bracket ].name, 'continued': continued }; } result[ game.bracket ].width += 1; } return result; }, getTeamGameBrackets( teamIndex ) { if( !( teamIndex in this.grid.byTeam ) ) { return {}; } var brackets = {}; var games = this.grid.byTeam[ teamIndex ]; for( var gameIndex in games ) { var game = this.games[ gameIndex ]; if( typeof( game ) === 'undefined' ) { continue; } if( !( game.bracket in brackets ) ) { brackets[ game.bracket ] = { name: this.brackets[ game.bracket ].name, games: [], }; } brackets[ game.bracket ].games.push( gameIndex ); } return brackets; }, getGameCountInAllBrackets() { var total = 0; for( var bracketIndex in this.brackets ) { total += this.getGameCountInBracket( this.brackets[ bracketIndex ] ); } return total; }, isBoundaryGame( gameIndex, previousGameIndex ) { if( gameIndex == 0 ) { return true; } if( !( gameIndex in this.games ) ) { return true; } if( typeof( previousGameIndex ) === 'undefined' ) { previousGameIndex = gameIndex - 1; } return this.games[ gameIndex ].bracket != this.games[ previousGameIndex ].bracket || this.isGameOnNewDay( gameIndex, previousGameIndex ); }, isGameOnNewDay( gameIndex, previousGameIndex ) { if( gameIndex == 0 ) { return true; } if( !( gameIndex in this.games ) ) { return true; } if( typeof( previousGameIndex ) === 'undefined' ) { previousGameIndex = gameIndex - 1; } return this.games[ gameIndex ].date.toLocaleDateString() != this.games[ previousGameIndex ].date.toLocaleDateString(); }, getTeamForegroundColour( colourIndex, gameIndex, teamIndex ) { if( !this.gamesHaveTeams && colourIndex ) { return "#efefef"; } if( !this.gamesHaveTeams ) { return 'inherit'; } if( !( colourIndex in this.colours ) ) { return 'inherit'; } return this.colours[ colourIndex ].foreground; }, getTeamBackgroundColour( colourIndex, gameIndex, teamIndex ) { if( !this.gamesHaveTeams && colourIndex ) { return "#3f3f3f"; } if( !this.gamesHaveTeams || !( colourIndex in this.colours ) ) { if( teamIndex % 2 == 0 && gameIndex % 2 == 0 ) { return "#f7f7f7"; } else if( teamIndex % 2 == 0 && gameIndex % 2 == 1 ) { return "#ffffff"; } else if( teamIndex % 2 == 1 && gameIndex % 2 == 0 ) { return "#f0f0f0"; } else if( teamIndex % 2 == 1 && gameIndex % 2 == 1 ) { return "#f7f7f7"; } if( teamIndex % 2 == 1 ) { if( gameIndex % 2 == 0 ) { return "#ffffff"; } else { return "#dfdfdf"; } } else { return "#efefef"; } } return this.colours[ colourIndex ].background; }, getTeamColourCharacter( colourIndex, gameIndex, teamIndex, withCheck ) { if( !this.gamesHaveTeams && colourIndex ) { if( withCheck ) { return ""; } else { return ""; } } if( !( colourIndex in this.colours ) ) { return ""; } return this.colours[ colourIndex ].character; }, getOffsetColourCharacter( teamIndex ) { if( !this.gamesHaveTeams ) { return "#" + (parseInt(teamIndex) + 1); } if( !teamIndex in this.colours ) { return "#" + (parseInt(teamIndex) + 1); } return this.colours[ teamIndex ].character; }, getOffsetColourForeground( teamIndex ) { if( !this.gamesHaveTeams ) { return "#ffffff"; } if( !teamIndex in this.colours ) { return ""; } return this.colours[ teamIndex ].foreground; }, getOffsetColourBackground( teamIndex ) { if( !this.gamesHaveTeams ) { return "#3f3f3f"; } if( !teamIndex in this.colours ) { return ""; } return this.colours[ teamIndex ].background; }, populateSampleData() { this.zoneGrid = "1 2 3; 4 5 6; 5 3 1; 6 4 2; 0 0 0 2 4 5;"; this.roundTitle = "Round Robin"; this.roundNotes = "This is a round robin draw."; this.teams = [ { name: "Team 1" }, { name: "Team 2" }, { name: "Team 3" }, { name: "Team 4" }, { name: "Team 5" }, { name: "Team 6" }, { name: "Team 7" }, { name: "Team 8" }, ]; this.brackets = [ { name: "Morning Games", start: "2016-11-19T10:00", finish: "2016-11-19T10:30", length: 15, }, { name: "Afternoon Games", start: "2016-11-19T13:30", finish: "2016-11-19T14:15", length: 15, } ] }, resetData() { this.colours = [ { foreground: "#ff0000", background: "#ffffff", character: "R" }, { foreground: "#0000ff", background: "#ffffff", character: "B" }, { foreground: "#00ff00", background: "#ffffff", character: "G" }, { foreground: "#ffff00", background: "#ffffff", character: "Y" }, { foreground: "#7700ff", background: "#ffffff", character: "Pu" }, { foreground: "#ff00ff", background: "#ffffff", character: "Pi" }, { foreground: "#00ffff", background: "#ffffff", character: "C" }, { foreground: "#ff7f00", background: "#ffffff", character: "O" }, ]; this.zoneGrid = ""; this.teams = []; this.gamesHaveTeams = true; this.roundTitle = ""; this.roundNotes = ""; this.brackets = []; this.tab = 'settings'; this.settingsTab = 'grid'; this.printAlertVisible = true; this.chunkSize = 30; }, applyData( newData ) { if( 'colours' in newData ) { this.colours = newData.colours; } if( 'zoneGrid' in newData ) { this.zoneGrid = newData.zoneGrid; } if( 'teams' in newData ) { this.teams = newData.teams; } if( 'gamesHaveTeams' in newData ) { this.gamesHaveTeams = newData.gamesHaveTeams; } if( 'roundTitle' in newData ) { this.roundTitle = newData.roundTitle; } if( 'roundNotes' in newData ) { this.roundNotes = newData.roundNotes; } if( 'brackets' in newData ) { this.brackets = newData.brackets; } }, gatherData() { var result = {}; result.colours = this.colours; result.zoneGrid = this.zoneGrid; result.teams = this.teams; result.gamesHaveTeams = this.gamesHaveTeams; result.roundTitle = this.roundTitle; result.roundNotes = this.roundNotes; result.brackets = this.brackets; return result; }, reset() { if( confirm( "Do you want to save before you continue? Press OK to save, or cancel to continue without saving." ) ) { this.save(); } this.resetData(); }, open( targetFileInputId ) { if( confirm( "Do you want to save before you continue? Press OK to save, or cancel to continue without saving." ) ) { this.save(); } var fileInput = document.getElementById( targetFileInputId ); fileInput.focus(); fileInput.click(); }, save() { output = JSON.stringify( this.gatherData() ); var url = "data:application/json;charset=utf-8," + encodeURIComponent( output ); var e = document.createElement( "a" ); e.setAttribute( "href", url ); e.setAttribute( "download", this.roundTitle + ".json" ); e.style.display = "none"; document.body.appendChild( e ); e.click(); document.body.removeChild( e ); }, onFileOpened( e ) { var fileInput = e.target; console.log( fileInput.files.length ); if( fileInput.files.length == 0 ) { return; } var file = fileInput.files[ 0 ]; //console.log( file.type ); //if( !( [ 'text/plain', 'text/json', 'application/json' ].includes( file.type ) ) ) { // return; //} var fileReader = new FileReader(); fileReader.onload = this.onFileOpenLoaded; console.log( "Loading file", file ); fileReader.readAsText( file ); }, onFileOpenLoaded( e ) { var result = e.target.result; console.log( "Retrieved", result ); try { var newData = JSON.parse( result ); this.resetData(); this.applyData( newData ); } catch( e ) { alert( "The file you chose could not be read." ); } }, checkCookies() { if( Cookies.get( "gridgen-print-ack" ) ) { this.printAlertVisible = false; } }, hidePrintAlert() { this.printAlertVisible = false; Cookies.set( "gridgen-print-ack", true, { expires: 1 } ); }, pad( input, length, character ) { input = input.toString(); if( input.length >= length ) { return input; } if( typeof( character ) === "undefined" ) { character = "0"; } return new Array( length - input.length + 1 ).join( character ) + input; } } } );