PageSourceSearch

https://www.bielersee.ch/_assets/35ae1b0d71a4028c179f16e8867b9b27/JavaScript/App.js?1780305259

js bielersee.ch collected 2026-10-02 11:43:17 UTC 13,225 bytes, 458 lines download raw bytes

1(function ($) {
2
3  var TOURDATATIMETABLE = TOURDATATIMETABLE || {},
4
5    $win = $(window),
6    $doc = $(document),
7    $body = $(document.body),
8    extentionClass = '.tx-tourdata-timetable';
9
10
11  TOURDATATIMETABLE = {
12
13    _: function () {
14
15      this.query.select._();
16      this.query.tripTypeToggler._();
17      this.query.dropdown._();
18      this.query.datepicker._();
19      this.result.timeline._();
20      this.result.accordion._();
21    },
22
23    query: {
24
25      select: {
26
27        _: function () {
28
29          var self = this;
30
31          // prevent submit form on enter
32          $(window).keydown(function (event) {
33
34            var key = event.key.toLowerCase();
35            if (key == 'enter') {
36
37              event.preventDefault();
38              return false;
39            }
40          });
41
42          // observe form elements and start action on change
43          $('#trip-type [type="radio"], #departure-place select, #arrival-place input[type=hidden], #datepicker', extentionClass).on('change', function () {
44
45            self.submitQuery();
46
47            return false;
48          });
49
50          $('#rotate-places button, #datepicker-prev button, #datepicker-next button', extentionClass).on('click', function () {
51
52            var clickedItem = $(this);
53
54            self.submitQuery(clickedItem.attr('name') + '=' + clickedItem.val());
55
56            return false;
57          });
58        },
59
60        submitQuery: function (param) {
61
62          var formData = $('form', extentionClass).serialize();
63
64          if (param) {
65            formData = decodeURI(formData);
66            formData = formData.split('&');
67            formData.push(param);
68            formData = formData.join('&');
69            formData = encodeURI(formData);
70          }
71
72          $('.query', extentionClass).addClass('loading');
73
74          $.ajax({
75            type: 'POST',
76            url: $('form', extentionClass).data('ajax'),
77            data: formData,
78            success: function (data) {
79              $('.query', extentionClass).html($(data).find('form'));
80              $('.query', extentionClass).removeClass('loading');
81              history.pushState({}, document.title, $('form', extentionClass).data('url'));
82              TOURDATATIMETABLE._();
83              hideKeSearchForm();
84            },
85            error: function (data) {
86              $('.query', extentionClass).removeClass('loading');
87              alert('Something went wrong');
88            }
89          });
90        }
91      },
92
93      tripTypeToggler: {
94
95        _: function () {
96
97          var tripTypeToggler = $('.trip-type-toggler', extentionClass),
98            tripTypeTogglerItems = tripTypeToggler.children('.trip-type-toggler-item');
99
100          tripTypeTogglerItems.on('click', function () {
101
102            var togglerItem = $(this),
103              onewayRadio = tripTypeToggler.find('input[id="oneway"]'),
104              roundtripRadio = tripTypeToggler.find('input[id="roundtrip"]');
105
106            if (togglerItem.data('type') == 'oneway') {
107              onewayRadio.attr('checked', true);
108              roundtripRadio.attr('checked', false);
109            } else {
110              onewayRadio.attr('checked', false);
111              roundtripRadio.attr('checked', true);
112            }
113
114            TOURDATATIMETABLE.query.select.submitQuery();
115          });
116        }
117      },
118
119      dropdown: {
120
121        dropdowns: [],
122
123        _: function () {
124
125          var dropdowns = $('.dropdown', extentionClass),
126            self = this;
127
128          dropdowns.each(function (index) {
129
130            self.dropdowns[index] = $(this);
131
132            var dropdown = self.dropdowns[index],
133              resultList = dropdown.find('.results ul'),
134              queryField = dropdown.find('input[type=text]'),
135              places = window['tx_tourdata_timetable_' + dropdown.parent().attr('id').replace('-', '')];
136
137            // handle action on field focus in
138            queryField.on('focusin', function () {
139
140              var fieldValue = queryField.val().toLowerCase();
141
142              self.updatePlaces(index);
143              dropdown.addClass('active');
144
145              // close all other dropdowns
146              dropdowns.each(function (innerIndex) {
147
148                if (innerIndex != index) {
149                  $(this).removeClass('active');
150                }
151              });
152            });
153
154            // check each pushed key
155            queryField.on('keyup', function (event) {
156
157              var queryValue = $(this).val().toLowerCase(),
158                key = event.key.toLowerCase(),
159                foundStops = [];
160
161              if (key == 'backspace') {
162                queryField.val('');
163                self.unselectListItem(index);
164                self.updatePlaces(index);
165                dropdown.addClass('active');
166                queryValue = '';
167              }
168
169              if (key == 'enter') {
170                if (resultList.find('li:not(.error):first').length > 0) {
171                  self.selectListItem(index, resultList.find('li:not(.error):first'));
172                  dropdown.removeClass('active');
173                }
174
175                return false;
176              }
177
178              if (queryValue.length < 1) {
179
180                foundStops = self.showAllPlaces(places);
181              } else {
182                $.each(places, function (key, stop) {
183
184                  var cleanQueryValue = queryValue.toLowerCase(),
185                    cleanStop = stop.toLowerCase();
186
187                  cleanQueryValue = cleanQueryValue.replace(' ', '');
188                  cleanStop = cleanStop.replace(' ', '');
189
190                  var distance = self.getDistance(cleanQueryValue, cleanStop.substr(0, cleanQueryValue.length));
191
192                  if (distance / cleanQueryValue.length < 0.1) {
193
194                    foundStops.push({id: key, name: stop, distance: distance});
195                  }
196                });
197
198                foundStops.sort(function (a, b) {
199
200                  return a.distance - b.distance;
201                });
202              }
203
204              self.updatePlaces(index, foundStops);
205              dropdown.addClass('active');
206            })
207
208            // remove all-result class on scrolling
209            resultList.on('scroll', function () {
210
211              resultList.closest('.results').removeClass('all-results');
212            });
213          });
214        },
215
216        showAllPlaces: function (places) {
217
218          var foundStops = [];
219
220          $.each(places, function (key, stop) {
221
222            foundStops.push({id: key, name: stop, distance: 0});
223          });
224
225          foundStops.sort(function (a, b) {
226
227            var nameA = a.name.toLowerCase();
228            var nameB = b.name.toLowerCase();
229            if (nameA < nameB) {
230
231              return -1;
232            }
233
234            if (nameA > nameB) {
235
236              return 1;
237            }
238
239            return 0;
240          });
241
242          return foundStops;
243        },
244
245        updatePlaces: function (index, foundStops) {
246
247          var self = this,
248            dropdown = $(this.dropdowns[index]),
249            resultList = dropdown.find('.results ul'),
250            resultListItems = resultList.find('li:not(.error)'),
251            resultContainer = resultList.closest('.results');
252
253          // update list if there are some found stops
254          if (foundStops) {
255            resultListItems.remove();
256
257            $.each(foundStops, function () {
258              resultList.append('<li data-value="' + this.id + '">' + this.name + '</li>');
259            });
260          }
261
262          // initialize list variable after rebuild
263          resultListItems = resultList.find('li:not(.error)');
264
265          // on click on result list item
266          resultListItems.on('click', function () {
267
268            self.selectListItem(index, $(this));
269            dropdown.removeClass('active');
270          });
271
272          // handle message if no result is found
273          if (resultListItems.length == 0) {
274            resultContainer.addClass('no-results');
275          } else {
276            resultContainer.removeClass('no-results');
277          }
278
279          // handle all-result class to add some special styles in this case
280          if (!foundStops && resultList.height() >= 290) {
281            resultContainer.addClass('all-results');
282          } else {
283            resultContainer.removeClass('all-results');
284          }
285        },
286
287        unselectListItem: function (index) {
288
289          this.dropdowns[index].find('input[type=hidden]').val('');
290        },
291
292        selectListItem: function (index, selectedItem) {
293
294          var dropdown = this.dropdowns[index];
295
296          dropdown.find('input[type=text]').val(selectedItem.text());
297          dropdown.find('input[type=hidden]').val(selectedItem.data('value'));
298
299          TOURDATATIMETABLE.query.select.submitQuery();
300        },
301
302        // found @ http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance
303        // Compute the edit distance between the two given strings
304        getDistance: function (a, b) {
305
306          if (a.length === 0) return b.length;
307          if (b.length === 0) return a.length;
308
309          var matrix = [];
310
311          // increment along the first column of each row
312          var i;
313          for (i = 0; i <= b.length; i++) {
314            matrix[i] = [i];
315          }
316
317          // increment each column in the first row
318          var j;
319          for (j = 0; j <= a.length; j++) {
320            matrix[0][j] = j;
321          }
322
323          // Fill in the rest of the matrix
324          for (i = 1; i <= b.length; i++) {
325            for (j = 1; j <= a.length; j++) {
326              if (b.charAt(i - 1) == a.charAt(j - 1)) {
327                matrix[i][j] = matrix[i - 1][j - 1];
328              } else {
329                matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
330                  Math.min(matrix[i][j - 1] + 1, // insertion
331                    matrix[i - 1][j] + 1)); // deletion
332              }
333            }
334          }
335
336          return matrix[b.length][a.length];
337        }
338      },
339
340      datepicker: {
341
342        _: function () {
343
344          $.datepicker.setDefaults({
345            beforeShowDay: function (date) {
346              var dateString = $.datepicker.formatDate('dd.mm.yy', date);
347              return [dates.indexOf(dateString) != -1]
348            },
349            inline: true,
350            altField: '#datepicker-input',
351            defaultDate: $('#datepicker-input').val()
352          });
353
354          $('#datepicker-trigger').on('click', function () {
355
356            $('#datepicker').datepicker($.datepicker.regional[$('html').attr('lang').split('-')[0]]);
357            $(this).addClass('open');
358            return false;
359          });
360        }
361      }
362    },
363
364    result: {
365
366      timeline: {
367
368        _: function () {
369
370          var timelines = $('.timeline', extentionClass),
371            self = this;
372
373          timelines.each(function (index) {
374
375            var timeline = $(this),
376              togglerWrapper = timeline.find('li.toggler'),
377              toggler = togglerWrapper.find('.line span, .place'),
378              stops = togglerWrapper.find('.stops');
379
380            // init the accordion
381            timeline.closest('.accordion-collapse').on('shown.bs.collapse', function () {
382
383              if (!stops.hasClass('init-done')) {
384                var stopsHeight = stops.height();
385                stops.css('height', 0);
386                stops.addClass('init-done', function () {
387
388                  stops.css('height', stopsHeight);
389                });
390              }
391            });
392
393            toggler.on('click', function () {
394
395              // toggle of accordion
396              if (!togglerWrapper.hasClass('minimized')) {
397                togglerWrapper.addClass('minimized');
398              } else if (stops.hasClass('init-done')) {
399                togglerWrapper.removeClass('minimized');
400              }
401            });
402          });
403        }
404      },
405
406      accordion: {
407
408        _: function () {
409
410          var self = this;
411
412          $('.main-accordion > div > div > .accordion-trigger', extentionClass).on('click', function () {
413
414            self.accordionToggler($(this))
415          });
416
417          $('.sub-accordion > div > div > .accordion-trigger', extentionClass).on('click', function () {
418
419            self.accordionToggler($(this))
420          });
421        },
422
423        accordionToggler: function (clickedAccordion) {
424
425          var accordion = clickedAccordion.closest('.accordion-item');
426
427          if (accordion.hasClass('show')) {
428            accordion.removeClass('show');
429          } else {
430            clickedAccordion.closest('.accordion').children().each(function () {
431
432              var otherAccordion = $(this);
433
434              otherAccordion.removeClass('show');
435            });
436
437            accordion.addClass('show');
438          }
439        }
440      }
441    }
442  }
443
444  // Formular mit id "form_kesearch_pi1" im div mit Klasse "query" ausblenden
445  function hideKeSearchForm() {
446    const queryDiv = document.querySelector('.query');
447    if (queryDiv) {
448      const form = queryDiv.querySelector('#form_kesearch_pi1');
449      if (form) {
450        form.style.display = 'none';
451      }
452    }
453  }
454
455  TOURDATATIMETABLE._();
456  hideKeSearchForm();
457
458})(jQuery);

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.