From 2b645413fc163863d000bddde5bc27a836321422 Mon Sep 17 00:00:00 2001
From: Jacek Kowalski <Jacek@jacekk.info>
Date: Sat, 13 Apr 2019 23:06:48 +0000
Subject: [PATCH] Get rid of jQuery dependency - use XHR and Promise

---
 index.js   |   13 +---
 map.js     |   26 +++-----
 common.js  |   81 +++++++++++++++++++++++++-
 lang_en.js |    1 
 index.html |    6 +-
 map.html   |    7 +-
 lang_pl.js |    1 
 7 files changed, 94 insertions(+), 41 deletions(-)

diff --git a/common.js b/common.js
index 6733d46..b434bf1 100644
--- a/common.js
+++ b/common.js
@@ -8,7 +8,6 @@
 };
 var ttss_types = ['t', 'b'];
 
-// Special directions
 var special_directions = {
 	'Zajezdnia Nowa Huta' : 'ZH',
 	'Zajezdnia Podgórze' : 'ZP',
@@ -17,12 +16,77 @@
 	'Przejazd techniczny' : 'PT',
 };
 
+
+/********
+ * AJAX *
+ ********/
+
+function Deferred(promise, request) {
+	return {
+		promise: promise,
+		request: request,
+		abort: function() {
+			request.abort.bind(request)
+			return Deferred(promise, request);
+		},
+		done: function(func) {
+			return Deferred(promise.then(func), request);
+		},
+		fail: function(func) {
+			return Deferred(promise.catch(func), request);
+		},
+		always: function(func) {
+			return Deferred(promise.finally(func), request);
+		},
+	};
+}
+
+Deferred.all = function(iterable) {
+	return Deferred(
+		Promise.all(
+			iterable.map(x => x.promise)
+		)
+	);
+};
+
+var $ = {
+	timeout: 10000,
+	dataType: 'json',
+	get: function(url) {
+		var self = this;
+		var request = new XMLHttpRequest();
+		var promise = new Promise(function(resolve, reject) {
+			request.timeout = self.timeout;
+			request.onreadystatechange = function() {
+				if(this.readyState == 4) {
+					if(this.status == 200) {
+						if(self.dataType == 'json') {
+							resolve(JSON.parse(this.responseText));
+						} else {
+							resolve(this.responseText);
+						}
+					} else {
+						reject(request);
+					}
+				}
+			};
+			request.open("GET", url, true);
+			request.send();
+		});
+		return Deferred(promise, request);
+	},
+};
+
+
+/***********
+ * VERSION *
+ ***********/
+
 var script_version;
 var script_version_xhr;
 
 var vehicles_info = {};
 
-// Check for website updates
 function checkVersion() {
 	if(script_version_xhr) script_version_xhr.abort();
 	
@@ -46,7 +110,11 @@
 	setInterval(checkVersion, 3600000);
 }
 
-/* Parsing of received JSON parts */
+
+/***********
+ * PARSING *
+ ***********/
+
 function parseStatus(status) {
 	switch(status.status) {
 		case 'STOPPING':
@@ -91,7 +159,6 @@
 	return lang.time_minutes_prefix + ((actual.getTime() - planned.getTime()) / 1000 / 60) + lang.time_minutes_suffix;
 }
 
-// Webservice-related functions
 function parseVehicle(vehicleId) {
 	if(!vehicleId) return false;
 	if(!vehicles_info || !vehicles_info[vehicleId]) {
@@ -159,7 +226,11 @@
 	return span;
 }
 
-// Element mangling
+
+/*******
+ * DOM *
+ *******/
+
 function deleteChildren(element) {
 	while(element.lastChild) element.removeChild(element.lastChild);
 }
diff --git a/index.html b/index.html
index 4b404ec..d8f447d 100644
--- a/index.html
+++ b/index.html
@@ -133,9 +133,9 @@
 				</div>
 			</div>
 		</div>
-		<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT" crossorigin="anonymous"></script>
+		<script src="https://polyfill.io/v3/polyfill.min.js?features=Promise,XMLHttpRequest"></script>
 		<script type="text/javascript" src="lang_pl.js?v7" id="lang_script"></script>
-		<script type="text/javascript" src="common.js?v7"></script>
-		<script type="text/javascript" src="index.js?v5"></script>
+		<script type="text/javascript" src="common.js?v8"></script>
+		<script type="text/javascript" src="index.js?v6"></script>
 	</body>
 </html>
diff --git a/index.js b/index.js
index 3000b78..e59ca07 100644
--- a/index.js
+++ b/index.js
@@ -176,6 +176,7 @@
 		
 		times_timer = setTimeout(function(){ loadTimes(); loadRoute(); }, ttss_refresh);
 	}).fail(fail_ajax).always(loading_end);
+	return times_xhr;
 }
 
 function loadRoute(tripId, vehicleInfo) {
@@ -239,6 +240,7 @@
 			route_table.appendChild(tr);
 		}
 	}).fail(fail_ajax);
+	return route_xhr;
 }
 
 function startTimer(date) {
@@ -375,19 +377,10 @@
 		
 		if(!stop_id) setText(refresh_text, lang.select_stop_click_go);
 	}).fail(fail_ajax);
+	return stop_name_autocomplete_xhr;
 }
 
 function init() {
-	if(!window.jQuery) {
-		fail(lang.jquery_not_loaded);
-		return;
-	}
-	
-	$.ajaxSetup({
-		dataType: 'json',
-		timeout: 10000,
-	});
-	
 	lang_select.addEventListener('input', function(e) {
 		change_language(lang_select.value);
 	});
diff --git a/lang_en.js b/lang_en.js
index 3ced546..d97716f 100644
--- a/lang_en.js
+++ b/lang_en.js
@@ -9,7 +9,6 @@
 	action_expand: 'Expand',
 	action_collapse: 'Collapse',
 	
-	jquery_not_loaded: 'Required JavaScript jQuery library failed to load. You may try refreshing the page.',
 	enter_stop_name_to_begin: 'Enter the stop name to begin.',
 	select_stop_click_go: 'Select the stop and click "Go".',
 	select_stop_type: {
diff --git a/lang_pl.js b/lang_pl.js
index 069f80d..794f6db 100644
--- a/lang_pl.js
+++ b/lang_pl.js
@@ -9,7 +9,6 @@
 	action_expand: 'Rozwiń',
 	action_collapse: 'Zwiń',
 	
-	jquery_not_loaded: 'Wymagana biblioteka jQuery nie została poprawnie załadowana. Spróbuj odświeżyć stronę.',
 	enter_stop_name_to_begin: 'Zacznij wpisywać nazwę przystanku.',
 	select_stop_click_go: 'Wyierz przystanek i kliknij "Dalej".',
 	select_stop_type: {
diff --git a/map.html b/map.html
index ff339ed..24cea68 100644
--- a/map.html
+++ b/map.html
@@ -21,11 +21,10 @@
 <div id="fail" class="ol-unselectable ol-control"><span></span> <span class="close">×</p></div>
 </div>
 <div id="panel"></div>
-<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT" crossorigin="anonymous"></script>
-<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList"></script>
+<script src="https://polyfill.io/v3/polyfill.min.js?features=Array.prototype.forEach,Array.prototype.includes,Array.prototype.map,Element.prototype.classList,Promise,String.prototype.startsWith,XMLHttpRequest,requestAnimationFrame"></script>
 <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v5.3.0/build/ol.js" integrity="sha384-iQkGyyH4ioz3m+maM3s9MX1Oq67mACa4B9Z3ovUv3Sv37LJ96fx3WnZfLoiC3Wfl" crossorigin="anonymous"></script>
 <script tyle="text/javascript" src="lang_pl.js?v7" id="lang_script"></script>
-<script tyle="text/javascript" src="common.js?v7"></script>
-<script tyle="text/javascript" src="map.js?v19"></script>
+<script tyle="text/javascript" src="common.js?v8"></script>
+<script tyle="text/javascript" src="map.js?v20"></script>
 </body>
 </html>
diff --git a/map.js b/map.js
index 1496bb5..e8550d4 100644
--- a/map.js
+++ b/map.js
@@ -151,7 +151,7 @@
 
 function fail_ajax_generic(data, fnc) {
 	// abort() is not a failure
-	if(data.readyState == 0 && data.statusText == 'abort') return;
+	if(data.readyState == 0) return;
 	
 	if(data.status == 0) {
 		fnc(lang.error_request_failed_connectivity, data);
@@ -247,7 +247,7 @@
 function unstyleSelectedFeatures() {
 	stop_selected_source.clear();
 	route_source.clear();
-	if(feature_clicked && ttss_types.indexOf(feature_clicked.getId().substr(0, 1)) >= 0) {
+	if(feature_clicked && ttss_types.includes(feature_clicked.getId().substr(0, 1))) {
 		styleVehicle(feature_clicked);
 	}
 }
@@ -315,7 +315,7 @@
 		var stop = stops[i];
 		
 		if(stop.category == 'other') continue;
-		if(stops_ignored.indexOf(stop.shortName) >= 0) continue;
+		if(stops_ignored.includes(stop.shortName)) continue;
 		
 		stop.geometry = getGeometry(stop);
 		var stop_feature = new ol.Feature(stop);
@@ -375,6 +375,7 @@
 		}));
 		route_layer.setVisible(true);
 	});
+	return path_xhr;
 }
 
 function vehicleTable(feature, table) {
@@ -423,6 +424,7 @@
 		
 		feature_timer = setTimeout(function() { vehicleTable(feature, table); }, ttss_refresh);
 	}).fail(fail_ajax_popup);
+	return feature_xhr;
 }
 
 function stopTable(stopType, stopId, table, ttss_type) {
@@ -476,6 +478,7 @@
 		
 		feature_timer = setTimeout(function() { stopTable(stopType, stopId, table, ttss_type); }, ttss_refresh);
 	}).fail(fail_ajax_popup);
+	return feature_xhr;
 }
 
 function featureClicked(feature) {
@@ -517,7 +520,7 @@
 		typeName = '';
 	}
 	// Vehicle
-	else if(ttss_types.indexOf(type) >= 0) {
+	else if(ttss_types.includes(type)) {
 		var span = displayVehicle(feature.get('vehicle_type'));
 		
 		additional = document.createElement('p');
@@ -537,7 +540,7 @@
 		styleVehicle(feature, true);
 	}
 	// Stop or stop point
-	else if(['s', 'p'].indexOf(type) >= 0) {
+	else if(['s', 'p'].includes(type)) {
 		var ttss_type = feature.getId().substr(1, 1);
 		if(type == 's') {
 			var second_type = lang.departures_for_buses;
@@ -561,7 +564,6 @@
 				);
 			}
 		} else {
-			
 			stopTable('stopPoint', feature.get('stopPoint'), tbody, ttss_type);
 			
 			additional = document.createElement('p');
@@ -770,16 +772,6 @@
 }
 
 function init() {
-	if(!window.jQuery) {
-		fail(lang.jquery_not_loaded);
-		return;
-	}
-	
-	$.ajaxSetup({
-		dataType: 'json',
-		timeout: 10000,
-	});
-	
 	panel = new Panel(document.getElementById('panel'));
 	
 	route_source = new ol.source.Vector({
@@ -948,7 +940,7 @@
 	stops_type.forEach(function(type) {
 		future_requests.push(updateStops(type.substr(0,1), type.substr(1,1)));
 	});
-	$.when(future_requests).done(hash);
+	Deferred.all(future_requests).done(hash);
 	
 	window.addEventListener('hashchange', hash);
 	

--
Gitblit v1.9.1