summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrewMurrell <amurrel@purdue.edu>2014-04-06 22:20:28 -0400
committerAndrewMurrell <amurrel@purdue.edu>2014-04-06 22:20:28 -0400
commitbf798e57a760b68c3c7460789cef6389141c067d (patch)
tree16cd7400b7f289b4aa6ec90e253c4d30d7a1a08c
parent91fee659eadaf6bcc4d063fd5645950da1250896 (diff)
parent628173fce3de8f5d3e31109b3aa7c964fdab38ca (diff)
Merge branch 'master' of http://github.com/LukeShu/leaguer
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock5
-rw-r--r--app/assets/javascripts/application.js3
-rw-r--r--app/assets/stylesheets/custom.css.scss1
-rw-r--r--app/assets/stylesheets/matches.css.scss24
-rw-r--r--app/controllers/matches_controller.rb61
-rw-r--r--app/controllers/servers_controller.rb53
-rw-r--r--app/controllers/tournaments_controller.rb2
-rw-r--r--app/controllers/users_controller.rb2
-rw-r--r--app/models/server.rb36
-rw-r--r--app/models/tournament.rb13
-rw-r--r--app/models/user.rb45
-rw-r--r--app/views/layouts/application.html.erb8
-rw-r--r--app/views/matches/index.html.erb70
-rw-r--r--app/views/matches/show.html.erb37
-rw-r--r--app/views/servers/_form.html.erb19
-rw-r--r--app/views/servers/edit.html.erb3
-rw-r--r--app/views/servers/index.html.erb25
-rw-r--r--app/views/servers/index.json.jbuilder4
-rw-r--r--app/views/servers/new.html.erb5
-rw-r--r--app/views/servers/show.html.erb8
-rw-r--r--app/views/servers/show.json.jbuilder2
-rw-r--r--app/views/tournaments/index.html.erb14
-rw-r--r--app/views/tournaments/show.html.erb4
-rwxr-xr-xbin/delayed_job5
-rw-r--r--db/migrate/20140406195921_create_simple_captcha_data.rb (renamed from db/migrate/20140405215315_create_simple_captcha_data.rb)0
-rw-r--r--db/migrate/20140406235927_create_delayed_jobs.rb22
-rw-r--r--db/migrate/20140406235933_create_servers.rb (renamed from db/migrate/20140406015318_create_servers.rb)1
-rw-r--r--db/migrate/20140406235940_create_matches.rb (renamed from db/migrate/20140406015321_create_matches.rb)0
-rw-r--r--db/migrate/20140406235946_create_teams.rb (renamed from db/migrate/20140406015324_create_teams.rb)0
-rw-r--r--db/migrate/20140406235952_create_alerts.rb (renamed from db/migrate/20140406015327_create_alerts.rb)0
-rw-r--r--db/migrate/20140406235958_create_pms.rb (renamed from db/migrate/20140406015330_create_pms.rb)0
-rw-r--r--db/migrate/20140407000005_create_tournaments.rb (renamed from db/migrate/20140406015332_create_tournaments.rb)0
-rw-r--r--db/migrate/20140407000011_create_games.rb (renamed from db/migrate/20140406015335_create_games.rb)0
-rw-r--r--db/migrate/20140407000017_create_users.rb (renamed from db/migrate/20140406015338_create_users.rb)0
-rw-r--r--db/migrate/20140407000024_create_sessions.rb (renamed from db/migrate/20140406015341_create_sessions.rb)0
-rw-r--r--db/migrate/20140407000030_create_server_settings.rb (renamed from db/migrate/20140406015344_create_server_settings.rb)0
-rw-r--r--db/migrate/20140407000036_create_game_settings.rb (renamed from db/migrate/20140406015347_create_game_settings.rb)0
-rw-r--r--db/migrate/20140407000042_create_tournament_preferences.rb (renamed from db/migrate/20140406015350_create_tournament_preferences.rb)0
-rw-r--r--db/migrate/20140407000048_create_scores.rb (renamed from db/migrate/20140406015353_create_scores.rb)0
-rw-r--r--db/migrate/20140407000054_create_remote_usernames.rb (renamed from db/migrate/20140406015356_create_remote_usernames.rb)0
-rw-r--r--db/migrate/20140407000100_create_tournament_players_join_table.rb (renamed from db/migrate/20140406015359_create_tournament_players_join_table.rb)0
-rw-r--r--db/migrate/20140407000106_create_tournament_hosts_join_table.rb (renamed from db/migrate/20140406015401_create_tournament_hosts_join_table.rb)0
-rw-r--r--db/migrate/20140407000112_create_team_user_join_table.rb (renamed from db/migrate/20140406015404_create_team_user_join_table.rb)0
-rw-r--r--db/migrate/20140407000118_create_match_team_join_table.rb (renamed from db/migrate/20140406015406_create_match_team_join_table.rb)0
-rw-r--r--db/migrate/20140407000143_add_hidden_attrs_to_user.rb (renamed from db/migrate/20140406015417_add_hidden_attrs_to_user.rb)0
-rw-r--r--db/schema.rb19
-rw-r--r--db/seeds.rb3
-rwxr-xr-xgenerate.sh27
-rw-r--r--test/controllers/servers_controller_test.rb4
-rw-r--r--test/fixtures/servers.yml14
-rw-r--r--vendor/assets/javascripts/coordinates.js94
-rw-r--r--vendor/assets/javascripts/drag.js229
-rw-r--r--vendor/assets/javascripts/dragsort.js234
54 files changed, 901 insertions, 197 deletions
diff --git a/Gemfile b/Gemfile
index 49e0795..f8ae193 100644
--- a/Gemfile
+++ b/Gemfile
@@ -49,7 +49,7 @@ gem 'turbolinks'
gem 'jbuilder', '~> 1.2'
# Asynchronously handle longer or delayed tasks
-gem 'delayed_job'
+gem 'delayed_job_active_record'
group :doc do
# bundle exec rake doc:rails generates the API under doc/api.
diff --git a/Gemfile.lock b/Gemfile.lock
index 0de5c48..b894f81 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -45,6 +45,9 @@ GEM
debugger-linecache (1.2.0)
delayed_job (4.0.0)
activesupport (>= 3.0, < 4.1)
+ delayed_job_active_record (4.0.0)
+ activerecord (>= 3.0, < 4.1)
+ delayed_job (>= 3.0, < 4.1)
erubis (2.7.0)
execjs (2.0.2)
hike (1.2.3)
@@ -134,7 +137,7 @@ DEPENDENCIES
bootstrap-sass
byebug
coffee-rails (~> 4.0.0)
- delayed_job
+ delayed_job_active_record
httparty
jbuilder (~> 1.2)
jquery-rails
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index d6925fa..cb6edeb 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -14,3 +14,6 @@
//= require jquery_ujs
//= require turbolinks
//= require_tree .
+//= require 'drag.js'
+//= require 'dragsort.js'
+//= require 'coordinates.js'
diff --git a/app/assets/stylesheets/custom.css.scss b/app/assets/stylesheets/custom.css.scss
index 1a9b09a..febcbb8 100644
--- a/app/assets/stylesheets/custom.css.scss
+++ b/app/assets/stylesheets/custom.css.scss
@@ -24,6 +24,7 @@ a, input[type="submit"] {
&.signup { @extend .btn-success; }
&.signin { @extend .btn-info; }
&.signout { @extend .btn-danger; }
+ &.server { @extend .btn-danger; }
}
p.errors {
diff --git a/app/assets/stylesheets/matches.css.scss b/app/assets/stylesheets/matches.css.scss
index 4c396e3..3ef9170 100644
--- a/app/assets/stylesheets/matches.css.scss
+++ b/app/assets/stylesheets/matches.css.scss
@@ -1,3 +1,27 @@
// Place all the styles related to the matches controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
+#boxes li {
+ cursor: move;
+ position: relative;
+ float: left;
+ margin: 5px;
+ width: 180px;
+ height: 240px;
+ border: 1px solid rgb(0, 0, 0);
+ text-align: center;
+ padding-top: 10px;
+ background-color: rgb(238, 238, 255);
+}
+#numeric li {
+ cursor: move;
+ position: relative;
+ float: left;
+ margin: 5px;
+ width: 180px;
+ height: 240px;
+ border: 1px solid rgb(0, 0, 0);
+ text-align: center;
+ padding-top: 10px;
+ background-color: rgb(238, 238, 255);
+} \ No newline at end of file
diff --git a/app/controllers/matches_controller.rb b/app/controllers/matches_controller.rb
index 31fc9ad..ee68e11 100644
--- a/app/controllers/matches_controller.rb
+++ b/app/controllers/matches_controller.rb
@@ -1,15 +1,22 @@
class MatchesController < ApplicationController
- before_action :set_tournament, only: [:index]
+ before_action :set_tournament, only: [:index, :update]
# GET /matches
# GET /matches.json
require 'httparty'
require 'json'
+ require 'delayed_job'
def index
@matches = @tournament.matches
+ # width of SVG
+ @width = 300 * (Math.log2(@matches.count).floor + 1);
+ # height of SVG
+ @height = 200 * 2**Math.log2(@matches.count).floor + 100;
end
+
+
def get_riot_info
if signed_in?
@@ -114,14 +121,64 @@ class MatchesController < ApplicationController
end #end def
# GET /matches/1
# GET /matches/1.json
+
+ def is_match_over
+ response = HTTParty.get("https://prod.api.pvp.net/api/lol/na/v1.3/summoner/by-name/#{@first}?api_key=ad539f86-22fd-474d-9279-79a7a296ac38")
+ riot_id = response["#{@first}"]['id']
+ #recent game information
+ game_info = HTTParty.get("https://prod.api.pvp.net/api/lol/na/v1.3/game/by-summoner/#{riot_id}/recent?api_key=ad539f86-22fd-474d-9279-79a7a296ac38")
+ first_id = game_info["games"][0]["gameId"]
+
+ while true do
+ sleep(240) #wait four minutes
+
+ recent = HTTParty.get("https://prod.api.pvp.net/api/lol/na/v1.3/game/by-summoner/#{riot_id}/recent?api_key=ad539f86-22fd-474d-9279-79a7a296ac38")
+ current_id = recent["games"][0]["gameId"]
+
+ if current_id != first_id
+ @match.status = 2
+ end
+ end #while
+ end
+ handle_asynchronously :is_match_over
+
def show
+ if @match.id == 1
+ is_match_over
+ end
+
+
+ end
+
+ def update
+ case params[:update_action]
+ when "start"
+ check_permission(:edit, @tournament)
+ status = 1
+ respond_to do |format|
+ if @match
+ format.html { redirect_to tournament_match_path(@tournament, self), notice: 'Match has started.' }
+ format.json { head :no_content }
+ else
+ format.html { redirect_to @tournament, notice: "You don't have permission to start this match." }
+ format.json { render json: "Permission denied", status: :forbidden }
+ end
+ end
+ else
+ respond_to do |format|
+ format.html { redirect_to @tournament, notice: "Invalid action", status: :unprocessable_entity }
+ format.json { render json: @tournament.errors, status: :unprocessable_entity }
+ end
+ end
+
end
private
# Use callbacks to share common setup or constraints between actions.
def set_match
set_tournament
- @match = @tournament.matches.find(params[:id]);
+ @match = @tournament.matches.find(params[:id])
+ @first = @match.teams.first.users.first.user_name.downcase
end
def set_tournament
@tournament = Tournament.find(params[:tournament_id])
diff --git a/app/controllers/servers_controller.rb b/app/controllers/servers_controller.rb
index 6596dc6..83a9f31 100644
--- a/app/controllers/servers_controller.rb
+++ b/app/controllers/servers_controller.rb
@@ -1,43 +1,15 @@
class ServersController < ApplicationController
-
- # GET /servers
- # GET /servers.json
- def index
- @servers = Server.all
- end
-
- # GET /servers/1
- # GET /servers/1.json
+ # GET /server
+ # GET /server.json
def show
end
- # GET /servers/new
- def new
- @server = Server.new
- end
-
- # GET /servers/1/edit
+ # GET /server/edit
def edit
end
- # POST /servers
- # POST /servers.json
- def create
- @server = Server.new(server_params)
-
- respond_to do |format|
- if @server.save
- format.html { redirect_to @server, notice: 'Server was successfully created.' }
- format.json { render action: 'show', status: :created, location: @server }
- else
- format.html { render action: 'new' }
- format.json { render json: @server.errors, status: :unprocessable_entity }
- end
- end
- end
-
- # PATCH/PUT /servers/1
- # PATCH/PUT /servers/1.json
+ # PATCH/PUT /server
+ # PATCH/PUT /server.json
def update
respond_to do |format|
if @server.update(server_params)
@@ -50,24 +22,15 @@ class ServersController < ApplicationController
end
end
- # DELETE /servers/1
- # DELETE /servers/1.json
- def destroy
- @server.destroy
- respond_to do |format|
- format.html { redirect_to servers_url }
- format.json { head :no_content }
- end
- end
-
private
+
# Use callbacks to share common setup or constraints between actions.
def set_server
- @server = Server.find(params[:id])
+ @server = Server.first
end
# Never trust parameters from the scary internet, only allow the white list through.
def server_params
- params[:server]
+ params.require(:server).permit(:default_user_permissions, :default_user_abilities => User.permission_bits.keys)
end
end
diff --git a/app/controllers/tournaments_controller.rb b/app/controllers/tournaments_controller.rb
index a9e91b0..2fc82ed 100644
--- a/app/controllers/tournaments_controller.rb
+++ b/app/controllers/tournaments_controller.rb
@@ -99,7 +99,7 @@ class TournamentsController < ApplicationController
format.html { redirect_to @tournament, notice: 'You have joined this tournament.' }
format.json { head :no_content }
else
- format.html { render action: 'permission_denied', status: :forbidden }
+ format.html { redirect_to @tournament, notice: "You don't have permission to start this tournament." }
format.json { render json: "Permission denied", status: :forbidden }
end
end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index dd66c18..637480f 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -33,7 +33,7 @@ class UsersController < ApplicationController
return
end
- @user.permissions = 0
+ @user.permissions = Server.first.default_user_permissions
respond_to do |format|
if @user.save
sign_in @user
diff --git a/app/models/server.rb b/app/models/server.rb
index 120f0fa..5ba7524 100644
--- a/app/models/server.rb
+++ b/app/models/server.rb
@@ -1,2 +1,38 @@
class Server < ActiveRecord::Base
+ def default_user_abilities
+ @abilities ||= User::Abilities.new(DefaultUser.new(self))
+ end
+ def default_user_abilities=(new)
+ new.each do |k,v|
+ if v == "0"
+ v = false
+ end
+ default_user_abilities[k] = v
+ end
+ end
+ class DefaultUser
+ def initialize(server)
+ @server = server
+ end
+ def can?(action)
+ bit = User.permission_bits[action]
+ if bit.nil?
+ return false
+ else
+ return (@server.default_user_permissions & bit != 0)
+ end
+ end
+ def add_ability(action)
+ bit = User.permission_bits[action.to_sym]
+ unless bit.nil?
+ @server.default_user_permissions |= bit
+ end
+ end
+ def remove_ability(action)
+ bit = User.permission_bits[action.to_sym]
+ unless bit.nil?
+ @server.default_user_permissions &= ~ bit
+ end
+ end
+ end
end
diff --git a/app/models/tournament.rb b/app/models/tournament.rb
index 0b55cb6..fdcdba2 100644
--- a/app/models/tournament.rb
+++ b/app/models/tournament.rb
@@ -78,19 +78,20 @@ class Tournament < ActiveRecord::Base
for i in 1..num_matches
self.matches.create(name: "Match #{i}", status: 0)
end
- match_num = 0
+ match_num = num_matches-1
team_num = 0
#for each grouping of min_players_per_team
- self.players.each_slice(min_players_per_team) do |players|
- #create a new team in the current match
- self.matches[match_num].teams.push(Team.create(users: players))
+ players.each_slice(min_players_per_team) do |players|
+
#if the match is full, move to the next match, otherwise move to the next team
- if (team_num != 0 and team_num % max_teams_per_match == 0)
- match_num += 1
+ if (team_num == min_teams_per_match)
+ match_num -= 1
team_num = 0
else
team_num += 1
end
+ #create a new team in the current match
+ self.matches[match_num].teams.push(Team.create(users: players))
end
end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 626e4bf..0b77ab1 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -11,31 +11,32 @@ class User < ActiveRecord::Base
def self.permission_bits
return {
- :create_tournament => 1,
- :edit_tournament => 2,
- :join_tournament => 3,
- :delete_tournament => 4,
+ :create_tournament => (2**1),
+ :edit_tournament => (2**2),
+ :join_tournament => (2**3),
+ :delete_tournament => (2**4),
- :create_game => 5,
- :edit_game => 6,
- :delete_game => 7,
+ :create_game => (2**5),
+ :edit_game => (2**6),
+ :delete_game => (2**7),
- :create_user => 8,
- :edit_user => 9,
- :delete_user => 10,
+ :create_user => (2**8),
+ :edit_user => (2**9),
+ :delete_user => (2**10),
- :create_alert => 11,
- :edit_alert => 12,
- :delete_alert => 13,
+ :create_alert => (2**11),
+ :edit_alert => (2**12),
+ :delete_alert => (2**13),
- :create_pm => 14,
- :edit_pm => 15,
- :delete_pm => 16,
+ :create_pm => (2**14),
+ :edit_pm => (2**15),
+ :delete_pm => (2**16),
- :create_session => 17,
- :delete_session => 18,
+ :create_session => (2**17),
+ :delete_session => (2**18),
- :edit_permissions => 19,
+ :edit_permissions => (2**19),
+ :edit_server => (2**20),
}
end
@@ -44,21 +45,21 @@ class User < ActiveRecord::Base
if bit.nil?
return false
else
- return (self.permissions & (2**bit) != 0)
+ return (self.permissions & bit != 0)
end
end
def add_ability(action)
bit = User.permission_bits[action.to_sym]
unless bit.nil?
- self.permissions |= 2**bit
+ self.permissions |= bit
end
end
def remove_ability(action)
bit = User.permission_bits[action.to_sym]
unless bit.nil?
- self.permissions &= ~ (2**bit)
+ self.permissions &= ~ bit
end
end
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 976ee85..de9f3b8 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -8,6 +8,11 @@
<%= yield :head %>
</head>
<body>
+<script>
+ window.onload = function() {
+ BetterDragSort.makeListSortable(document.getElementById("boxes"));
+ };
+</script>
<header><nav>
<div class="navbar-brand"><%= link_to('Leaguer', root_path) %></div>
<div>
@@ -21,6 +26,9 @@
<% if signed_in? %>
<%= link_to current_user.user_name, current_user, :class => "user" %>
<%= link_to "Sign out", session_path("current"), method: "delete", :class => "signout" %>
+ <% if current_user.can? :edit_server %>
+ <%= link_to "Server settings", edit_server_path, :class => "server" %>
+ <% end %>
<% else %>
<%= link_to "Log in", new_session_path, :class => "signin" %>
<%= link_to "Sign up", new_user_path, :class => "signup" %>
diff --git a/app/views/matches/index.html.erb b/app/views/matches/index.html.erb
index 219507d..052d176 100644
--- a/app/views/matches/index.html.erb
+++ b/app/views/matches/index.html.erb
@@ -18,7 +18,15 @@
<td><%= match.id%></td>
<td><%= match.name %></td>
<td><%= link_to "Show", tournament_match_path(@tournament, match) %>
- <td><%= submit_tag("Start Match") %>
+ <td> <%# If user is the host, let them start the tournment %>
+ <% if @tournament.hosts.include?(current_user) %>
+
+ <%= form_tag(tournament_match_path(@tournament, match), method: "put") do %>
+ <input type="hidden" name="update_action" value="start">
+ <%= submit_tag("Start Match") %>
+ <% end %>
+ <% end %>
+</div></td>
</tr>
<% end %>
</tbody>
@@ -26,17 +34,51 @@
<br>
-
-<SVG version="1.1"
- baseProfile="full"
- width="<%= 300 * @matches.count / 2 + 50 %>" height="<%= 200 * @matches.count + 50 %>"
- xmlns="http://www.w3.org/2000/svg">
-
- <% (1..@matches.count).each do |i| %>
- <g class="svg-match">
- <rect rx="10"
-
- </g>
- <% end %>
-
+<div id="match-tree">
+ <SVG version="1.1"
+ baseProfile="full"
+ width="<%= @width %>" height="<%= @height = [@height, 500].max %>"
+ xmlns="http://www.w3.org/2000/svg">
+ <script type="text/ecmascript"><![CDATA[
+ function redirect(i){
+ window.location.replace("<%= request.original_url %>"+"/"+i);
+ }
+ ]]>
+ </script>
+ <% (1..@matches.count).each do |i| %>
+ <g id="svg-match-<%= i %>" onmouseover="dispStats(<%= i %>)" onclick="redirect(<%= @matches[i-1].id %>)" cursor="pointer">
+ <rect height="120px" width="213px"
+ x="<%= @width - (i-1)*50 - 250*(Math.log2(i).floor+1) %>"
+ y="<%= (@height/(Math.log2(i).floor+2)) - 60 + 250*(i - 2**(Math.log2(i).floor)) %>"
+ fill="#ffd281"
+ rx="20px"
+ stroke-width="2"
+ <% case @matches[i-1].status %>
+ <% when 0 %>
+ <% if @matches[i-1].teams.count < @tournament.min_teams_per_match %>
+ stroke="red"
+ fill-opacity="0.6"
+ <% else %>
+ stroke="green"
+ <% end %>
+ <% when 1 %>
+ stroke="orange"
+ <% when 2 %>
+ stroke="yellow"
+ <% when 3 %>
+ stroke="grey"
+ <% end %>
+ />
+ </g>
+ <% if i > 1 %>
+ <line
+ stroke="black"
+ x1="<%= @width - (i-2)*50 - 250*(Math.log2(i-1).floor+1) %>"
+ y1="<%= (@height/(Math.log2(i-1).floor+2)) - 60 + 250*((i-1) - 2**(Math.log2(i-1).floor)) + 60 %>"
+ x2="<%= @width - (i-1)*50 - 250*(Math.log2(i).floor+1) + 213 %>"
+ y2="<%= (@height/(Math.log2(i).floor+2)) - 60 + 250*(i - 2**(Math.log2(i).floor)) + 60 %>"
+ />
+ <% end %>
+ <% end %>
</SVG>
+</div>
diff --git a/app/views/matches/show.html.erb b/app/views/matches/show.html.erb
index 6fb4042..25be7b8 100644
--- a/app/views/matches/show.html.erb
+++ b/app/views/matches/show.html.erb
@@ -2,7 +2,6 @@
<strong>Status:</strong>
<%= @match.status %>
</p>
-
<p>
<strong>Tournament:</strong>
<%= @match.tournament.id %>
@@ -27,49 +26,39 @@
Note:- The change of status from 1 to 2 is coming from League Data Pull (RIOT API)
-->
-<!--
- This is what the HOST will see when the Match Status is NOT 3
--->
-<% if (@tournament.hosts.include?(current_user) and @match.winner.nil?) %>
- <%= form_for([@tournament, @match], method: "put") do |f| %>
- <ul>
- <% @match.teams.each do |team| %>
- <li><label><%= f.radio_button(:winner, team.id) %>
- <%= team.users.collect{|u| u.user_name}.join(", ") %></label></li>
- <% end %>
- </ul>
- <%= f.submit("Select Winner") %>
- <% end %>
-<% end %>
<!--
This is what the Players and the Hosts of the tournament will view when the Match Status is 0
-->
-<% if (@match.status==0) %>
+<% if (@match.status==1) %>
<% if (@tournament.players.include?(current_user) || @tournament.hosts.include?(current_user)) %>
<% @match.teams.each do |team| %>
- <ul>
+ <ol>
<% team.users.collect{|u| u.user_name}.each do |k| %>
- <li><label><%= k %></label></li>
+ <li><%= k %></li>
<% end %>
- </ul>
+ </ol>
<% end %>
<% end %>
<% end %>
<!--
+ When Match Status is 2
Players see the Peer Review Page
Host see the Game Status
-->
<% if (@match.status==0) %>
- <% if (@tournament.players.include?(current_user) %>
+ <% if (@tournament.players.include?(current_user)) %>
<% @match.teams.each do |team| %>
- <ul>
+ <ol id="boxes" class="sortable">
<% team.users.collect{|u| u.user_name}.each do |k| %>
- <li><label><%= k %></label></li>
+ <li><%= k %></li>
<% end %>
- </ul>
- <% end %>
+ </ol>
+
+ <% end %>
+ <% elsif (@tournament.hosts.include?(current_user)) %>
+ <label>Game Status Page Goes here! Because you are a Host that is not a player!</label>
<% end %>
<% end %>
diff --git a/app/views/servers/_form.html.erb b/app/views/servers/_form.html.erb
index b08654b..1afde11 100644
--- a/app/views/servers/_form.html.erb
+++ b/app/views/servers/_form.html.erb
@@ -1,15 +1,16 @@
<%= form_for(@server) do |f| %>
- <% if @server.errors.any? %>
- <div id="error_explanation">
- <h2><%= pluralize(@server.errors.count, "error") %> prohibited this server from being saved:</h2>
+ <%= render "common/error_messages", :target => @server %>
- <ul>
- <% @server.errors.full_messages.each do |msg| %>
- <li><%= msg %></li>
+ <fieldset>
+ <legend>Default permissions for new users</legend>
+ <ul>
+ <%= fields_for "server[default_user_abilities]", @server.default_user_abilities do |a| %>
+ <% @server.default_user_abilities.keys.each do |ability| %>
+ <li><label><%= a.check_box(ability) %> <%= ability.to_s.humanize %></label></li>
<% end %>
- </ul>
- </div>
- <% end %>
+ <% end %>
+ </ul>
+ </fieldset>
<div class="actions">
<%= f.submit %>
diff --git a/app/views/servers/edit.html.erb b/app/views/servers/edit.html.erb
index a92cdb5..d37864f 100644
--- a/app/views/servers/edit.html.erb
+++ b/app/views/servers/edit.html.erb
@@ -2,5 +2,4 @@
<%= render 'form' %>
-<%= link_to 'Show', @server %> |
-<%= link_to 'Back', servers_path %>
+<%= link_to server_path %>
diff --git a/app/views/servers/index.html.erb b/app/views/servers/index.html.erb
deleted file mode 100644
index f45d393..0000000
--- a/app/views/servers/index.html.erb
+++ /dev/null
@@ -1,25 +0,0 @@
-<h1>Listing servers</h1>
-
-<table>
- <thead>
- <tr>
- <th></th>
- <th></th>
- <th></th>
- </tr>
- </thead>
-
- <tbody>
- <% @servers.each do |server| %>
- <tr>
- <td><%= link_to 'Show', server %></td>
- <td><%= link_to 'Edit', edit_server_path(server) %></td>
- <td><%= link_to 'Destroy', server, method: :delete, data: { confirm: 'Are you sure?' } %></td>
- </tr>
- <% end %>
- </tbody>
-</table>
-
-<br>
-
-<%= link_to 'New Server', new_server_path %>
diff --git a/app/views/servers/index.json.jbuilder b/app/views/servers/index.json.jbuilder
deleted file mode 100644
index 2776abc..0000000
--- a/app/views/servers/index.json.jbuilder
+++ /dev/null
@@ -1,4 +0,0 @@
-json.array!(@servers) do |server|
- json.extract! server, :id
- json.url server_url(server, format: :json)
-end
diff --git a/app/views/servers/new.html.erb b/app/views/servers/new.html.erb
deleted file mode 100644
index 0422009..0000000
--- a/app/views/servers/new.html.erb
+++ /dev/null
@@ -1,5 +0,0 @@
-<h1>New server</h1>
-
-<%= render 'form' %>
-
-<%= link_to 'Back', servers_path %>
diff --git a/app/views/servers/show.html.erb b/app/views/servers/show.html.erb
index 67f7647..54aaf66 100644
--- a/app/views/servers/show.html.erb
+++ b/app/views/servers/show.html.erb
@@ -1,2 +1,6 @@
-<%= link_to 'Edit', edit_server_path(@server) %> |
-<%= link_to 'Back', servers_path %>
+<p>
+ <strong>Default user permissions:</strong>
+ <%= @server.default_user_permissions %>
+</p>
+
+<%= link_to 'Edit', edit_server_path %>
diff --git a/app/views/servers/show.json.jbuilder b/app/views/servers/show.json.jbuilder
index 972b1c0..c566f76 100644
--- a/app/views/servers/show.json.jbuilder
+++ b/app/views/servers/show.json.jbuilder
@@ -1 +1 @@
-json.extract! @server, :id, :created_at, :updated_at
+json.extract! @server, :id, :default_user_permissions, :created_at, :updated_at
diff --git a/app/views/tournaments/index.html.erb b/app/views/tournaments/index.html.erb
index e174de7..72eacba 100644
--- a/app/views/tournaments/index.html.erb
+++ b/app/views/tournaments/index.html.erb
@@ -15,13 +15,17 @@
<h3><%= t.name %></h3>
<% end %>
- <div class="row">
+ <div class="row" style="margin-left:2%;">
<div class="col-md-4 host">
Hosted by: <%= t.hosts.first.name %>
</div>
- <div class="col-md-8 things">
- <p> Players per team </p>
- <p> two </p>
+ <div class="col-md-4 things">
+ <p> Players per team: <%= t.min_players_per_team %></p>
+ <p> Players signed up: <%= t.players.count %> </p>
+ </div>
+ <div class="col-md-4 things">
+ <p> <%= (t.randomized_teams)? "Teams are Random" : "Teams are Chosen" %></p>
+ <p> Players signed up: <%= t.players.count %> </p>
</div>
</div>
@@ -36,7 +40,7 @@
<%= submit_tag("Join") %>
<% end %>
<% else %>
- <p> You've signed up for this tournament! </p>
+ <p style="margin-top:10px;"> You've signed up for this tournament! </p>
<% end %>
</div>
diff --git a/app/views/tournaments/show.html.erb b/app/views/tournaments/show.html.erb
index b654804..e80e0e8 100644
--- a/app/views/tournaments/show.html.erb
+++ b/app/views/tournaments/show.html.erb
@@ -66,13 +66,13 @@
<% if @tournament.joinable_by?(current_user) && !@tournament.players.include?(current_user) %>
<%= form_tag(tournament_path(@tournament), method: "put") do %>
<input type="hidden" name="update_action" value="join">
- <%= submit_tag("Join Tournamnet") %>
+ <%= submit_tag("Join Tournament") %>
<% end %>
<% elsif @tournament.players.include?(current_user) %>
<%= form_tag(tournament_path(@tournament), method: "put") do %>
<input type="hidden" name="update_action" value="leave">
- <%= submit_tag("Leave Tournamnet") %>
+ <%= submit_tag("Leave Tournament") %>
<% end %>
<% end %>
diff --git a/bin/delayed_job b/bin/delayed_job
new file mode 100755
index 0000000..edf1959
--- /dev/null
+++ b/bin/delayed_job
@@ -0,0 +1,5 @@
+#!/usr/bin/env ruby
+
+require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
+require 'delayed/command'
+Delayed::Command.new(ARGV).daemonize
diff --git a/db/migrate/20140405215315_create_simple_captcha_data.rb b/db/migrate/20140406195921_create_simple_captcha_data.rb
index 4573b20..4573b20 100644
--- a/db/migrate/20140405215315_create_simple_captcha_data.rb
+++ b/db/migrate/20140406195921_create_simple_captcha_data.rb
diff --git a/db/migrate/20140406235927_create_delayed_jobs.rb b/db/migrate/20140406235927_create_delayed_jobs.rb
new file mode 100644
index 0000000..ec0dd93
--- /dev/null
+++ b/db/migrate/20140406235927_create_delayed_jobs.rb
@@ -0,0 +1,22 @@
+class CreateDelayedJobs < ActiveRecord::Migration
+ def self.up
+ create_table :delayed_jobs, :force => true do |table|
+ table.integer :priority, :default => 0, :null => false # Allows some jobs to jump to the front of the queue
+ table.integer :attempts, :default => 0, :null => false # Provides for retries, but still fail eventually.
+ table.text :handler, :null => false # YAML-encoded string of the object that will do work
+ table.text :last_error # reason for last failure (See Note below)
+ table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future.
+ table.datetime :locked_at # Set when a client is working on this object
+ table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
+ table.string :locked_by # Who is working on this object (if locked)
+ table.string :queue # The name of the queue this job is in
+ table.timestamps
+ end
+
+ add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority'
+ end
+
+ def self.down
+ drop_table :delayed_jobs
+ end
+end
diff --git a/db/migrate/20140406015318_create_servers.rb b/db/migrate/20140406235933_create_servers.rb
index f33241a..fbe1b02 100644
--- a/db/migrate/20140406015318_create_servers.rb
+++ b/db/migrate/20140406235933_create_servers.rb
@@ -1,6 +1,7 @@
class CreateServers < ActiveRecord::Migration
def change
create_table :servers do |t|
+ t.integer :default_user_permissions
t.timestamps
end
diff --git a/db/migrate/20140406015321_create_matches.rb b/db/migrate/20140406235940_create_matches.rb
index 31eea12..31eea12 100644
--- a/db/migrate/20140406015321_create_matches.rb
+++ b/db/migrate/20140406235940_create_matches.rb
diff --git a/db/migrate/20140406015324_create_teams.rb b/db/migrate/20140406235946_create_teams.rb
index fdf9a68..fdf9a68 100644
--- a/db/migrate/20140406015324_create_teams.rb
+++ b/db/migrate/20140406235946_create_teams.rb
diff --git a/db/migrate/20140406015327_create_alerts.rb b/db/migrate/20140406235952_create_alerts.rb
index 68a8e10..68a8e10 100644
--- a/db/migrate/20140406015327_create_alerts.rb
+++ b/db/migrate/20140406235952_create_alerts.rb
diff --git a/db/migrate/20140406015330_create_pms.rb b/db/migrate/20140406235958_create_pms.rb
index 93bb5c6..93bb5c6 100644
--- a/db/migrate/20140406015330_create_pms.rb
+++ b/db/migrate/20140406235958_create_pms.rb
diff --git a/db/migrate/20140406015332_create_tournaments.rb b/db/migrate/20140407000005_create_tournaments.rb
index c0d8929..c0d8929 100644
--- a/db/migrate/20140406015332_create_tournaments.rb
+++ b/db/migrate/20140407000005_create_tournaments.rb
diff --git a/db/migrate/20140406015335_create_games.rb b/db/migrate/20140407000011_create_games.rb
index 5e4f56f..5e4f56f 100644
--- a/db/migrate/20140406015335_create_games.rb
+++ b/db/migrate/20140407000011_create_games.rb
diff --git a/db/migrate/20140406015338_create_users.rb b/db/migrate/20140407000017_create_users.rb
index 8032870..8032870 100644
--- a/db/migrate/20140406015338_create_users.rb
+++ b/db/migrate/20140407000017_create_users.rb
diff --git a/db/migrate/20140406015341_create_sessions.rb b/db/migrate/20140407000024_create_sessions.rb
index f667f1e..f667f1e 100644
--- a/db/migrate/20140406015341_create_sessions.rb
+++ b/db/migrate/20140407000024_create_sessions.rb
diff --git a/db/migrate/20140406015344_create_server_settings.rb b/db/migrate/20140407000030_create_server_settings.rb
index dfdd91b..dfdd91b 100644
--- a/db/migrate/20140406015344_create_server_settings.rb
+++ b/db/migrate/20140407000030_create_server_settings.rb
diff --git a/db/migrate/20140406015347_create_game_settings.rb b/db/migrate/20140407000036_create_game_settings.rb
index b1caf5d..b1caf5d 100644
--- a/db/migrate/20140406015347_create_game_settings.rb
+++ b/db/migrate/20140407000036_create_game_settings.rb
diff --git a/db/migrate/20140406015350_create_tournament_preferences.rb b/db/migrate/20140407000042_create_tournament_preferences.rb
index 991d659..991d659 100644
--- a/db/migrate/20140406015350_create_tournament_preferences.rb
+++ b/db/migrate/20140407000042_create_tournament_preferences.rb
diff --git a/db/migrate/20140406015353_create_scores.rb b/db/migrate/20140407000048_create_scores.rb
index 4ca0b0b..4ca0b0b 100644
--- a/db/migrate/20140406015353_create_scores.rb
+++ b/db/migrate/20140407000048_create_scores.rb
diff --git a/db/migrate/20140406015356_create_remote_usernames.rb b/db/migrate/20140407000054_create_remote_usernames.rb
index e265985..e265985 100644
--- a/db/migrate/20140406015356_create_remote_usernames.rb
+++ b/db/migrate/20140407000054_create_remote_usernames.rb
diff --git a/db/migrate/20140406015359_create_tournament_players_join_table.rb b/db/migrate/20140407000100_create_tournament_players_join_table.rb
index be240e8..be240e8 100644
--- a/db/migrate/20140406015359_create_tournament_players_join_table.rb
+++ b/db/migrate/20140407000100_create_tournament_players_join_table.rb
diff --git a/db/migrate/20140406015401_create_tournament_hosts_join_table.rb b/db/migrate/20140407000106_create_tournament_hosts_join_table.rb
index 7521d89..7521d89 100644
--- a/db/migrate/20140406015401_create_tournament_hosts_join_table.rb
+++ b/db/migrate/20140407000106_create_tournament_hosts_join_table.rb
diff --git a/db/migrate/20140406015404_create_team_user_join_table.rb b/db/migrate/20140407000112_create_team_user_join_table.rb
index f3b57fc..f3b57fc 100644
--- a/db/migrate/20140406015404_create_team_user_join_table.rb
+++ b/db/migrate/20140407000112_create_team_user_join_table.rb
diff --git a/db/migrate/20140406015406_create_match_team_join_table.rb b/db/migrate/20140407000118_create_match_team_join_table.rb
index c2ed1b7..c2ed1b7 100644
--- a/db/migrate/20140406015406_create_match_team_join_table.rb
+++ b/db/migrate/20140407000118_create_match_team_join_table.rb
diff --git a/db/migrate/20140406015417_add_hidden_attrs_to_user.rb b/db/migrate/20140407000143_add_hidden_attrs_to_user.rb
index 9b5c505..9b5c505 100644
--- a/db/migrate/20140406015417_add_hidden_attrs_to_user.rb
+++ b/db/migrate/20140407000143_add_hidden_attrs_to_user.rb
diff --git a/db/schema.rb b/db/schema.rb
index 829ad0e..f4612b8 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20140406015417) do
+ActiveRecord::Schema.define(version: 20140407000143) do
create_table "alerts", force: true do |t|
t.integer "author_id"
@@ -22,6 +22,22 @@ ActiveRecord::Schema.define(version: 20140406015417) do
add_index "alerts", ["author_id"], name: "index_alerts_on_author_id"
+ create_table "delayed_jobs", force: true do |t|
+ t.integer "priority", default: 0, null: false
+ t.integer "attempts", default: 0, null: false
+ t.text "handler", null: false
+ t.text "last_error"
+ t.datetime "run_at"
+ t.datetime "locked_at"
+ t.datetime "failed_at"
+ t.string "locked_by"
+ t.string "queue"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority"
+
create_table "game_settings", force: true do |t|
t.integer "game_id"
t.integer "stype"
@@ -115,6 +131,7 @@ ActiveRecord::Schema.define(version: 20140406015417) do
end
create_table "servers", force: true do |t|
+ t.integer "default_user_permissions"
t.datetime "created_at"
t.datetime "updated_at"
end
diff --git a/db/seeds.rb b/db/seeds.rb
index 01723bb..a6ddf11 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -6,6 +6,9 @@
# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
# Mayor.create(name: 'Emanuel', city: cities.first)
#
+p = User.permission_bits
+Server.create(default_user_permissions: p[:join_tournament] | p[:create_pm])
+
Game.create(name: "League of Legends",min_players_per_team: 5, max_players_per_team: 5, min_teams_per_match: 2, max_teams_per_match: 2, set_rounds: nil, randomized_teams: true)
Game.create(name: "Chess", min_players_per_team: 1, max_players_per_team: 1, min_teams_per_match: 2, max_teams_per_match: 2, set_rounds: nil, randomized_teams: true)
Game.create(name: "Hearthstone", min_players_per_team: 1, max_players_per_team: 1, min_teams_per_match: 2, max_teams_per_match: 2, set_rounds: 1, randomized_teams: false)
diff --git a/generate.sh b/generate.sh
index 1e15106..e3e07f9 100755
--- a/generate.sh
+++ b/generate.sh
@@ -9,17 +9,18 @@ set -xe
srcdir=$(dirname "$(readlink -f "$0")")
cd "$srcdir"
-git rm -rf app test config/routes.rb db/migrate
+git rm -rf -- app test config/routes.rb db/migrate || true
git checkout clean-start -- app test config/routes.rb
bundle exec rails generate simple_captcha
+bundle exec rails generate delayed_job:active_record
# The whole shebang, models, views, and controllers
-bundle exec rails generate scaffold server --force $NOTEST
-bundle exec rails generate scaffold match status:integer tournament:references name:string winner:references remote_id:string $NOTEST
-bundle exec rails generate scaffold team match:references $NOTEST
-bundle exec rails generate scaffold alert author:references message:text $NOTEST
-bundle exec rails generate scaffold pm author:references recipient:references message:text $NOTEST
+bundle exec rails generate scaffold server default_user_permissions:integer
+bundle exec rails generate scaffold match status:integer tournament:references name:string winner:references remote_id:string
+bundle exec rails generate scaffold team match:references
+bundle exec rails generate scaffold alert author:references message:text
+bundle exec rails generate scaffold pm author:references recipient:references message:text
bundle exec rails generate scaffold tournament name:string:unique game:references status:integer \
min_players_per_team:integer max_players_per_team:integer \
min_teams_per_match:integer max_teams_per_match:integer \
@@ -33,10 +34,10 @@ bundle exec rails generate scaffold user name:string email:string:uniq user_name
bundle exec rails generate scaffold session user:references token:string:uniq
# Just models
-bundle exec rails generate model server_setting $NOTEST
-bundle exec rails generate model game_setting game:references stype:integer name:string default:text description:text type_opt:text display_order:integer $NOTEST
-bundle exec rails generate model tournament_preference tournament:references vartype:integer name:string value:text $NOTEST
-bundle exec rails generate model score user:references match:references value:integer $NOTEST
+bundle exec rails generate model server_setting
+bundle exec rails generate model game_setting game:references stype:integer name:string default:text description:text type_opt:text display_order:integer
+bundle exec rails generate model tournament_preference tournament:references vartype:integer name:string value:text
+bundle exec rails generate model score user:references match:references value:integer
bundle exec rails generate model remote_username game:references user:references json_value:text
# Join tables
@@ -46,9 +47,9 @@ bundle exec rails generate migration CreateTeamUserJoinTable teams users
bundle exec rails generate migration CreateMatchTeamJoinTable matches teams
# Just controllers
-bundle exec rails generate controller search $NOTEST
-bundle exec rails generate controller main $NOTEST
-bundle exec rails generate controller static $NOTEST
+bundle exec rails generate controller search
+bundle exec rails generate controller main
+bundle exec rails generate controller static
# Migrations
# By having these separate from the original 'generate', it makes it
diff --git a/test/controllers/servers_controller_test.rb b/test/controllers/servers_controller_test.rb
index 5891bb0..3a01d56 100644
--- a/test/controllers/servers_controller_test.rb
+++ b/test/controllers/servers_controller_test.rb
@@ -18,7 +18,7 @@ class ServersControllerTest < ActionController::TestCase
test "should create server" do
assert_difference('Server.count') do
- post :create, server: { }
+ post :create, server: { default_user_permissions: @server.default_user_permissions }
end
assert_redirected_to server_path(assigns(:server))
@@ -35,7 +35,7 @@ class ServersControllerTest < ActionController::TestCase
end
test "should update server" do
- patch :update, id: @server, server: { }
+ patch :update, id: @server, server: { default_user_permissions: @server.default_user_permissions }
assert_redirected_to server_path(assigns(:server))
end
diff --git a/test/fixtures/servers.yml b/test/fixtures/servers.yml
index 937a0c0..3001059 100644
--- a/test/fixtures/servers.yml
+++ b/test/fixtures/servers.yml
@@ -1,11 +1,7 @@
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
-# This model initially had no columns defined. If you add columns to the
-# model remove the '{}' from the fixture names and add the columns immediately
-# below each fixture, per the syntax in the comments below
-#
-one: {}
-# column: value
-#
-two: {}
-# column: value
+one:
+ default_user_permissions: 1
+
+two:
+ default_user_permissions: 1
diff --git a/vendor/assets/javascripts/coordinates.js b/vendor/assets/javascripts/coordinates.js
new file mode 100644
index 0000000..e2f5bf2
--- /dev/null
+++ b/vendor/assets/javascripts/coordinates.js
@@ -0,0 +1,94 @@
+var Coordinates = {
+ ORIGIN : new Coordinate(0, 0),
+
+ northwestPosition : function(element) {
+ var x = parseInt(element.style.left);
+ var y = parseInt(element.style.top);
+
+ return new Coordinate(isNaN(x) ? 0 : x, isNaN(y) ? 0 : y);
+ },
+
+ southeastPosition : function(element) {
+ return Coordinates.northwestPosition(element).plus(
+ new Coordinate(element.offsetWidth, element.offsetHeight));
+ },
+
+ northwestOffset : function(element, isRecursive) {
+ var offset = new Coordinate(element.offsetLeft, element.offsetTop);
+
+ if (!isRecursive) return offset;
+
+ var parent = element.offsetParent;
+ while (parent) {
+ offset = offset.plus(
+ new Coordinate(parent.offsetLeft, parent.offsetTop));
+ parent = parent.offsetParent;
+ }
+ return offset;
+ },
+
+ southeastOffset : function(element, isRecursive) {
+ return Coordinates.northwestOffset(element, isRecursive).plus(
+ new Coordinate(element.offsetWidth, element.offsetHeight));
+ },
+
+ fixEvent : function(event) {
+ event.windowCoordinate = new Coordinate(event.clientX, event.clientY);
+ }
+};
+
+function Coordinate(x, y) {
+ this.x = x;
+ this.y = y;
+}
+
+Coordinate.prototype.toString = function() {
+ return "(" + this.x + "," + this.y + ")";
+}
+
+Coordinate.prototype.plus = function(that) {
+ return new Coordinate(this.x + that.x, this.y + that.y);
+}
+
+Coordinate.prototype.minus = function(that) {
+ return new Coordinate(this.x - that.x, this.y - that.y);
+}
+
+Coordinate.prototype.distance = function(that) {
+ var deltaX = this.x - that.x;
+ var deltaY = this.y - that.y;
+
+ return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
+}
+
+Coordinate.prototype.max = function(that) {
+ var x = Math.max(this.x, that.x);
+ var y = Math.max(this.y, that.y);
+ return new Coordinate(x, y);
+}
+
+Coordinate.prototype.constrain = function(min, max) {
+ if (min.x > max.x || min.y > max.y) return this;
+
+ var x = this.x;
+ var y = this.y;
+
+ if (min.x != null) x = Math.max(x, min.x);
+ if (max.x != null) x = Math.min(x, max.x);
+ if (min.y != null) y = Math.max(y, min.y);
+ if (max.y != null) y = Math.min(y, max.y);
+
+ return new Coordinate(x, y);
+}
+
+Coordinate.prototype.reposition = function(element) {
+ element.style["top"] = this.y + "px";
+ element.style["left"] = this.x + "px";
+}
+
+Coordinate.prototype.equals = function(that) {
+ if (this == that) return true;
+ if (!that || that == null) return false;
+
+ return this.x == that.x && this.y == that.y;
+}
diff --git a/vendor/assets/javascripts/drag.js b/vendor/assets/javascripts/drag.js
new file mode 100644
index 0000000..9ba6746
--- /dev/null
+++ b/vendor/assets/javascripts/drag.js
@@ -0,0 +1,229 @@
+/*
+ * drag.js - click & drag DOM elements
+ *
+ * originally based on Youngpup's dom-drag.js, www.youngpup.net
+ */
+
+var Drag = {
+ BIG_Z_INDEX : 10000,
+ group : null,
+ isDragging : false,
+
+ makeDraggable : function(group) {
+ group.handle = group;
+ group.handle.group = group;
+
+ group.minX = null;
+ group.minY = null;
+ group.maxX = null;
+ group.maxY = null;
+ group.threshold = 0;
+ group.thresholdY = 0;
+ group.thresholdX = 0;
+
+ group.onDragStart = new Function();
+ group.onDragEnd = new Function();
+ group.onDrag = new Function();
+
+ // TODO: use element.prototype.myFunc
+ group.setDragHandle = Drag.setDragHandle;
+ group.setDragThreshold = Drag.setDragThreshold;
+ group.setDragThresholdX = Drag.setDragThresholdX;
+ group.setDragThresholdY = Drag.setDragThresholdY;
+ group.constrain = Drag.constrain;
+ group.constrainVertical = Drag.constrainVertical;
+ group.constrainHorizontal = Drag.constrainHorizontal;
+
+ group.onmousedown = Drag.onMouseDown;
+ },
+
+ constrainVertical : function() {
+ var nwOffset = Coordinates.northwestOffset(this, true);
+ this.minX = nwOffset.x;
+ this.maxX = nwOffset.x;
+ },
+
+ constrainHorizontal : function() {
+ var nwOffset = Coordinates.northwestOffset(this, true);
+ this.minY = nwOffset.y;
+ this.maxY = nwOffset.y;
+ },
+
+ constrain : function(nwPosition, sePosition) {
+ this.minX = nwPosition.x;
+ this.minY = nwPosition.y;
+ this.maxX = sePosition.x;
+ this.maxY = sePosition.y;
+ },
+
+ setDragHandle : function(handle) {
+ if (handle && handle != null)
+ this.handle = handle;
+ else
+ this.handle = this;
+
+ this.handle.group = this;
+ this.onmousedown = null;
+ this.handle.onmousedown = Drag.onMouseDown;
+ },
+
+ setDragThreshold : function(threshold) {
+ if (isNaN(parseInt(threshold))) return;
+
+ this.threshold = threshold;
+ },
+
+ setDragThresholdX : function(threshold) {
+ if (isNaN(parseInt(threshold))) return;
+
+ this.thresholdX = threshold;
+ },
+
+ setDragThresholdY : function(threshold) {
+ if (isNaN(parseInt(threshold))) return;
+
+ this.thresholdY = threshold;
+ },
+
+ onMouseDown : function(event) {
+ event = Drag.fixEvent(event);
+ Drag.group = this.group;
+
+ var group = this.group;
+ var mouse = event.windowCoordinate;
+ var nwOffset = Coordinates.northwestOffset(group, true);
+ var nwPosition = Coordinates.northwestPosition(group);
+ var sePosition = Coordinates.southeastPosition(group);
+ var seOffset = Coordinates.southeastOffset(group, true);
+
+ group.originalOpacity = group.style.opacity;
+ group.originalZIndex = group.style.zIndex;
+ group.initialWindowCoordinate = mouse;
+ // TODO: need a better name, but don't yet understand how it
+ // participates in the magic while dragging
+ group.dragCoordinate = mouse;
+
+ Drag.showStatus(mouse, nwPosition, sePosition, nwOffset, seOffset);
+
+ group.onDragStart(nwPosition, sePosition, nwOffset, seOffset);
+
+ // TODO: need better constraint API
+ if (group.minX != null)
+ group.minMouseX = mouse.x - nwPosition.x +
+ group.minX - nwOffset.x;
+ if (group.maxX != null)
+ group.maxMouseX = group.minMouseX + group.maxX - group.minX;
+
+ if (group.minY != null)
+ group.minMouseY = mouse.y - nwPosition.y +
+ group.minY - nwOffset.y;
+ if (group.maxY != null)
+ group.maxMouseY = group.minMouseY + group.maxY - group.minY;
+
+ group.mouseMin = new Coordinate(group.minMouseX, group.minMouseY);
+ group.mouseMax = new Coordinate(group.maxMouseX, group.maxMouseY);
+
+ document.onmousemove = Drag.onMouseMove;
+ document.onmouseup = Drag.onMouseUp;
+
+ return false;
+ },
+
+ showStatus : function(mouse, nwPosition, sePosition, nwOffset, seOffset) {
+ window.status =
+ "mouse: " + mouse.toString() + " " +
+ "NW pos: " + nwPosition.toString() + " " +
+ "SE pos: " + sePosition.toString() + " " +
+ "NW offset: " + nwOffset.toString() + " " +
+ "SE offset: " + seOffset.toString();
+ },
+
+ onMouseMove : function(event) {
+ event = Drag.fixEvent(event);
+ var group = Drag.group;
+ var mouse = event.windowCoordinate;
+ var nwOffset = Coordinates.northwestOffset(group, true);
+ var nwPosition = Coordinates.northwestPosition(group);
+ var sePosition = Coordinates.southeastPosition(group);
+ var seOffset = Coordinates.southeastOffset(group, true);
+
+ Drag.showStatus(mouse, nwPosition, sePosition, nwOffset, seOffset);
+
+ if (!Drag.isDragging) {
+ if (group.threshold > 0) {
+ var distance = group.initialWindowCoordinate.distance(
+ mouse);
+ if (distance < group.threshold) return true;
+ } else if (group.thresholdY > 0) {
+ var deltaY = Math.abs(group.initialWindowCoordinate.y - mouse.y);
+ if (deltaY < group.thresholdY) return true;
+ } else if (group.thresholdX > 0) {
+ var deltaX = Math.abs(group.initialWindowCoordinate.x - mouse.x);
+ if (deltaX < group.thresholdX) return true;
+ }
+
+ Drag.isDragging = true;
+ group.style["zIndex"] = Drag.BIG_Z_INDEX;
+ group.style["opacity"] = 0.75;
+ }
+
+ // TODO: need better constraint API
+ var adjusted = mouse.constrain(group.mouseMin, group.mouseMax);
+ nwPosition = nwPosition.plus(adjusted.minus(group.dragCoordinate));
+ nwPosition.reposition(group);
+ group.dragCoordinate = adjusted;
+
+ // once dragging has started, the position of the group
+ // relative to the mouse should stay fixed. They can get out
+ // of sync if the DOM is manipulated while dragging, so we
+ // correct the error here
+ //
+ // TODO: what we really want to do is find the offset from
+ // our corner to the mouse coordinate and adjust to keep it
+ // the same
+ var offsetBefore = Coordinates.northwestOffset(group);
+ group.onDrag(nwPosition, sePosition, nwOffset, seOffset);
+ var offsetAfter = Coordinates.northwestOffset(group);
+
+ if (!offsetBefore.equals(offsetAfter)) {
+ var errorDelta = offsetBefore.minus(offsetAfter);
+ nwPosition = Coordinates.northwestPosition(group).plus(errorDelta);
+ nwPosition.reposition(group);
+ }
+
+ return false;
+ },
+
+ onMouseUp : function(event) {
+ event = Drag.fixEvent(event);
+ var group = Drag.group;
+
+ var mouse = event.windowCoordinate;
+ var nwOffset = Coordinates.northwestOffset(group, true);
+ var nwPosition = Coordinates.northwestPosition(group);
+ var sePosition = Coordinates.southeastPosition(group);
+ var seOffset = Coordinates.southeastOffset(group, true);
+
+ document.onmousemove = null;
+ document.onmouseup = null;
+ group.onDragEnd(nwPosition, sePosition, nwOffset, seOffset);
+
+ if (Drag.isDragging) {
+ // restoring zIndex before opacity avoids visual flicker in Firefox
+ group.style["zIndex"] = group.originalZIndex;
+ group.style["opacity"] = group.originalOpacity;
+ }
+
+ Drag.group = null;
+ Drag.isDragging = false;
+
+ return false;
+ },
+
+ fixEvent : function(event) {
+ if (typeof event == 'undefined') event = window.event;
+ Coordinates.fixEvent(event);
+
+ return event;
+ }
+};
diff --git a/vendor/assets/javascripts/dragsort.js b/vendor/assets/javascripts/dragsort.js
new file mode 100644
index 0000000..6356663
--- /dev/null
+++ b/vendor/assets/javascripts/dragsort.js
@@ -0,0 +1,234 @@
+// TODO: refactor away duplicationg in DragSort and DragSortX
+
+var BetterDragSort = {
+
+ makeListSortable : function(list) {
+ var items = list.getElementsByTagName("li");
+
+ for (var i = 0; i < items.length; i++) {
+ BetterDragSort.makeItemSortable(items[i]);
+ }
+ },
+
+ makeItemSortable : function(item) {
+ Drag.makeDraggable(item);
+ item.setDragThresholdY(5);
+
+ item.onDragStart = BetterDragSort.onDragStart;
+ item.onDrag = BetterDragSort.onDrag;
+ item.onDragEnd = BetterDragSort.onDragEnd;
+ },
+
+ onDragStart : function(nwPosition, sePosition, nwOffset, seOffset) {
+ var items = this.parentNode.getElementsByTagName("li");
+ var minOffset = Coordinates.northwestOffset(items[0], true);
+ var maxOffset = minOffset;
+ for (var i = 0; i < items.length; i++) {
+ maxOffset = maxOffset.max(Coordinates.northwestOffset(items[i], true));
+ }
+ this.constrain(minOffset, maxOffset);
+ },
+
+ onDrag : function(nwPosition, sePosition, nwOffset, seOffset) {
+ var swapper = null;
+
+ var next = DragUtils.nextItem(this);
+ while (next != null) {
+ var nextNWOffset = Coordinates.northwestOffset(next, true);
+ var nextSEOffset = Coordinates.southeastOffset(next, true);
+
+ if (nwOffset.y >= (nextNWOffset.y - 2) &&
+ nwOffset.y <= (nextSEOffset.y + 2) &&
+ nwOffset.x >= (nextNWOffset.x - 2) &&
+ nwOffset.x <= (nextSEOffset.x + 2)) {
+ var swapper = next;
+ break;
+ }
+ var next = DragUtils.nextItem(next);
+ }
+ if (swapper != null) {
+ BetterDragSort.moveAfter(this, swapper);
+ return;
+ }
+
+ var previous = DragUtils.previousItem(this);
+ while (previous != null) {
+ var previousNWOffset = Coordinates.northwestOffset(previous, true);
+ var previousSEOffset = Coordinates.southeastOffset(previous, true);
+
+ var fudgeFactor = 2;
+ if (nwOffset.y >= (previousNWOffset.y - fudgeFactor) &&
+ nwOffset.y <= (previousSEOffset.y + fudgeFactor) &&
+ nwOffset.x >= (previousNWOffset.x - fudgeFactor) &&
+ nwOffset.x <= (previousSEOffset.x + fudgeFactor)) {
+ var swapper = previous;
+ break;
+ }
+ var previous = DragUtils.previousItem(previous);
+ }
+ if (swapper != null) {
+ BetterDragSort.moveBefore(this, swapper);
+ return;
+ }
+ },
+
+ moveAfter : function(item1, item2) {
+ var parent = item1.parentNode;
+ parent.removeChild(item1);
+ parent.insertBefore(item1, item2.nextSibling);
+
+ item1.style["top"] = "0px";
+ item1.style["left"] = "0px";
+ },
+
+ moveBefore : function(item1, item2) {
+ var parent = item1.parentNode;
+ parent.removeChild(item1);
+ parent.insertBefore(item1, item2);
+
+ item1.style["top"] = "0px";
+ item1.style["left"] = "0px";
+ },
+
+ onDragEnd : function(nwPosition, sePosition, nwOffset, seOffset) {
+ this.style["top"] = "0px";
+ this.style["left"] = "0px";
+ }
+};
+
+
+var DragSort = {
+
+ makeListSortable : function(list) {
+ var items = list.getElementsByTagName("li");
+
+ for (var i = 0; i < items.length; i++) {
+ DragSort.makeItemSortable(items[i]);
+ }
+ },
+
+ makeItemSortable : function(item) {
+ Drag.makeDraggable(item);
+ item.setDragThresholdY(5);
+
+ item.onDragStart = DragSort.onDragStart;
+ item.onDrag = DragSort.onDrag;
+ item.onDragEnd = DragSort.onDragEnd;
+ },
+
+ onDragStart : function(nwPosition, sePosition, nwOffset, seOffset) {
+ var items = this.parentNode.getElementsByTagName("li");
+ var minOffset = Coordinates.northwestOffset(items[0], true);
+ var maxOffset = Coordinates.northwestOffset(items[items.length - 1], true);
+ this.constrain(minOffset, maxOffset);
+ },
+
+ onDrag : function(nwPosition, sePosition, nwOffset, seOffset) {
+ var parent = this.parentNode;
+
+ var item = this;
+ var next = DragUtils.nextItem(item);
+ while (next != null && this.offsetTop >= next.offsetTop - 2) {
+ var item = next;
+ var next = DragUtils.nextItem(item);
+ }
+ if (this != item) {
+ DragUtils.swap(this, next);
+ return;
+ }
+
+ var item = this;
+ var previous = DragUtils.previousItem(item);
+ while (previous != null && this.offsetTop <= previous.offsetTop + 2) {
+ var item = previous;
+ var previous = DragUtils.previousItem(item);
+ }
+ if (this != item) {
+ DragUtils.swap(this, item);
+ return;
+ }
+ },
+
+ onDragEnd : function(nwPosition, sePosition, nwOffset, seOffset) {
+ this.style["top"] = "0px";
+ this.style["left"] = "0px";
+ }
+};
+
+var DragSortX = {
+
+ makeListSortable : function(list) {
+ var items = list.getElementsByTagName("li");
+
+ var minOffset = Coordinates.northwestOffset(items[0], true);
+ var maxOffset = Coordinates.northwestOffset(items[items.length - 1], true);
+
+ for (var i = 0; i < items.length; i++) {
+ Drag.makeDraggable(items[i]);
+ items[i].constrain(minOffset, maxOffset);
+ items[i].setDragThresholdX(5);
+
+ items[i].onDrag = DragSortX.onDrag;
+
+ items[i].onDragEnd = function(nwPosition, sePosition, nwOffset, seOffset) {
+ this.style["top"] = "0px";
+ this.style["left"] = "0px";
+ };
+ }
+ },
+
+ onDrag : function(nwPosition, sePosition, nwOffset, seOffset) {
+ var parent = this.parentNode;
+
+ var item = this;
+ var next = DragUtils.nextItem(item);
+ while (next != null && this.offsetLeft >= next.offsetLeft - 2) {
+ var item = next;
+ var next = DragUtils.nextItem(item);
+ }
+ if (this != item) {
+ DragUtils.swap(this, next);
+ return;
+ }
+
+ var item = this;
+ var previous = DragUtils.previousItem(item);
+ while (previous != null && this.offsetLeft <= previous.offsetLeft + 2) {
+ var item = previous;
+ var previous = DragUtils.previousItem(item);
+ }
+ if (this != item) {
+ DragUtils.swap(this, item);
+ return;
+ }
+ }
+};
+
+var DragUtils = {
+ swap : function(item1, item2) {
+ var parent = item1.parentNode;
+ parent.removeChild(item1);
+ parent.insertBefore(item1, item2);
+
+ item1.style["top"] = "0px";
+ item1.style["left"] = "0px";
+ },
+
+ nextItem : function(item) {
+ var sibling = item.nextSibling;
+ while (sibling != null) {
+ if (sibling.nodeName == item.nodeName) return sibling;
+ sibling = sibling.nextSibling;
+ }
+ return null;
+ },
+
+ previousItem : function(item) {
+ var sibling = item.previousSibling;
+ while (sibling != null) {
+ if (sibling.nodeName == item.nodeName) return sibling;
+ sibling = sibling.previousSibling;
+ }
+ return null;
+ }
+};