@@ -3,7 +3,7 @@ class ContestsController < ApplicationController
|
||||
include ContestantsConcern
|
||||
|
||||
before_action :set_contest, only: %i[ destroy show ]
|
||||
before_action :set_settings_contest, only: %i[ settings_general_edit settings_general_update settings_public_edit settings_public_update settings_onsite_edit settings_onsite_update settings_online_edit settings_online_update settings_categories_edit ]
|
||||
before_action :set_settings_contest, only: %i[ stopwatch stopwatch_continue stopwatch_pause stopwatch_reset stopwatch_start settings_general_edit settings_general_update settings_public_edit settings_public_update settings_onsite_edit settings_onsite_update settings_online_edit settings_online_update settings_categories_edit ]
|
||||
before_action :offline_setup, only: %i[ offline_new offline_create offline_edit offline_update offline_completed ]
|
||||
skip_before_action :require_authentication, only: %i[ scoreboard offline_new offline_create offline_edit offline_update offline_completed ]
|
||||
|
||||
@@ -80,6 +80,47 @@ class ContestsController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
def stopwatch
|
||||
authorize @contest
|
||||
end
|
||||
|
||||
def stopwatch_continue
|
||||
authorize @contest
|
||||
|
||||
pause_duration = Time.now() - @contest.pause_time
|
||||
@contest.start_time = @contest.start_time + pause_duration
|
||||
@contest.pause_time = nil
|
||||
@contest.save
|
||||
redirect_to "/contests/#{@contest.id}/stopwatch"
|
||||
end
|
||||
|
||||
def stopwatch_pause
|
||||
authorize @contest
|
||||
authorize @contest
|
||||
|
||||
@contest.pause_time = Time.now()
|
||||
@contest.save
|
||||
redirect_to "/contests/#{@contest.id}/stopwatch"
|
||||
end
|
||||
|
||||
def stopwatch_reset
|
||||
authorize @contest
|
||||
|
||||
@contest.start_time = nil
|
||||
@contest.pause_time = nil
|
||||
@contest.save
|
||||
redirect_to "/contests/#{@contest.id}/stopwatch"
|
||||
end
|
||||
|
||||
def stopwatch_start
|
||||
authorize @contest
|
||||
|
||||
@contest.start_time = Time.now()
|
||||
@contest.pause_time = nil
|
||||
@contest.save
|
||||
redirect_to "/contests/#{@contest.id}/stopwatch"
|
||||
end
|
||||
|
||||
def new
|
||||
authorize :contest
|
||||
|
||||
@@ -241,7 +282,7 @@ class ContestsController < ApplicationController
|
||||
end
|
||||
|
||||
def settings_public_params
|
||||
params.expect(contest: [ :public, :ranking_mode ])
|
||||
params.expect(contest: [ :public, :ranking_mode, :show_stopwatch ])
|
||||
end
|
||||
|
||||
def settings_onsite_params
|
||||
|
||||
@@ -10,9 +10,12 @@
|
||||
# lang :string default("en")
|
||||
# name :string
|
||||
# offline_form :boolean default(FALSE)
|
||||
# pause_time :datetime
|
||||
# public :boolean default(FALSE)
|
||||
# ranking_mode :string
|
||||
# show_stopwatch :boolean
|
||||
# slug :string
|
||||
# start_time :datetime
|
||||
# team :boolean default(FALSE)
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
|
||||
@@ -75,6 +75,26 @@ class ContestPolicy < ApplicationPolicy
|
||||
edit?
|
||||
end
|
||||
|
||||
def stopwatch?
|
||||
edit?
|
||||
end
|
||||
|
||||
def stopwatch_continue?
|
||||
edit?
|
||||
end
|
||||
|
||||
def stopwatch_pause?
|
||||
edit?
|
||||
end
|
||||
|
||||
def stopwatch_reset?
|
||||
edit?
|
||||
end
|
||||
|
||||
def stopwatch_start?
|
||||
edit?
|
||||
end
|
||||
|
||||
def finalize_import?
|
||||
owner_or_admin
|
||||
end
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
li.nav-item
|
||||
a.nav-link class=active_page(contest_puzzles_path(@contest)) href=contest_puzzles_path(@contest)
|
||||
= t("puzzles.plural").capitalize
|
||||
li.nav-item
|
||||
a.nav-link class=active_page("/contests/#{@contest.id}/stopwatch") href="/contests/#{@contest.id}/stopwatch"
|
||||
= t("contests.nav.stopwatch").capitalize
|
||||
li.nav-item
|
||||
a.nav-link class=active_page(contest_messages_path(@contest)) href=contest_messages_path(@contest)
|
||||
= t("messages.plural").capitalize
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
thead
|
||||
tr
|
||||
th
|
||||
- if @contest.show_stopwatch
|
||||
.stopwatch id="display-time" style="font-size: 60px; font-weight: 400;"
|
||||
= render "stopwatch_js"
|
||||
th
|
||||
th
|
||||
th
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.row
|
||||
.mt-3.col-6.d-flex.flex-column style="height: calc(100vh - 250px)"
|
||||
.mt-3.col-6.d-flex.flex-column style="height: calc(100vh - 310px)"
|
||||
.d-flex.flex-column style="overflow-y: auto"
|
||||
table.table.table-striped.table-hover
|
||||
thead
|
||||
|
||||
@@ -3,14 +3,14 @@ css:
|
||||
|
||||
.row
|
||||
- if @puzzles.size > 0
|
||||
.d-flex.flex-column.justify-content-center.mb-5
|
||||
.d-flex.flex-column.justify-content-center.mb-2
|
||||
= image_tag(@puzzles[0].image, style: "max-height: 200px; object-fit: contain") if @puzzles[0].image.attached?
|
||||
.mt-2.fs-6 style="text-align: center"
|
||||
=> "#{@puzzles[0].name} -"
|
||||
= "#{@puzzles[0].brand} #{@puzzles[0].pieces}p"
|
||||
|
||||
.row
|
||||
.mt-3.d-flex.flex-column style="height: calc(100vh - 250px)"
|
||||
.mt-3.d-flex.flex-column
|
||||
.d-flex.flex-column style="overflow-y: auto"
|
||||
table.table.table-striped.table-hover
|
||||
thead
|
||||
|
||||
22
app/views/contests/_stopwatch_js.html.slim
Normal file
22
app/views/contests/_stopwatch_js.html.slim
Normal file
@@ -0,0 +1,22 @@
|
||||
javascript:
|
||||
startTime = #{@contest.start_time.present? ? @contest.start_time.to_i : "null"};
|
||||
pauseTime = #{@contest.pause_time.present? ? @contest.pause_time.to_i : "null"};
|
||||
function updateTime() {
|
||||
const displayTimeEl = document.getElementById('display-time');
|
||||
if (displayTimeEl) {
|
||||
if (startTime) {
|
||||
let s = Math.floor((Date.now() - 1000 * startTime) / 1000);
|
||||
if (pauseTime) s = Math.floor(pauseTime - startTime);
|
||||
let ss = s % 60;
|
||||
let mm = Math.floor(s / 60) % 60;
|
||||
let hh = Math.floor(s / 3600);
|
||||
displayTimeEl.innerHTML = `${hh < 10 ? `0${hh}` : hh}:${mm < 10 ? `0${mm}` : mm}:${ss < 10 ? `0${ss}` : ss}`;
|
||||
setTimeout(updateTime, 1000);
|
||||
} else {
|
||||
displayTimeEl.innerHTML = '00:00:00';
|
||||
}
|
||||
} else {
|
||||
setTimeout(updateTime, 20);
|
||||
}
|
||||
}
|
||||
setTimeout(updateTime, 1);
|
||||
@@ -3,12 +3,16 @@ css:
|
||||
.mobile-single { display: block !important; }
|
||||
.desktop-single { display: none; }
|
||||
#scoreboard-switches { display: none; }
|
||||
.stopwatch { font-size: 50px !important; }
|
||||
}
|
||||
|
||||
- if @contest.puzzles.size < 2
|
||||
= render "selectors"
|
||||
|
||||
turbo-frame id="scoreboard"
|
||||
- if @contest.show_stopwatch
|
||||
.stopwatch id="display-time" style="font-size: 60px; font-weight: 400; margin-bottom: 0; text-align: center;"
|
||||
= render "stopwatch_js"
|
||||
a.btn.btn-primary href="" id="refresh-button" style="display: none;"
|
||||
.mobile-single style="display: none;"
|
||||
= render "scoreboard_mobile_single"
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
.form-check.form-switch
|
||||
= form.check_box :public, class: "form-check-input"
|
||||
= form.label :public
|
||||
.row.mt-2
|
||||
.col
|
||||
.form-check.form-switch
|
||||
= form.check_box :show_stopwatch, class: "form-check-input"
|
||||
= form.label :show_stopwatch
|
||||
.row.mt-3
|
||||
.col
|
||||
.form-floating
|
||||
|
||||
16
app/views/contests/stopwatch.html.slim
Normal file
16
app/views/contests/stopwatch.html.slim
Normal file
@@ -0,0 +1,16 @@
|
||||
.row
|
||||
.col
|
||||
.alert.alert-primary
|
||||
= t("contests.stopwatch.info")
|
||||
h1.mt-3 id="display-time" style="font-size: 80px;"
|
||||
= render "stopwatch_js"
|
||||
.row.mt-3
|
||||
.col.d-flex
|
||||
- if !@contest.start_time.present?
|
||||
= button_to t("helpers.buttons.stopwatch_start"), "/contests/#{@contest.id}/stopwatch_start", method: :post, class: "btn btn-primary"
|
||||
- if @contest.pause_time.present?
|
||||
= button_to t("helpers.buttons.stopwatch_continue"), "/contests/#{@contest.id}/stopwatch_continue", method: :post, class: "btn btn-primary"
|
||||
- if @contest.start_time.present? && !@contest.pause_time.present?
|
||||
= button_to t("helpers.buttons.stopwatch_pause"), "/contests/#{@contest.id}/stopwatch_pause", method: :post, class: "btn btn-primary"
|
||||
- if @contest.start_time.present?
|
||||
= button_to t("helpers.buttons.stopwatch_reset"), "/contests/#{@contest.id}/stopwatch_reset", method: :post, class: "ms-3 btn btn-warning"
|
||||
Reference in New Issue
Block a user