+ /**
+ * Compute and set the zone.
+ *
+ * We can be given a zone in two ways. First, on Commuter Bus
+ * tickets, it is given explicitly via the querystring. But
+ * It can also be specified implicitly via the origin and
+ * destination on a MARC Train ticket. Here we try both and
+ * then call set_zone() with the result if something worked.
+ */
+ function compute_and_set_zone() {
+ const params = new URLSearchParams(document.location.search);
+ const src = params.get("origin");
+ const dest = params.get("destination");
+
+ if (src && dest) {
+ /* MARC Train. We can assume that compute_marc_zone() doesn't
+ * return null because that's part of our form validation. */
+ const zone = compute_marc_zone(src, dest);
+ set_zone(zone);
+ }
+ else if (params.get("zone")) {
+ /* Commuter Bus */
+ set_zone(params.get("zone"));
+ }
+ }
+
+
+ /**
+ * Set the origin and destination for the MARC Train if they
+ * were provided, and unhide them if so.
+ */
+ function set_marc_origin_destination() {
+ const params = new URLSearchParams(document.location.search);
+ if (!params.get("origin") || !params.get("destination")) {
+ return;
+ }
+
+ const src = params.get("origin");
+ const dest = params.get("destination");
+
+ /* origindest contains both the origin and destination */
+ const origindest = document.getElementById("origindest");
+
+ const origin = document.getElementById("origin");
+ const destination = document.getElementById("destination");
+
+ origin.textContent = params.get("origin");
+ destination.textContent = params.get("destination");
+
+ origindest.style.display = "block"; /* hidden by default */
+ }
+
+
+ /**
+ * Hide the menu and display the ticket. This is what happens
+ * when you submit the form.
+ */
+ function go() {
+ /* To create our "window" onto the scene, we're going to slide the
+ * SVG off the left-hand side of the screen, and we don't want
+ * scroll bars to appear. */
+ document.body.style.overflow = "hidden";
+ document.body.style.margin = "0";
+ document.body.style.padding = "0";
+
+ const svg = document.querySelector("svg");
+ const menu = document.getElementById("menu");
+ svg.style.display = "initial";
+ menu.style.display = "none";
+ }
+
+ /**
+ * Validate the MARC form's origin/destination.
+ *
+ * We don't want the user to be able to choose a pair of stops that
+ * aren't actually connected by the same MARC line. If we don't have
+ * zone information for the (origin,destination) pair, that indicates
+ * that it's probably not a valid choice; otherwise I would have
+ * filled in the information from the CharmPass app already.
+ */
+ function validate_origin_destination(event) {
+ const origins = document.getElementsByName("origin");
+ const destinations = document.getElementsByName("destination");
+
+ let src = null;
+ let dest = null;
+ origins.forEach((x) => { if (x.checked) src = x; })
+ destinations.forEach((x) => {
+ if (x.checked) dest = x;
+
+ /* clear all errors before possibly setting one */
+ x.setCustomValidity('');
+ })
+
+ if (src.value === dest.value) {
+ let err = "Origin and destination are the same!";
+ dest.setCustomValidity(err);
+ }
+ else if (compute_marc_zone(src.value, dest.value) === null) {
+ let err = "Origin and destination are on different lines!";
+ dest.setCustomValidity(err);
+ }
+ }
+
+ /*****************************************************/
+ /* Add event handlers for all of the functions above */
+ /*****************************************************/
+
+ const params = new URLSearchParams(document.location.search);
+ if (params.get("go")) {
+ /* First unhide the SVG (swap it with the form) */
+ window.addEventListener("load", go);
+
+ /* Center the ticket once when the page has loaded */
+ window.addEventListener("load", center_ticket);
+
+ /* Re-center the ticket when the window is resized */
+ window.addEventListener("resize", center_ticket);
+
+ /* Set the service identifier when the page has loaded */
+ window.addEventListener("load", set_service_id);
+
+ /* Set the service name when the page has loaded */
+ window.addEventListener("load", set_service_name);
+
+ /* Resize the ticket background if necessary */
+ window.addEventListener("load", resize_ticket);
+
+ /* Set the security code text when the page has loaded */
+ window.addEventListener("load", set_code);
+
+ /* Center the security code text when the page has loaded; in
+ * particular, after we set the code. */
+ window.addEventListener("load", center_code);
+
+ /* Set the ticket expiration date/time upon page load */
+ window.addEventListener("load", set_ticket_expiry);
+
+ /* Set the MARC Train origin and destination, if applicable */
+ window.addEventListener("load", set_marc_origin_destination);
+
+ /* Compute and set the zone, if applicable */
+ window.addEventListener("load", compute_and_set_zone);
+
+ /* Swap colors when the screen is tapped */
+ document.body.addEventListener("click", swap_day_night);
+ }
+ else {
+ /* If we haven't submitted the form yet, set up change handlers
+ * for the origin/destination radio buttons that validate that
+ * the origin and destination are on the same line. */
+ document.getElementsByName("origin").forEach(
+ (x) => x.addEventListener("change", validate_origin_destination)
+ );
+ document.getElementsByName("destination").forEach(
+ (x) => x.addEventListener("change", validate_origin_destination)
+ );
+
+ /* Also do it when the page loads, because firefox likes to
+ * remember your selection even after the page reloads. */
+ window.addEventListener("load", validate_origin_destination);
+ }
+