diff options
author | AndrewMurrell <amurrel@purdue.edu> | 2014-04-06 22:20:28 -0400 |
---|---|---|
committer | AndrewMurrell <amurrel@purdue.edu> | 2014-04-06 22:20:28 -0400 |
commit | bf798e57a760b68c3c7460789cef6389141c067d (patch) | |
tree | 16cd7400b7f289b4aa6ec90e253c4d30d7a1a08c | |
parent | 91fee659eadaf6bcc4d063fd5645950da1250896 (diff) | |
parent | 628173fce3de8f5d3e31109b3aa7c964fdab38ca (diff) |
Merge branch 'master' of http://github.com/LukeShu/leaguer
54 files changed, 901 insertions, 197 deletions
@@ -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; + } +}; |