Handle races which can be flown in any order.
authorCMDR furrycat <elite@furrycat.net>
Tue, 7 Feb 2017 14:09:33 +0000 (09:09 -0500)
committerCMDR furrycat <elite@furrycat.net>
Tue, 7 Feb 2017 14:13:46 +0000 (09:13 -0500)
If the "reverse" field is set the start and finish stations can be swapped when
adding an entry.

entry.js
images/reverse.png [new file with mode: 0644]
lib/entry.php
lib/race.php
propel/schema.xml
style.css

index 86cc697..f18ac27 100644 (file)
--- a/entry.js
+++ b/entry.js
@@ -813,6 +813,17 @@ function changed_joker(event) {
   validate(get_table());
 }
 
+/* Callback when we swap start and finish. */
+function reversed(event) {
+  var input = event.target;
+  var table = get_table();
+  /* Swap heading and rows. */
+  for (var j = 0; j <= last_column(table); j++) {
+    if (j && ! valid_column(table, j)) continue;
+    swap_cells(table, first_row(table), j, last_row(table), j, true);
+  }
+}
+
 /* Create a new input element. */
 function checkpoint(id) {
   var date = elite_date();
@@ -965,6 +976,9 @@ function loaded() {
   if (typeof optional_waypoints == 'number' && optional_waypoints) waypoints = optional_waypoints;
   else waypoints = total_waypoints;
   omitted_optional = total_waypoints - waypoints - 1;
+  for (var input of document.getElementsByClassName('reverse')) {
+    input.addEventListener('dblclick', reversed, true);
+  }
   validate(table);
   do_plot(table, document.getElementById('plot'));
   var stats = document.getElementById('stats').getElementsByTagName('table')[0];
diff --git a/images/reverse.png b/images/reverse.png
new file mode 100644 (file)
index 0000000..d16778f
Binary files /dev/null and b/images/reverse.png differ
index e41abcd..761f805 100644 (file)
     return false;
   }
 
-  function show_leg($station, $start_finish, $station_id, $system_id, $order, $n) {
+  function show_leg($station, $start_finish, $station_id, $system_id, $order, $reverse, $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";
+    if ($start_finish && $reverse) $classes[] = "reverse";
     $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";
       }
     }
     $event = $race->getEvent();
+    $reverse = $race->getReverse();
     $allotted_time = 0 + $race->getAllottedTime();
     $legs = array();
     $system_ids = array();
     }
     if ($entry) retrieve_entry($entry);
     if ($_POST['lap1station1']) {
+      /* Don't show the swap start/finish icon. */
+      $reverse = false;
+      echo "var reverse = false;\n";
       /*
         XXX: Trust client validation only because furrycat is the only user
         and he can vouch for himself.
         return true;
       }
     }
-    else echo "//--></script>\n";
+    else {
+      echo "var reverse = " . json_encode($reverse) . ";\n";
+      echo "//--></script>\n";
+    }
     if (! $entry) {
       $sq = new ShipQuery;
       $sq->joinWith('Ship.Competitor');
         $order = 0;
       }
       else $class = '';
-      show_leg($station, $class, $station_id, $system_id, $order, ++$n);
+      show_leg($station, $class, $station_id, $system_id, $order, $reverse, ++$n);
     }
     foreach ($legs as $station => $attributes) {
       list($flags, $station_id, $system_id, $order) = $attributes;
       if (! ($flags & Course::FinishFlag())) continue;
       /* Last leg. */
       $order = 0;
-      show_leg($station, 'finish_line', $station_id, $system_id, $order, ++$n);
+      show_leg($station, 'finish_line', $station_id, $system_id, $order, $reverse, ++$n);
     }
     echo "<tr>\n";
     echo "<td>";
index e3bf483..fd23fdd 100644 (file)
     $race->setClassName($name);
     $race->setEventId($event_id);
     if ($hull_id) $race->setHullId($hull_id);
+    else $race->setHullId(null);
     if ($allotted_time) $race->setAllottedTime($allotted_time);
-    $optional = $posted['optional'];
+    $optional = $_POST['optional'];
     if (is_int($optional) && $optional > 0) $race->setWaypoints($optional);
+    $reverse = $_POST['reverse'];
+    if ($reverse) $race->setReverse(true);
     $prizes = 0;
     foreach ($posted as $k => $v) {
       if (! preg_match('/^prize_(.+)$/', $k, $m)) continue;
     echo "</p>\n";
 
     echo "<h3>Waypoints</h3>\n";
-    echo "<p>Number of optional waypoints: ";
+    echo "<p>";
+    echo "<label><input type=\"checkbox\" name=\"reverse\"";
+    if ($_POST['reverse']) echo " checked=\"checked\"";
+    echo "> Can reverse</label>\n";
+    echo "<label>Number of optional waypoints: ";
     input("optional");
-    echo "</p>\n";
+    echo "<label></p>\n";
 
     echo "<table>\n";
     foreach ($stations as $station) {
index c883df7..aef3907 100644 (file)
     <column name="class_name" type="varchar" size="64" required="false"/>
     <column name="allotted_time" type="integer" required="false"/>
     <column name="waypoints" type="integer" required="false"/>
+    <column name="reverse" type="boolean" default="false" required="false"/>
     <column name="prizes" type="integer" required="false"/>
     <unique name="name">
       <unique-column name="event_id"/>
index a40fe51..536c3c0 100644 (file)
--- a/style.css
+++ b/style.css
@@ -12,6 +12,8 @@ a.disabled { text-decoration: line-through; color: #ff6418; }
 #laps th, #laps td { padding-left: 1em; }
 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: ""; }
+#laps p[class*='reverse'] { pointer-events: none; }
+#laps p[class*='reverse']:after { pointer-events: all; background-image: url(images/reverse.png); background-position: left center; position: relative; padding-left: 16px; background-repeat: no-repeat; content: ""; }
 #laps input:disabled { background-color: transparent; color: black; }
 th { text-align: left; }
 th:nth-child(n+2),td:nth-child(n+2) { text-align: center; }