radiant-race_results-extension 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. data/README.md +8 -0
  2. data/Rakefile +137 -0
  3. data/app/controllers/admin/race_clubs_controller.rb +15 -0
  4. data/app/controllers/admin/race_competitors_controller.rb +15 -0
  5. data/app/controllers/admin/race_instances_controller.rb +17 -0
  6. data/app/controllers/admin/races_controller.rb +35 -0
  7. data/app/controllers/race_instances_controller.rb +23 -0
  8. data/app/controllers/race_performances_controller.rb +16 -0
  9. data/app/controllers/races_controller.rb +13 -0
  10. data/app/helpers/races_helper.rb +38 -0
  11. data/app/models/race.rb +64 -0
  12. data/app/models/race_category.rb +114 -0
  13. data/app/models/race_checkpoint.rb +31 -0
  14. data/app/models/race_checkpoint_time.rb +64 -0
  15. data/app/models/race_club.rb +48 -0
  16. data/app/models/race_club_alias.rb +9 -0
  17. data/app/models/race_competitor.rb +20 -0
  18. data/app/models/race_instance.rb +178 -0
  19. data/app/models/race_page.rb +69 -0
  20. data/app/models/race_performance.rb +175 -0
  21. data/app/models/race_performance_status.rb +58 -0
  22. data/app/models/race_record.rb +27 -0
  23. data/app/views/admin/race_checkpoints/_checkpoint.html.haml +19 -0
  24. data/app/views/admin/race_club_aliases/_race_club_alias.html.haml +10 -0
  25. data/app/views/admin/race_clubs/_club.html.haml +19 -0
  26. data/app/views/admin/race_clubs/_form.html.haml +21 -0
  27. data/app/views/admin/race_clubs/edit.html.haml +20 -0
  28. data/app/views/admin/race_clubs/index.html.haml +27 -0
  29. data/app/views/admin/race_competitors/_competitor.html.haml +14 -0
  30. data/app/views/admin/race_competitors/_form.html.haml +21 -0
  31. data/app/views/admin/race_competitors/edit.html.haml +20 -0
  32. data/app/views/admin/race_competitors/index.html.haml +27 -0
  33. data/app/views/admin/race_instances/_form.html.haml +98 -0
  34. data/app/views/admin/race_instances/edit.html.haml +17 -0
  35. data/app/views/admin/race_instances/new.html.haml +18 -0
  36. data/app/views/admin/race_records/_record.html.haml +20 -0
  37. data/app/views/admin/races/_form.html.haml +82 -0
  38. data/app/views/admin/races/_race.html.haml +36 -0
  39. data/app/views/admin/races/edit.html.haml +19 -0
  40. data/app/views/admin/races/index.html.haml +26 -0
  41. data/app/views/admin/races/new.html.haml +19 -0
  42. data/app/views/race_categories/show.html.haml +36 -0
  43. data/app/views/race_clubs/show.html.haml +25 -0
  44. data/app/views/race_instances/index.html.haml +14 -0
  45. data/app/views/race_instances/show.html.haml +52 -0
  46. data/app/views/race_performances/_headings.html.haml +4 -0
  47. data/app/views/race_performances/_performance.html.haml +21 -0
  48. data/app/views/races/index.html.haml +38 -0
  49. data/app/views/races/show.html.haml +81 -0
  50. data/cucumber.yml +1 -0
  51. data/db/migrate/20091116130836_race_data.rb +128 -0
  52. data/db/migrate/20091124095157_competitor_details.rb +9 -0
  53. data/db/migrate/20091126110634_club_aliases.rb +17 -0
  54. data/db/migrate/20091223094002_instance_details.rb +11 -0
  55. data/db/migrate/20091224100524_race_distance.rb +11 -0
  56. data/db/migrate/20091224100734_race_records.rb +19 -0
  57. data/db/migrate/20091224105637_category_details.rb +13 -0
  58. data/db/migrate/20091224115909_filters.rb +11 -0
  59. data/db/migrate/20091228122837_record_holder.rb +11 -0
  60. data/db/migrate/20100106104850_remember_calculations.rb +9 -0
  61. data/db/migrate/20100426104801_race_attachments.rb +11 -0
  62. data/features/support/env.rb +16 -0
  63. data/features/support/paths.rb +14 -0
  64. data/lib/duration_extensions.rb +61 -0
  65. data/lib/race_results/admin_ui.rb +76 -0
  66. data/lib/race_results/race_tags.rb +722 -0
  67. data/lib/tasks/race_results_extension_tasks.rake +28 -0
  68. data/public/images/admin/calendar_down.png +0 -0
  69. data/public/images/admin/new-race.png +0 -0
  70. data/public/javascripts/admin/races.js +29 -0
  71. data/public/stylesheets/sass/admin/races.sass +131 -0
  72. data/race_results_extension.rb +38 -0
  73. data/spec/datasets/competitors_dataset.rb +81 -0
  74. data/spec/datasets/race_sites_dataset.rb +8 -0
  75. data/spec/datasets/races_dataset.rb +179 -0
  76. data/spec/files/dunnerdale_2009.csv +277 -0
  77. data/spec/files/long_duddon_2008.csv +230 -0
  78. data/spec/lib/duration_spec.rb +50 -0
  79. data/spec/models/race_category_spec.rb +65 -0
  80. data/spec/models/race_club_spec.rb +32 -0
  81. data/spec/models/race_instance_spec.rb +104 -0
  82. data/spec/models/race_performance_spec.rb +7 -0
  83. data/spec/models/race_performance_status_spec.rb +31 -0
  84. data/spec/models/race_spec.rb +39 -0
  85. data/spec/spec.opts +6 -0
  86. data/spec/spec_helper.rb +36 -0
  87. data/vendor/plugins/acts_as_list/README +23 -0
  88. data/vendor/plugins/acts_as_list/init.rb +3 -0
  89. data/vendor/plugins/acts_as_list/lib/active_record/acts/list.rb +256 -0
  90. data/vendor/plugins/acts_as_list/test/list_test.rb +332 -0
  91. metadata +195 -0
@@ -0,0 +1,178 @@
1
+ require 'csv'
2
+
3
+ class RaceInstance < ActiveRecord::Base
4
+
5
+ has_site if respond_to? :has_site
6
+ belongs_to :created_by, :class_name => 'User'
7
+ belongs_to :updated_by, :class_name => 'User'
8
+ belongs_to :race
9
+ has_many :performances, :class_name => 'RacePerformance'
10
+ has_many :competitors, :through => :performances, :source => :race_competitor
11
+ has_many :categories, :through => :performances, :source => :race_category, :uniq => true
12
+
13
+ has_many :finishers, :class_name => 'RacePerformance', :conditions => "race_performances.status_id >= 100"
14
+ has_many :non_finishers, :class_name => 'RacePerformance', :conditions => "race_performances.status_id < 100"
15
+ has_many :successful_competitors, :through => :finishers, :source => :race_competitor
16
+ has_many :unsuccessful_competitors, :through => :non_finishers, :source => :race_competitor
17
+
18
+ object_id_attr :filter, TextFilter
19
+ has_attached_file :results,
20
+ :url => Radiant::Config["race_results.url"] ? Radiant::Config["race_results.url"] : "/:class/:id/:basename:no_original_style.:extension",
21
+ :path => Radiant::Config["race_results.path"] ? Radiant::Config["race_results.path"] : ":rails_root/public/:class/:id/:basename:no_original_style.:extension"
22
+
23
+ after_save :process_results_file
24
+
25
+ validates_presence_of :name, :slug, :race
26
+ validates_uniqueness_of :slug, :scope => :race_id
27
+ validates_length_of :slug, :maximum => 100, :message => '{{count}}-character limit'
28
+ validates_format_of :slug, :with => %r{^([-_.A-Za-z0-9]*|)$}, :message => 'not URL-friendly'
29
+ default_scope :order => 'started_at DESC'
30
+
31
+ named_scope :with_results, {:conditions => "results_file_name IS NOT NULL"}
32
+ named_scope :without_results, {:conditions => "results_file_name IS NULL"}
33
+ named_scope :past, {:conditions => ["started_at <= :when", {:when => Time.now}]}
34
+ named_scope :future, {:conditions => ["started_at > :when", {:when => Time.now}], :order => "started_at ASC"}
35
+
36
+ def to_param
37
+ slug
38
+ end
39
+
40
+ def full_name
41
+ "#{race.name} #{name}"
42
+ end
43
+
44
+ def path
45
+ "#{race.slug}/#{slug}"
46
+ end
47
+
48
+ def nice_start_time
49
+ return unless started_at
50
+ if started_at.min == 0
51
+ started_at.to_datetime.strftime("%-1I%p").downcase
52
+ else
53
+ started_at.to_datetime.strftime("%-1I:%M%p").downcase
54
+ end
55
+ end
56
+
57
+ def nice_start_date
58
+ started_at.to_datetime.strftime("%B %e %Y") if started_at
59
+ end
60
+
61
+ def past?
62
+ started_at <= Time.now
63
+ end
64
+
65
+ def future?
66
+ started_at > Time.now
67
+ end
68
+
69
+ def has_results?
70
+ performances.any?
71
+ end
72
+
73
+ def checkpoints
74
+ # we will need to accommodate races whose checkpoints are different with each instance, but for now:
75
+ race.checkpoints
76
+ end
77
+
78
+ def performance_by(competitor)
79
+
80
+ end
81
+
82
+ def performance_at(position)
83
+
84
+ end
85
+
86
+ def winning_performance(category=nil)
87
+ if category
88
+ category = RaceCategory.find_by_name(category) unless category.is_a? RaceCategory
89
+ performances.completed.eligible_for_category(category).first if category_present?(category)
90
+ else
91
+ performances.completed.first
92
+ end
93
+ end
94
+
95
+ def winner(category=nil)
96
+ if perf = winning_performance(category)
97
+ perf.competitor
98
+ end
99
+ end
100
+
101
+ def top(count=20)
102
+ performances.top(count)
103
+ end
104
+
105
+ def category_top(category, count=5)
106
+ performances.eligible_for_category(category).top(count) if category_present?(category)
107
+ end
108
+
109
+ def category_present?(category)
110
+ categories.include?(category)
111
+ end
112
+
113
+ protected
114
+
115
+ def process_results_file
116
+ if csv_data = read_results_file
117
+ headers = csv_data.shift.map(&:to_s)
118
+ race_data = csv_data.map {|row| row.map {|cell| cell.to_s } }.map {|row| Hash[*headers.zip(row).flatten] } # build AoA and then hash the second level
119
+ RaceInstance.transaction do
120
+ performances.destroy_all
121
+ race_data.each do |line|
122
+ runner = normalize_fields(line)
123
+ next if runner['name'].blank?
124
+
125
+ runner['elapsed_time'] ||= "0"
126
+ club = RaceClub.find_or_create_by_any_name(runner.delete('club')) unless runner['club'].blank?
127
+ competitor = RaceCompetitor.find_or_create_by_name_and_club(runner.delete('name'), club)
128
+ category = RaceCategory.find_or_create_by_normalized_name(runner.delete('category'))
129
+ competitor.update_attribute(:gender, category.gender) unless competitor.gender
130
+ status = RacePerformanceStatus.from_time(runner['elapsed_time'])
131
+ performance = self.performances.create!({
132
+ :position => runner.delete('position'),
133
+ :competitor => competitor,
134
+ :category => category,
135
+ :elapsed_time => runner.delete('elapsed_time'),
136
+ :status_id => status.id
137
+ })
138
+
139
+ headers.each do |key|
140
+ value = runner[normalize(key)]
141
+ if value && value.looks_like_duration? && cp = race.checkpoints.find_by_name(key)
142
+ cp.times.create(:race_performance_id => performance.id, :elapsed_time => value)
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ def read_results_file
151
+ CSV.read(results.path)
152
+ rescue
153
+ nil
154
+ end
155
+
156
+ @@field_aliases = {
157
+ 'cat' => 'category',
158
+ 'time' => 'elapsed_time',
159
+ 'finish' => 'elapsed_time',
160
+ 'pos' => 'position'
161
+ }
162
+
163
+ def normalize_fields(line)
164
+ line.keys.each do |key|
165
+ line[normalize(key)] = line.delete(key)
166
+ end
167
+ line
168
+ end
169
+
170
+ def normalize(value)
171
+ squashed = value.strip.downcase
172
+ squashed.gsub!(/\s+/, "_")
173
+ squashed.gsub!(/\W+/, "")
174
+ @@field_aliases[squashed] || squashed
175
+ end
176
+
177
+ end
178
+
@@ -0,0 +1,69 @@
1
+ class RacePage < Page
2
+ include WillPaginate::ViewHelpers
3
+
4
+ description %{ Takes race and race instance names in child position or as parameters and populates the necessary race objects. }
5
+
6
+ attr_accessor :race, :race_instance
7
+
8
+ def self.sphinx_indexes
9
+ []
10
+ end
11
+
12
+ def cache?
13
+ true
14
+ end
15
+
16
+ def find_by_url(url, live = true, clean = false)
17
+ url = clean_url(url) if clean
18
+ my_url = self.url
19
+ return false unless url =~ /^#{Regexp.quote(my_url)}(.*)/
20
+ race_slug, instance_slug, subset, id = $1.split('/')
21
+ if race_slug && @race = Race.find_by_slug(race_slug)
22
+ if instance_slug && @race_instance = @race.instances.find_by_slug(instance_slug)
23
+ if subset && id && %w{club cat p}.include?(subset)
24
+ case subset
25
+ when "club"
26
+ @club = RaceClub.find(id)
27
+ @template = 'race_clubs/show'
28
+ when "cat"
29
+ @category = RaceCategory.find(id)
30
+ @template = 'race_categories/show'
31
+ when 'p'
32
+ @performance = RacePerformance.find(id)
33
+ @template = 'race_performances/show'
34
+ end
35
+ else
36
+ @template = 'race_instances/show'
37
+ end
38
+ else
39
+ @template = 'races/show'
40
+ end
41
+ end
42
+ self
43
+ end
44
+
45
+ def pagination
46
+ p = request.params[:page]
47
+ p = 1 if p.blank? || p == 0
48
+ return {
49
+ :page => request.params[:page] || 1,
50
+ :per_page => Radiant::Config['race_results.per_page'] || 100
51
+ }
52
+ end
53
+
54
+ def render
55
+
56
+ end
57
+
58
+ def title
59
+ if race_instance
60
+ race_instance.full_name
61
+ elsif race
62
+ race.name
63
+ else
64
+ read_attribute(:title)
65
+ end
66
+ end
67
+
68
+
69
+ end
@@ -0,0 +1,175 @@
1
+ class RacePerformance < ActiveRecord::Base
2
+
3
+ has_site if respond_to? :has_site
4
+ belongs_to :created_by, :class_name => 'User'
5
+ belongs_to :updated_by, :class_name => 'User'
6
+ belongs_to :race_instance
7
+ belongs_to :race_competitor
8
+ belongs_to :race_category
9
+ has_many :checkpoint_times, :class_name => 'RaceCheckpointTime'
10
+
11
+ delegate :name, :reader, :club, :to => :competitor
12
+
13
+ before_validation_on_create :times_from_checkpoints
14
+ validates_presence_of :race_competitor_id, :race_instance_id
15
+
16
+ default_scope :order => :elapsed_time
17
+
18
+ # has_many through doesn't work with a foreign_key setting, so we do the readable names here instead
19
+ alias :competitor :race_competitor
20
+ alias :competitor= :race_competitor=
21
+ alias :category :race_category
22
+ alias :category= :race_category=
23
+
24
+ named_scope :top, lambda {|count|
25
+ {
26
+ :order => 'elapsed_time DESC',
27
+ :limit => count
28
+ }
29
+ }
30
+
31
+ named_scope :by, lambda {|race_competitor|
32
+ {
33
+ :conditions => ['race_competitor_id = ?', race_competitor.id]
34
+ }
35
+ }
36
+
37
+ named_scope :in, lambda {|race_instance|
38
+ {
39
+ :conditions => ['race_instance_id = ?', race_instance.id]
40
+ }
41
+ }
42
+
43
+ named_scope :in_race, lambda {|race|
44
+ {
45
+ :conditions => ['race_instance_id in (?)', race.instances.map(&:id).join(',')]
46
+ }
47
+ }
48
+
49
+ named_scope :in_category, lambda {|category|
50
+ category = RaceCategory.find_by_name(category) unless category.is_a? RaceCategory
51
+ {
52
+ :conditions => ['race_category_id = ?', category.id]
53
+ }
54
+ }
55
+
56
+ named_scope :eligible_for_category, lambda {|category|
57
+ category = RaceCategory.find_by_name(category) unless category.is_a? RaceCategory
58
+ eligible_categories = RaceCategory.within(category)
59
+ {
60
+ :conditions => ["race_category_id in (#{eligible_categories.map{'?'}.join(',')})", *eligible_categories.map(&:id)]
61
+ }
62
+ }
63
+
64
+ named_scope :by_members_of, lambda { |club|
65
+ club = RaceClub.find_by_name(club) unless club.is_a? RaceClub
66
+ {
67
+ :select => 'race_performances.*',
68
+ :joins => "LEFT JOIN race_competitors AS competitors ON race_performances.race_competitor_id = competitors.id",
69
+ :conditions => ["competitors.race_club_id = ?", club.id]
70
+ }
71
+ }
72
+
73
+ named_scope :quicker_than, lambda { |seconds|
74
+ {
75
+ :conditions => ["elapsed_time IS NOT NULL AND elapsed_time > 0 AND elapsed_time < ?", seconds]
76
+ }
77
+ }
78
+
79
+ named_scope :completed, {
80
+ :conditions => 'status_id >= 100'
81
+ }
82
+
83
+ named_scope :incomplete, {
84
+ :conditions => 'status_id < 100'
85
+ }
86
+
87
+ def start
88
+ started_at || race_instance.started_at || checkpoint_times.first.elapsed_time
89
+ end
90
+
91
+ def finish
92
+ finished_at || start + elapsed_time
93
+ end
94
+
95
+ def position
96
+ read_attribute(:position) || calculate_position
97
+ end
98
+
99
+ def calculate_position
100
+ update_attribute(:position, race_instance.performances.quicker_than(time_in_seconds).count + 1)
101
+ position
102
+ end
103
+
104
+ def prizes
105
+ read_attribute(:prizes) || calculate_prizes
106
+ end
107
+
108
+ def calculate_prizes
109
+ prizelist = []
110
+ positions.each do |cat,pos|
111
+ prizelist << "#{pos.ordinalize} #{cat}" if pos <= 3
112
+ end
113
+ update_attribute(:prizes, prizelist.join(', '))
114
+ prizes
115
+ end
116
+
117
+ def positions
118
+ race_instance.categories.containing(category).inject({}) { |h, cat| h.merge( { cat.name => position_in(cat) } ) }
119
+ end
120
+
121
+ def position_in(cat)
122
+ race_instance.performances.eligible_for_category(cat).quicker_than(time_in_seconds).count + 1
123
+ end
124
+
125
+ def time_in_seconds
126
+ read_attribute(:elapsed_time)
127
+ end
128
+
129
+ def elapsed_time
130
+ if s = time_in_seconds
131
+ s.to_timecode
132
+ else
133
+ ""
134
+ end
135
+ end
136
+
137
+ def elapsed_time=(time)
138
+ write_attribute(:elapsed_time, time.seconds) if time # numbers will pass through unchanged. strings will be timecode-parsed
139
+ end
140
+
141
+ def time_at(checkpoint)
142
+ checkpoint_times.time_at(checkpoint).first
143
+ end
144
+
145
+ def status
146
+ RacePerformanceStatus.find(self.status_id)
147
+ end
148
+ def status=(value)
149
+ self.status_id = value.id
150
+ end
151
+ def finished?
152
+ status == RacePerformanceStatus["Finished"]
153
+ end
154
+
155
+
156
+
157
+ def prized?
158
+ true if prizes.any?
159
+ end
160
+
161
+ protected
162
+
163
+ def times_from_checkpoints
164
+ # self.started_at ||= checkpoint_times.first.elapsed_time if checkpoint_times.any? && !race_instance.started_at
165
+ # self.finished_at ||= checkpoint_times.last.elapsed_time if checkpoint_times.any? && !elapsed_time
166
+ # self.elapsed_time ||= finished_at - started_at
167
+ end
168
+
169
+ def recalculate_positions
170
+ position(true)
171
+ prizes(true)
172
+ end
173
+
174
+ end
175
+
@@ -0,0 +1,58 @@
1
+ class RacePerformanceStatus
2
+ attr_accessor :id, :name, :aliases
3
+
4
+ def initialize(options = {})
5
+ options = options.symbolize_keys
6
+ @id, @name = options[:id], options[:name]
7
+ @aliases = (options[:aliases] || []).collect {|name| name.to_s.downcase.intern}
8
+ end
9
+
10
+ def symbol
11
+ @name.to_s.downcase.intern
12
+ end
13
+
14
+ def has_alias?(value)
15
+ @aliases.include?(value.to_s.downcase.intern)
16
+ end
17
+
18
+ def to_s
19
+ @name
20
+ end
21
+
22
+ def to_i
23
+ @id
24
+ end
25
+
26
+ def self.[](value="")
27
+ value = "?" if value.blank? || value == 0
28
+ @@statuses.find { |status| status.symbol == value.to_s.downcase.intern || status.has_alias?(value) }
29
+ end
30
+
31
+ def self.find(id=0)
32
+ @@statuses.find { |status| status.id.to_s == id.to_s }
33
+ end
34
+
35
+ def self.find_all
36
+ @@statuses.dup
37
+ end
38
+
39
+ def self.from_time(time=nil)
40
+ time ||= ""
41
+ if time.seconds > 0 # String.seconds returns 0 for a string that doesn't parse. See DurationExtensions for method.
42
+ self["Finished"]
43
+ elsif self[time]
44
+ self[time]
45
+ else
46
+ self["?"]
47
+ end
48
+ end
49
+
50
+ @@statuses = [
51
+ RacePerformanceStatus.new(:id => 0, :name => '?', :aliases => ['unknown'] ),
52
+ RacePerformanceStatus.new(:id => 10, :name => 'Ret', :aliases => ['retired', 'r']),
53
+ RacePerformanceStatus.new(:id => 20, :name => 'DNF', :aliases => ['did not finish', 'x']),
54
+ RacePerformanceStatus.new(:id => 30, :name => 'TO', :aliases => ['timed out', 't']),
55
+ RacePerformanceStatus.new(:id => 50, :name => 'Dsq', :aliases => ['disqualified', 'disq', 'd']),
56
+ RacePerformanceStatus.new(:id => 100, :name => 'Finished')
57
+ ]
58
+ end
@@ -0,0 +1,27 @@
1
+ class RaceRecord < ActiveRecord::Base
2
+
3
+ has_site if respond_to? :has_site
4
+ belongs_to :created_by, :class_name => 'User'
5
+ belongs_to :updated_by, :class_name => 'User'
6
+ belongs_to :race
7
+ belongs_to :race_competitor
8
+ belongs_to :race_category
9
+
10
+ # these associations are only populated in the relatively rare case where the record is part of one of our result sets
11
+ belongs_to :race_instance
12
+ belongs_to :race_performance
13
+
14
+ def elapsed_time
15
+ if s = read_attribute(:elapsed_time)
16
+ s.to_timecode
17
+ else
18
+ ""
19
+ end
20
+ end
21
+
22
+ def elapsed_time=(time)
23
+ write_attribute(:elapsed_time, time.seconds) if time # numbers will pass through unchanged. strings will be timecode-parsed
24
+ end
25
+
26
+ end
27
+
@@ -0,0 +1,19 @@
1
+ - with_value ||= false
2
+ - cssclass = f.object.new_record? ? 'adding subform' : 'subform'
3
+ %div{:class => cssclass}
4
+ .name
5
+ = f.label :name, "Checkpoint Name"
6
+ = f.text_field :name, :class => 'textbox'
7
+ .location
8
+ = f.label :location, "Location"
9
+ = f.text_field :location, :class => 'textbox'
10
+ .value
11
+ - if with_value
12
+ = f.label :value, "Value"
13
+ = f.text_field :value, :class => 'textbox'
14
+
15
+ - if f.object.new_record?
16
+ = link_to_function "cancel", "this.up('.subform').remove()"
17
+ - else
18
+ = f.check_box '_delete', { :onclick=>"this.checked ? this.up('.subform').addClassName('deleting') : this.up('.subform').removeClassName('deleting')" , :class => 'record_delete'}
19
+ = f.label '_delete', 'delete', :class => 'quiet'
@@ -0,0 +1,10 @@
1
+ - cssclass = f.object.new_record? ? 'adding subform' : 'subform'
2
+ %p{:class => cssclass}
3
+ = f.label :name, "AKA:"
4
+ = f.text_field :name, :class => 'alias_name'
5
+
6
+ - if f.object.new_record?
7
+ = link_to_function "cancel", "this.up('.subform').remove()"
8
+ - else
9
+ = f.check_box '_delete', { :onclick=>"this.checked ? this.up('.subform').addClassName('deleting') : this.up('.subform').removeClassName('deleting')" , :class => 'alias_delete'}
10
+ = f.label '_delete', 'delete', :class => 'quiet'
@@ -0,0 +1,19 @@
1
+ %tr.node.level-1
2
+ - render_region :tbody do |tbody|
3
+ - tbody.title_cell do
4
+ %td.club_name
5
+ %p
6
+ = link_to club.name, edit_admin_race_club_url(club)
7
+
8
+ - tbody.members_cell do
9
+ %td.club_members
10
+ - if club.competitors.any?
11
+ = club.competitors.count
12
+ - else
13
+ \-
14
+
15
+ - tbody.aliases_cell do
16
+ %td.club_aliases
17
+ - if club.other_names.any?
18
+ aka
19
+ = club.other_names.map(&:name).join(', ')
@@ -0,0 +1,21 @@
1
+ = render_region :form_top
2
+
3
+ - if @race_club.errors.any?
4
+ %p.haserror
5
+ Sorry: there were problems:
6
+ %br
7
+ = @race_club.errors.full_messages
8
+
9
+ - render_region :form do |form|
10
+ - form.edit_name do
11
+ %p.title
12
+ = f.label :name, "Displayed Name"
13
+ = f.text_field :name, :class => 'textbox', :maxlength => 100
14
+
15
+ - form.edit_aliases do
16
+ %h2
17
+ Aliases and abbreviations
18
+ %div#other_names
19
+ = f.fields_for :other_names do |af|
20
+ = render :partial => 'admin/race_club_aliases/race_club_alias', :locals => {:f => af}
21
+ = link_to_new_nested_form "Add an alias", f, :other_names, :partial => 'admin/race_club_aliases/race_club_alias'
@@ -0,0 +1,20 @@
1
+ - include_stylesheet 'admin/races'
2
+ - include_javascript 'admin/races'
3
+
4
+ = render_region :top
5
+
6
+ - render_region :main do |main|
7
+ - main.edit_header do
8
+ %h1
9
+ Edit Club
10
+
11
+ - main.edit_form do
12
+ - form_for :race_club, @race_club, :url => admin_race_club_path(@race_club), :html => { :method => "put" } do |f|
13
+ .form-area
14
+ = render :partial => "form", :locals => { :f => f }
15
+
16
+ %p.buttons
17
+ = save_model_button(@race_club)
18
+ = save_model_and_continue_editing_button(@race_club)
19
+ or
20
+ = link_to "Cancel", admin_race_clubs_path
@@ -0,0 +1,27 @@
1
+ - include_stylesheet 'admin/races'
2
+
3
+ #clubs_table.outset
4
+ %table#race_clubs.index{:cellspacing=>"0", :border=>"0", :cellpadding=>"0"}
5
+ %thead
6
+ %tr
7
+ - render_region :thead do |thead|
8
+ - thead.title_header do
9
+ %th.club
10
+ Name
11
+ - thead.members_header do
12
+ %th.members
13
+ Members
14
+ - thead.aliases_header do
15
+ %th.members
16
+ Aliases
17
+
18
+ %tbody
19
+ - @race_clubs.each do |club|
20
+ = render :partial => 'club', :object => club
21
+
22
+ - render_region :bottom do |bottom|
23
+ - bottom.buttons do
24
+ #actions
25
+ = will_paginate @race_clubs
26
+ %ul
27
+ %li= link_to image('plus') + " " + "new club", new_admin_race_club_url
@@ -0,0 +1,14 @@
1
+ %tr.node.level-1
2
+ - render_region :tbody do |tbody|
3
+ - tbody.title_cell do
4
+ %td.competitor_name
5
+ %p
6
+ = link_to competitor.name, edit_admin_race_competitor_url(competitor)
7
+
8
+ - tbody.club_cell do
9
+ %td.competitor_club
10
+ = competitor.club ? competitor.club.name : "unattached"
11
+
12
+ - tbody.races_cell do
13
+ %td.competitor_races
14
+ = competitor.performances.count
@@ -0,0 +1,21 @@
1
+ = render_region :form_top
2
+
3
+ - if @race_club.errors.any?
4
+ %p.haserror
5
+ Sorry: there were problems:
6
+ %br
7
+ = @race_club.errors.full_messages
8
+
9
+ - render_region :form do |form|
10
+ - form.edit_name do
11
+ %p.title
12
+ = f.label :name, "Displayed Name"
13
+ = f.text_field :name, :class => 'textbox', :maxlength => 100
14
+
15
+ - form.edit_aliases do
16
+ %h2
17
+ Aliases and abbreviations
18
+ %div#other_names
19
+ = f.fields_for :other_names do |af|
20
+ = render :partial => 'admin/race_club_aliases/race_club_alias', :locals => {:f => af}
21
+ = link_to_new_nested_form "Add an alias", f, :other_names, :partial => 'admin/race_club_aliases/race_club_alias'
@@ -0,0 +1,20 @@
1
+ - include_stylesheet 'admin/races'
2
+ - include_javascript 'admin/races'
3
+
4
+ = render_region :top
5
+
6
+ - render_region :main do |main|
7
+ - main.edit_header do
8
+ %h1
9
+ Edit Club
10
+
11
+ - main.edit_form do
12
+ - form_for :race_club, @race_club, :url => admin_race_club_path(@race_club), :html => { :method => "put" } do |f|
13
+ .form-area
14
+ = render :partial => "form", :locals => { :f => f }
15
+
16
+ %p.buttons
17
+ = save_model_button(@race_club)
18
+ = save_model_and_continue_editing_button(@race_club)
19
+ or
20
+ = link_to "Cancel", admin_race_clubs_path