Skip to content

Instantly share code, notes, and snippets.

@victorstanciu
Created January 22, 2013 08:52
Show Gist options
  • Save victorstanciu/4593140 to your computer and use it in GitHub Desktop.
Save victorstanciu/4593140 to your computer and use it in GitHub Desktop.
define(function () {
var Bracket = function (element, manager) {
this.element = element;
this.manager = manager;
this.id = parseInt(element.getAttribute('data-id')); // don't rely on this to be unique until a sync() is made
this.round = parseInt(element.getAttribute('data-round'));
this.rounds = parseInt(element.getAttribute('data-rounds'));
this.order = parseInt(element.getAttribute('data-order'));
this.dom = {
archers: this.element.select('select'),
scores: this.element.select('[data-role="score"]'),
winner: this.element.down('[data-role="winner"]')
};
/**
* This object will eventually hold references to the previous and next brackets in the tree
* The values are set automatically on first use via the next() and previous() methods
*/
this.relatives = {};
this.listeners = {};
};
Bracket.prototype.addListeners = function() {
var self = this;
var next = this.next();
if (next) {
// if one of the archers that takes part in this bracket also takes part in the next bracket, it means that he actually won this one
next.on('archer.select', function (id) {
if (self.has(id)) {
self.setWinner(id);
}
});
next.on('archer.deselect', function (id) {
if (self.has(id)) {
self.check();
}
});
}
this.element.select('select').invoke('observe', 'change', function (event) {
var previous = parseInt(this.getAttribute('data-previous-value'));
var id = parseInt(this[this.selectedIndex].value);
if (!isNaN(previous)) {
self.emit('archer.deselect', previous);
}
self.check();
if (!isNaN(id)) {
this.setAttribute('data-previous-value', id);
self.emit('archer.select', id);
}
});
this.dom.scores.invoke('observe', 'blur', this.check.bind(this));
};
/**
* Tries to figure out this bracket's winner via the score fields
*/
Bracket.prototype.check = function () {
this.clearWinner();
var archers = this.getArchers();
var scores = this.dom.scores.pluck('value').map(Number).reject(isNaN).uniq();
if (archers.length == 2 && scores.length == 2) {
var max = scores.max();
var winner = parseInt(this.dom.archers[scores.indexOf(max)].value);
}
if (this.bye()) {
var winner = parseInt(this.dom.archers[0].value);
}
if (typeof winner == 'undefined' || isNaN(winner)) {
return;
}
this.setWinner(winner);
};
Bracket.prototype.setWinner = function (id) {
this.dom.winner.value = id;
this.dom.scores.invoke('removeClassName', 'bracket-winner');
var archer_event = this.dom.archers.invoke('removeClassName', 'bracket-winner').find(function (select) {
return select.value == id;
}).addClassName('bracket-winner');
this.dom.scores[this.dom.archers.indexOf(archer_event)].addClassName('bracket-winner');
this.emit('winner', id);
var loser = this.getLoser();
if (loser) {
this.emit('loser', loser);
}
};
Bracket.prototype.clearWinner = function() {
this.dom.winner.value = '';
this.dom.archers.invoke('removeClassName', 'bracket-winner')
this.dom.scores.invoke('removeClassName', 'bracket-winner');
};
Bracket.prototype.getWinner = function() {
var winner = parseInt(this.dom.winner.value);
if (!isNaN(winner) && winner > 0) {
return winner;
}
return false;
};
Bracket.prototype.getLoser = function () {
var winner = this.getWinner();
if (!winner) {
return false;
}
var archers = this.getArchers();
if (archers.length == 1) {
return false;
}
return archers[Math.abs(1 - archers.indexOf(winner))];
};
Bracket.prototype.winner = function(id) {
id = parseInt(id);
if (isNaN(id) || id == 0) {
return false;
}
return this.dom.winner.value == id;
};
Bracket.prototype.getArchers = function() {
return this.dom.archers.pluck('value').map(Number).reject(isNaN).reject(function (id) {
return id == 0
});
};
Bracket.prototype.bye = function() {
return isNaN(Number(this.dom.archers[1].value));
};
/**
* Checks if the specified archer event is one of the two participants of this bracket
*/
Bracket.prototype.has = function(id) {
if (this.dom.archers.find(function (select) {
return select[select.selectedIndex].value == id;
})) {
return true;
}
return false;
};
Bracket.prototype.enable = function (ids) {
if (typeof ids == 'string' && ids == 'all') {
this.element.select('option').each(function (option) {
// option.disabled = false;
option.removeClassName('disabled');
})
return;
}
if (!(ids instanceof Array)) {
ids = [ids];
}
this.element.select('option').each(function (option) {
if (ids.indexOf(parseInt(option.value)) != -1) {
option.removeClassName('disabled');
}
});
return this;
};
Bracket.prototype.disable = function (ids) {
if (typeof ids == 'string' && ids == 'all') {
this.element.select('option[value][value!="-1"]').each(function (option) {
option.addClassName('disabled');
});
return;
}
if (!(ids instanceof Array)) {
ids = [ids];
}
this.dom.archers.each(function (elm) {
elm.select('option[value][value!="-1"]').each(function (option, index) {
if (ids.indexOf(parseInt(option.value)) == -1) {
return;
}
option.addClassName('disabled');
})
});
};
Bracket.prototype.valid = function() {
var unset = this.element.select('selected').find(function (elm) {
return elm.selectedIndex == 0;
});
if (unset) {
return false;
}
return true;
};
Bracket.prototype.next = function () {
if (!this.relatives.hasOwnProperty('next')) {
var next_round = this.round - 1;
if (next_round >= 1) {
var next_order = Math.ceil(this.order / 2);
this.relatives.next = this.manager.getBracket(next_round, next_order);
} else {
this.relatives.next = false;
}
}
return this.relatives.next;
};
/**
* Unlike next(), this method returns the previous TWO brackets,
* as the winners of those brackets participate in this one
*/
Bracket.prototype.previous = function () {
if (!this.relatives.hasOwnProperty('previous')) {
var prev_round = this.round + 1;
if (this.round <= this.rounds) {
var prev_orders = [this.order * 2 - 1, this.order * 2];
this.relatives.previous = this.manager.getBrackets(prev_round, prev_orders);
} else {
this.relatives.previous = false;
}
}
return this.relatives.previous;
};
Bracket.prototype.emit = function(event) {
if (!this.listeners.hasOwnProperty(event)) {
return;
}
var listeners = this.listeners[event];
var args = Array.prototype.slice.call(arguments);
args.splice(0, 1);
for (var i = 0; i < listeners.length; i++) {
listeners[i].apply(this, args);
}
return this;
};
Bracket.prototype.on = function(events, handler) {
if (!(events instanceof Array)) {
events = [events];
}
for (var i = 0; i < events.length; i++) {
var event = events[i];
if (!this.listeners.hasOwnProperty(event)) {
this.listeners[event] = [];
}
this.listeners[event].push(handler);
}
return this;
};
/**
* Called when data is fetched from the database (on bracket.save(), for example)
*/
Bracket.prototype.sync = function(data) {
this.id = data.id;
this.element.setAttribute('data-id', this.id);
this.element.down('input[name="id[]"]').value = this.id;
};
/**
* Called when a bracket round is removed
*/
Bracket.prototype.remove = function() {
};
return Bracket;
});
define(['events/bracket'], function (Bracket) {
var Brackets = function (element, archer_events, options) {
var self = this;
self.brackets = [];
self.element = element;
self.archer_events = archer_events;
self.division = self.element.getAttribute('data-division');
self.options = Object.extend({}, options || {});
self.element.select('.bracket').each(function (elm) {
var bracket = self.create(elm);
});
self.dom = {
indicator: self.element.down('[data-role="indicator"]')
};
self.addListeners();
self.update();
};
Brackets.prototype.enable = function(ids, round) {
this.getBrackets(round).each(function (bracket) {
bracket.enable(ids);
});
};
Brackets.prototype.disable = function(ids, round) {
this.getBrackets(round).each(function (bracket) {
bracket.disable(ids);
});
};
Brackets.prototype.update = function() {
var self = this;
for (var round = self.options.start; round >= 1; round--) {
var brackets = self.getBrackets(round);
var participants = [];
var winners = [];
var losers = [];
brackets.each(function (bracket) {
var p = bracket.getArchers();
if (p.length) {
participants = participants.concat(p);
}
var winner = bracket.getWinner();
if (winner) {
winners.push(winner);
var loser = bracket.getLoser();
if (loser) {
losers.push(loser);
}
}
});
if (round == this.options.start) {
this.enable('all', round);
}
this.disable(participants, round);
// go through all the rounds that follow after the current one and disable the archers that have been eliminated
for (var next_round = round - 1; next_round >= 1; next_round--) {
this.disable('all', next_round);
this.enable(participants, next_round);
if (next_round > 1) {
// losers play in the second round of finals, don't disable them
this.disable(losers, next_round);
}
}
}
};
Brackets.prototype.addListeners = function() {
var self = this;
self.element.on('submit', function (event) {
event.stop();
self.save();
});
if (self.options.start > 2) { // semi-finals and finals cannot be removed
self.element.down('[data-role="remove-round"]').on('click', self.removeRound.bind(self));
}
for (var i = 0; i < self.brackets.length; i++) {
var bracket = self.brackets[i];
bracket.addListeners();
bracket.on(['archer.select', 'archer.deselect', 'winner', 'loser'], self.update.bind(self));
}
};
Brackets.prototype.save = function() {
var self = this;
var data = self.element.serialize(true);
self.element.disable();
self.dom.indicator.show();
new Ajax.Request(APP.url('admin/brackets/save'), {
parameters: data,
onSuccess: function (transport) {
self.element.enable();
self.dom.indicator.hide();
var response = transport.responseText.evalJSON();
for (var round in response) {
for (var order in response[round]) {
var bracket = self.getBracket(round, order);
bracket.sync(response[round][order]);
}
}
}
});
};
Brackets.prototype.create = function (element) {
var bracket = new Bracket(element, this);
this.brackets.push(bracket);
return bracket;
};
Brackets.prototype.getBrackets = function(round, orders) {
var brackets = [];
for (var i = 0; i < this.brackets.length; i++) {
if (this.brackets[i].round == round) {
brackets.push(this.brackets[i]);
}
}
if (typeof orders != 'undefined' && orders.length > 1) {
var ret = [];
for (var i = 0; i < orders.length; i++) {
if (typeof brackets[orders[i] - 1] == 'undefined') {
continue;
}
ret.push(brackets[orders[i] - 1]);
}
return ret;
}
return brackets;
};
Brackets.prototype.getBracket = function(round, order) {
var brackets = this.getBrackets(round);
if (!brackets.length) {
return false;
}
return brackets[order - 1];
};
Brackets.prototype.removeRound = function(event) {
var self = this;
if (!confirm('Ești sigur(ă)?')) {
return;
}
var round = event.element().getAttribute('data-round');
new Ajax.Request(APP.url('admin/event_divisions/remove_round'), {
parameters: {
id: self.division,
round: round
},
onSuccess: function (transport) {
var response = transport.responseText.evalJSON();
if (response.error) {
require(['growler'], function (growler) {
growler.error('Eroare', response.error);
})
return false;
}
for (var i = 0; i < self.brackets.length; i++) {
brackets[i].remove();
}
console.log(brackets);;
// self.element.select('th[data-round="'+round+'"]', 'td[data-round="'+round+'"]').invoke('');
console.log(response);
}
});
};
return Brackets;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment