return get_row_attribute_id(table, i, 'system');
}
+/* Get leg order; for set-course races. */
+function get_course_order(table, i) {
+ return get_row_attribute_id(table, i, 'order');
+}
+
/* Pad string. */
function zero_pad(n) {
if (n < 10) return '0' + String(n);
for (var i = first_row(table); valid_row(table, i, 1); i++) {
if (start_line(table, i) || finish_line(table, i)) continue;
if (start_line(table, i + 1) || finish_line(table, i + 1)) continue;
+ if (get_course_order(table, i)) continue;
+ if (get_course_order(table, i + 1)) continue;
var above = get_cell_input(i, j).value || 'zzz';
var below = get_cell_input(i + 1, j).value || 'zzz';
if (above == below) continue;
return true;
}
+ function show_leg($station, $start_finish, $station_id, $system_id, $order, $n) {
+ $td_class = $start_finish ? " class=\"$start_finish\"" : '';
+ echo "<tr>\n";
+ $classes = array("station$station_id", "system$system_id");
+ if (is_int($order)) $classes[] = "order$order";
+ $class_list = implode(' ', $classes);
+ echo "<td$td_class><p class=\"$class_list\">$station</p></td>\n";
+ echo "<td id=\"distance$n\"><p></p></td>\n";
+ echo "</tr>\n";
+ }
+
function sort_legs($a, $b) {
list($a_flags, $a_station_id, $a_system_id, $a_order) = $a;
list($b_flags, $b_station_id, $b_system_id, $b_order) = $b;
echo "<th>Leg</th>\n";
$n = 0;
foreach ($legs as $station => $attributes) {
- list($flags, $id, $system_id) = $attributes;
+ list($flags, $station_id, $system_id, $order) = $attributes;
/* Skip finish line. */
if ($flags & Course::FinishFlag() && ! ($flags & Course::StartFlag())) continue;
- $n++;
- $label = $station;
- $class = ($flags & Course::StartFlag()) ? ' class="start_line"' : '';
- echo "<tr>\n";
- echo "<td$class><p class=\"station$id system$system_id\">$station</p></td>\n";
- echo "<td id=\"distance$n\"><p></p></td>\n";
- echo "</tr>\n";
+ if ($flags & Course::StartFlag()) {
+ $class = 'start_line';
+ $order = 0;
+ }
+ else $class = '';
+ show_leg($station, $class, $station_id, $system_id, $order, ++$n);
}
foreach ($legs as $station => $attributes) {
- list($flags, $id, $system_id) = $attributes;
+ list($flags, $station_id, $system_id, $order) = $attributes;
if (! ($flags & Course::FinishFlag())) continue;
- $class = ' class="finish_line"';
- echo "<tr>\n";
- echo "<td$class><p class=\"station$id system$system_id\">$station</p></td>\n";
- echo "<td id=\"distance$n\"><p></p></td>\n";
- echo "</tr>\n";
+ /* Last leg. */
+ $order = 0;
+ show_leg($station, 'finish_line', $station_id, $system_id, $order, ++$n);
}
echo "<tr>\n";
echo "<td>";
if (do_race($name, $allotted_time, $posted)) return true;
}
+ echo "<div id=\"waypoints\">\n";
form();
echo "<table>\n";
foreach ($stations as $station) {
hidden('allotted_time', $allotted_time);
submit('add_race', 'Submit race');
end_form();
+ echo "</div>\n";
return false;
}
/* Check start and finish lines are set. */
function validate() {
- var stations = 0;
var flags = 0;
- for (input of document.getElementsByClassName('station')) {
- var value = parseInt(input.value);
+ var stations = [];
+ for (select of document.getElementsByClassName('station')) {
+ var value = parseInt(select.value);
var flag = value & mandatory_flags;
- if (value && ! flag) stations++;
+ if (value && ! flag) stations.push(select);
flags |= flag;
}
var valid = (flags == mandatory_flags);
if (valid) {
/* Either all stations must be ordered or none. */
- var ordered = 0;
+ var ordered = {};
for (input of document.getElementsByTagName('input')) {
if (! input.name.match(/^station\d+order$/)) continue;
- if (input.value) ordered++;
+ if (input.value) {
+ ordered[input.value] = input;
+ /* Stations not in the course can't be ordered. */
+ var select = document.getElementById(input.name.replace(/order$/, ''));
+ if (select && ! parseInt(select.value)) input.setCustomValidity("Not part of race");
+ }
+ else input.setCustomValidity("");
+ }
+ var keys = Object.keys(ordered);
+ if (keys.length) {
+ /* If one station is ordered they all must be. */
+ for (select of stations) {
+ var input = document.getElementById(select.name + "order");
+ if (input && ! input.value) input.setCustomValidity("Missing order");
+ }
+ valid = false;
+ /* Ordering must be contiguous from 1. */
+ for (var i = 1; i <= stations.length; i++) {
+ if (ordered[i]) continue;
+ for (var j = 0; j < keys.length; j++) {
+ if (parseInt(keys[j]) <= i) continue;
+ var input = ordered[keys[j]];
+ input.setCustomValidity("Out of order");
+ valid = false;
+ }
+ break;
+ }
}
- if (ordered > 0 && ordered < stations) valid = false;
}
var submits = document.getElementsByName('add_race');
if (input == event.target) continue;
input.value &= ~(event.target.value & mandatory_flags);
}
- if (event.target.value & mandatory_flags) {
+ var flag = parseInt(event.target.value);
+ if (flag & mandatory_flags || ! flag) {
/* Clear order. */
var input = document.getElementById(event.target.name + 'order');
if (input) input.value = '';
function changed_order(event) {
var order = parseInt(event.target.value);
if (order) {
+ var select = document.getElementById(event.target.name.replace(/order$/, ''));
+ if (select) select.value = 1;
for (input of document.getElementsByTagName('input')) {
if (input == event.target) continue;
if (! input.name.match(/^station\d+order$/)) continue;
}
var waypoints = document.getElementsByClassName('station');
if (waypoints.length) {
+ var div = document.getElementById('waypoints');
+ if (div && div.offsetHeight > window.innerHeight * 0.9) div.style.height = '80%';
for (input of waypoints) {
+ input.id = input.name;
input.addEventListener('change', changed_waypoint, true);
input.addEventListener('focusout', changed_waypoint, true);
}
#laps table { background-color: rgba(20, 50, 100, 0.2); }
#laps th, #laps td { padding-left: 1em; }
#laps label:nth-child(even) { padding-top: 0.5em; padding-bottom: 0.5em; background-color: rgba(128, 128, 128, 0.1); }
+#laps p[class*='order']:after { background-image: url(images/locked.gif); background-position: left center; position: relative; padding-left: 16px; background-repeat: no-repeat; content: ""; }
th { text-align: left; }
th:nth-child(n+2),td:nth-child(n+2) { text-align: center; }
#stats td:nth-child(n+1) { text-align: left; }
.classification .bbcode { display: none; background-color: rgba(0, 0, 0, 0.1); }
#systems { overflow-x: auto; }
#stations { overflow-x: auto; }
+#waypoints { overflow-x: auto; }