PageSourceSearch

https://www.kartbus.org/wp-content/themes/kartbus/js/real-time-arrivals.js?ver=7.1.2

js kartbus.org collected 2026-10-02 06:23:48 UTC 6,136 bytes, 219 lines download raw bytes

1var routes;
2var platforms;
3var selectedStopId;
4var refreshTimeoutId;
5
6function ensureArray(item) {
7  return _.isArray(item) ? item: [item];
8}
9
10function formatStop(stop) {
11  return {
12    name: stop['@attributes'].Name,
13    stopId: stop['@attributes'].PlatformTag
14  }
15}
16
17jQuery(function($) {
18  function populateRoutes(routes) {
19    $('#real-time-arrival-route option').not(':first-child').remove();
20    $('#real-time-arrival-route').append(routes.map(route => {
21      return $('<option>').val(route.No).text(route.No + ' - ' + route.Name);
22    }))
23    .prop('disabled', false);
24
25    clearStops();
26  }
27
28  function populateStops(stops) {
29    clearStops();
30    $('#real-time-arrival-stop').append(stops.map(function(stop) {
31      return $('<option>').val(stop.Tag).text(stop.Name);
32    }))
33    .prop('disabled', false);
34  }
35
36  function resetRoutes() {
37    $('#real-time-arrival-route option').first().prop('selected', true);
38  }
39
40  function clearStops() {
41    $('#real-time-arrival-stop option').not(':first-child').remove();
42    $('#real-time-arrival-stop').prop('disabled', true);
43    selectedStopId = undefined;
44    clearResults();
45  }
46
47  function clearResults() {
48    $('.real-time-arrival-results').empty();
49  }
50
51  function normalizeArrivals(results) {
52    // Current API shape:
53    // results.Projects[].Routes[].Destinations[].Trips[]: { ET: number|null, ST: ... }
54    // where ET appears to be minutes until arrival.
55    if (!results || !Array.isArray(results.Projects) || results.Projects.length === 0) return [];
56
57    const arrivals = [];
58    results.Projects.forEach(project => {
59      (project.Routes || []).forEach(route => {
60        (route.Destinations || []).forEach(destination => {
61          const minutes = (destination.Trips || [])
62            .map(t => (t && typeof t.ET === 'number' ? t.ET : null))
63            .filter(m => typeof m === 'number' && Number.isFinite(m) && m >= 0)
64            .sort((a, b) => a - b);
65
66          if (minutes.length === 0) return;
67          arrivals.push({
68            routeNo: route.No,
69            destinationName: destination.Name,
70            minutes
71          });
72        });
73      });
74    });
75
76    return arrivals;
77  }
78
79  function getTimes() {
80    if (!selectedStopId) {
81      return
82    }
83
84    if (refreshTimeoutId) {
85      clearTimeout(refreshTimeoutId);
86      refreshTimeoutId = undefined;
87    }
88
89    fetch(`/wp-content/themes/kartbus/realtime.php?type=times&stop_id=${selectedStopId}`)
90    .then(response => {
91      if (!response.ok) {
92        throw new Error('Network response was not ok');
93      }
94      return response.json();
95    })
96    .then(results => {
97      clearResults();
98
99      if (!results || !results.Projects) {
100        console.error('unable to fetch times');
101        $('.real-time-arrival-results').append($('<h3>').text('Unable to fetch times'));
102        return;
103      }
104
105      const selectedStop = platforms.find(platform => platform.Tag === selectedStopId);
106
107      $('.real-time-arrival-results').append($('<h3>').text(selectedStop.Name));
108      $('.real-time-arrival-results').append($('<div>').text(`Stop ID: ${selectedStop.No}`));
109
110      const arrivals = normalizeArrivals(results);
111      if (arrivals.length === 0) {
112        $('.real-time-arrival-results').append($('<p>').text('No times'))
113        return;
114      }
115
116      arrivals.forEach(arrival => {
117        var container = $('<div>').addClass('d-flex align-items-center real-time-arrival-prediction');
118        var route = routes.find(route => route.No === arrival.routeNo);
119        if (!route) {
120          // If route list is out of sync with arrivals, still render something useful.
121          route = { No: arrival.routeNo, Name: arrival.destinationName || '', Color: '#6c757d' };
122        }
123
124        $('<div>').text(route.No).addClass('route-number').css('background-color', route.Color).appendTo(container);
125        
126        $('<div>').text(route.Name).addClass('ml-2 mr-2').appendTo(container);
127
128        arrival.minutes.forEach(minute => {
129          $('<div>').addClass('ml-2')
130            .append($('<span>').text(minute).addClass('real-time-arrival-prediction-time'))
131            .append($('<span>').text('min'))
132            .appendTo(container);
133        });
134
135        $('.real-time-arrival-results').append(container);
136      })
137    });
138
139    // Refresh every minute;
140    refreshTimeoutId = setTimeout(getTimes, 60 * 1000);
141  }
142
143  fetch('/wp-content/themes/kartbus/realtime.php?type=routes')
144  .then(response => {
145    if (!response.ok) {
146      throw new Error('Network response was not ok');
147    }
148    return response.json();
149  })
150  .then(results => {
151    if (!results || !results.Projects || !results.Platforms) {
152      console.error('unable to fetch routes');
153      return;
154    }
155
156    routes = results.Projects[0].Routes;
157    platforms = results.Platforms;
158
159    populateRoutes(routes);
160  })
161  .catch(error => console.log(error))
162
163  $('#real-time-arrival-route').change(function() {
164    var routeNo = $('#real-time-arrival-route').val();
165
166    if (routeNo === '') {
167      clearStops();
168      return;
169    }
170
171    var route = _.find(routes, {No: routeNo});
172    var stops = route.Platforms.map(stopId => {
173      return platforms.find(platform => platform.Tag === stopId)
174    });
175    populateStops(stops);
176  });
177
178  $('#real-time-arrival-stop').change(function() {
179    var stopId = $('#real-time-arrival-stop').val();
180
181    if (stopId === '') {
182      return;
183    }
184
185    selectedStopId = parseInt(stopId, 10)
186    getTimes();
187  });
188
189  $('input[name="arrival_type"]').change(function() {
190    var type = $('input[name="arrival_type"]:checked').val();
191
192    $('#' + type).prop('hidden', false)
193    .siblings().prop('hidden', true);
194
195    resetRoutes();
196    clearStops();
197  });
198
199  $('#real-time-arrival-stop-id-form').submit(function(e) {
200    e.preventDefault();
201
202    var stopId = $('#real-time-arrival-stop-id').val();
203
204    if (!stopId) {
205      alert('Please enter a stop ID');
206      return;
207    }
208
209    var selectedStop = platforms.find(platform => platform.No === stopId);
210
211    if (!selectedStop) {
212      alert('Invalid stop ID');
213      return;
214    }
215
216    selectedStopId = selectedStop.Tag;
217    getTimes();
218  })
219});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.