small modifications so that at least something can work
[lantea.git] / js / ui.js
CommitLineData
a7393a71
RK
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
23cd2dcc 4
993fd081 5// Get the best-available indexedDB object.
3d99a6fd 6window.indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
993fd081
RK
7var mainDB;
8
7a549148 9var gUIHideCountdown = 0;
4b1d0915 10var gWaitCounter = 0;
68afcd96 11var gAction, gActionLabel;
c4d0569c 12var gOSMAPIURL = "http://api.openstreetmap.org/";
7a549148 13
b47b4a65 14window.onload = function() {
68afcd96
RK
15 gAction = document.getElementById("action");
16 gActionLabel = document.getElementById("actionlabel");
17
b47b4a65
RK
18 var mSel = document.getElementById("mapSelector");
19 for (var mapStyle in gMapStyles) {
20 var opt = document.createElement("option");
21 opt.value = mapStyle;
22 opt.text = gMapStyles[mapStyle].name;
23 mSel.add(opt, null);
24 }
23cd2dcc 25
7a549148
RK
26 var areas = document.getElementsByClassName('overlayArea');
27 for (var i = 0; i <= areas.length - 1; i++) {
28 areas[i].addEventListener("mouseup", uiEvHandler, false);
29 areas[i].addEventListener("mousemove", uiEvHandler, false);
30 areas[i].addEventListener("mousedown", uiEvHandler, false);
31 areas[i].addEventListener("mouseout", uiEvHandler, false);
32
33 areas[i].addEventListener("touchstart", uiEvHandler, false);
34 areas[i].addEventListener("touchmove", uiEvHandler, false);
35 areas[i].addEventListener("touchend", uiEvHandler, false);
36 areas[i].addEventListener("touchcancel", uiEvHandler, false);
37 areas[i].addEventListener("touchleave", uiEvHandler, false);
38 }
39
1222624d
RK
40 document.getElementById("body").addEventListener("keydown", uiEvHandler, false);
41
8e901dce 42 if (navigator.platform.length == "") {
b91b74a7
RK
43 // For Firefox OS, don't display the "save" button.
44 // Do this by setting the debugHide class for testing in debug mode.
45 document.getElementById("saveTrackButton").classList.add("debugHide");
c4d0569c
RK
46 // For now, only show the upload UI on Firefox OS.
47 document.getElementById("uploadTrackButton").classList.remove("debugHide");
48 // Without OAuth, the login data is useless
49 //document.getElementById("uploadSettingsArea").classList.remove("debugHide");
50 }
51
52 if (gDebug) {
53 gOSMAPIURL = "http://api06.dev.openstreetmap.org/";
b91b74a7 54 }
7a549148 55
993fd081 56 initDB();
b47b4a65 57 initMap();
4b1d0915
RK
58
59 var loopCnt = 0;
60 var waitForInitAndDraw = function() {
61 if ((gWaitCounter <= 0) || (loopCnt > 100)) {
62 if (gWaitCounter <= 0)
63 gWaitCounter = 0;
64 else
915d4271 65 console.log("Loading failed (waiting for init).");
4b1d0915
RK
66
67 gMapPrefsLoaded = true;
68 resizeAndDraw();
68afcd96
RK
69 gActionLabel.textContent = "";
70 gAction.style.display = "none";
4b1d0915 71 setTracking(document.getElementById("trackCheckbox"));
c4d0569c 72 gPrefs.get(gDebug ? "osm_dev_user" : "osm_user", function(aValue) {
8389557a
RK
73 if (aValue) {
74 document.getElementById("uploadUser").value = aValue;
75 document.getElementById("uploadTrackButton").disabled = false;
76 }
77 });
c4d0569c 78 gPrefs.get(gDebug ? "osm_dev_pwd" : "osm_pwd", function(aValue) {
8389557a
RK
79 var upwd = document.getElementById("uploadPwd");
80 if (aValue)
81 document.getElementById("uploadPwd").value = aValue;
82 });
4b1d0915
RK
83 }
84 else
85 setTimeout(waitForInitAndDraw, 100);
86 loopCnt++;
87 };
88 waitForInitAndDraw();
b47b4a65
RK
89}
90
91window.onresize = function() {
92 resizeAndDraw();
93}
94
993fd081
RK
95function initDB() {
96 // Open DB.
1222624d 97 var request = window.indexedDB.open("MainDB-lantea", 2);
993fd081
RK
98 request.onerror = function(event) {
99 // Errors can be handled here. Error codes explain in:
100 // https://developer.mozilla.org/en/IndexedDB/IDBDatabaseException#Constants
915d4271
RK
101 if (gDebug)
102 console.log("error opening mainDB: " + event.target.errorCode);
993fd081
RK
103 };
104 request.onsuccess = function(event) {
993fd081
RK
105 mainDB = request.result;
106 };
107 request.onupgradeneeded = function(event) {
108 mainDB = request.result;
a8634d37 109 var ver = mainDB.version || 0; // version is empty string for a new DB
915d4271
RK
110 if (gDebug)
111 console.log("mainDB has version " + ver + ", upgrade needed.");
112 if (!mainDB.objectStoreNames.contains("prefs")) {
a8634d37
RK
113 // Create a "prefs" objectStore.
114 var prefsStore = mainDB.createObjectStore("prefs");
915d4271
RK
115 }
116 if (!mainDB.objectStoreNames.contains("track")) {
a8634d37
RK
117 // Create a "track" objectStore.
118 var trackStore = mainDB.createObjectStore("track", {autoIncrement: true});
119 }
915d4271 120 if (!mainDB.objectStoreNames.contains("tilecache")) {
a8634d37
RK
121 // Create a "tilecache" objectStore.
122 var tilecacheStore = mainDB.createObjectStore("tilecache");
123 }
993fd081
RK
124 mainDB.onversionchange = function(event) {
125 mainDB.close();
126 mainDB = undefined;
127 initDB();
128 };
129 };
130}
131
7a549148
RK
132function showUI() {
133 if (gUIHideCountdown <= 0) {
134 var areas = document.getElementsByClassName('overlayArea');
135 for (var i = 0; i <= areas.length - 1; i++) {
136 areas[i].classList.remove("hidden");
137 }
138 setTimeout(maybeHideUI, 1000);
139 }
140 gUIHideCountdown = 5;
141}
142
143function maybeHideUI() {
144 gUIHideCountdown--;
145 if (gUIHideCountdown <= 0) {
146 var areas = document.getElementsByClassName('overlayArea');
147 for (var i = 0; i <= areas.length - 1; i++) {
148 areas[i].classList.add("hidden");
149 }
150 }
151 else {
152 setTimeout(maybeHideUI, 1000);
153 }
154}
155
993fd081
RK
156function toggleTrackArea() {
157 var fs = document.getElementById("trackArea");
158 if (fs.style.display != "block") {
159 fs.style.display = "block";
7a549148 160 showUI();
993fd081
RK
161 }
162 else {
163 fs.style.display = "none";
164 }
165}
166
b47b4a65 167function toggleSettings() {
993fd081 168 var fs = document.getElementById("settingsArea");
b47b4a65
RK
169 if (fs.style.display != "block") {
170 fs.style.display = "block";
7a549148 171 showUI();
b47b4a65
RK
172 }
173 else {
174 fs.style.display = "none";
175 }
176}
99631a75 177
c5378747
RK
178function toggleFullscreen() {
179 if ((document.fullScreenElement && document.fullScreenElement !== null) ||
180 (document.mozFullScreenElement && document.mozFullScreenElement !== null) ||
181 (document.webkitFullScreenElement && document.webkitFullScreenElement !== null)) {
182 if (document.cancelFullScreen) {
183 document.cancelFullScreen();
184 } else if (document.mozCancelFullScreen) {
185 document.mozCancelFullScreen();
186 } else if (document.webkitCancelFullScreen) {
187 document.webkitCancelFullScreen();
188 }
189 }
190 else {
191 var elem = document.getElementById("body");
192 if (elem.requestFullScreen) {
193 elem.requestFullScreen();
194 } else if (elem.mozRequestFullScreen) {
195 elem.mozRequestFullScreen();
196 } else if (elem.webkitRequestFullScreen) {
197 elem.webkitRequestFullScreen();
198 }
199 }
200}
201
7a549148
RK
202var uiEvHandler = {
203 handleEvent: function(aEvent) {
204 var touchEvent = aEvent.type.indexOf('touch') != -1;
205
206 switch (aEvent.type) {
207 case "mousedown":
208 case "touchstart":
209 case "mousemove":
210 case "touchmove":
211 case "mouseup":
212 case "touchend":
1222624d 213 case "keydown":
7a549148
RK
214 showUI();
215 break;
216 }
217 }
218};
219
8389557a
RK
220function setUploadField(aField) {
221 switch (aField.id) {
222 case "uploadUser":
c4d0569c 223 gPrefs.set(gDebug ? "osm_dev_user" : "osm_user", aField.value);
8389557a
RK
224 document.getElementById("uploadTrackButton").disabled = !aField.value.length;
225 break;
226 case "uploadPwd":
c4d0569c 227 gPrefs.set(gDebug ? "osm_dev_pwd" : "osm_pwd", aField.value);
8389557a
RK
228 break;
229 }
230}
231
99631a75
RK
232function makeISOString(aTimestamp) {
233 // ISO time format is YYYY-MM-DDTHH:mm:ssZ
234 var tsDate = new Date(aTimestamp);
235 return tsDate.getUTCFullYear() + "-" +
236 (tsDate.getUTCMonth() < 10 ? "0" : "") + tsDate.getUTCMonth() + "-" +
237 (tsDate.getUTCDate() < 10 ? "0" : "") + tsDate.getUTCDate() + "T" +
238 (tsDate.getUTCHours() < 10 ? "0" : "") + tsDate.getUTCHours() + ":" +
239 (tsDate.getUTCMinutes() < 10 ? "0" : "") + tsDate.getUTCMinutes() + ":" +
240 (tsDate.getUTCSeconds() < 10 ? "0" : "") + tsDate.getUTCSeconds() + "Z";
241}
242
8389557a
RK
243function convertTrack(aTargetFormat) {
244 var out = "";
245 switch (aTargetFormat) {
246 case "gpx":
247 out += '<?xml version="1.0" encoding="UTF-8" ?>' + "\n\n";
248 out += '<gpx version="1.0" creator="Lantea" xmlns="http://www.topografix.com/GPX/1/0">' + "\n";
249 if (gTrack.length) {
250 out += ' <trk>' + "\n";
993fd081 251 out += ' <trkseg>' + "\n";
8389557a
RK
252 for (var i = 0; i < gTrack.length; i++) {
253 if (gTrack[i].beginSegment && i > 0) {
254 out += ' </trkseg>' + "\n";
255 out += ' <trkseg>' + "\n";
256 }
257 out += ' <trkpt lat="' + gTrack[i].coords.latitude + '" lon="' +
258 gTrack[i].coords.longitude + '">' + "\n";
259 if (gTrack[i].coords.altitude) {
260 out += ' <ele>' + gTrack[i].coords.altitude + '</ele>' + "\n";
261 }
262 out += ' <time>' + makeISOString(gTrack[i].time) + '</time>' + "\n";
263 out += ' </trkpt>' + "\n";
264 }
265 out += ' </trkseg>' + "\n";
266 out += ' </trk>' + "\n";
993fd081 267 }
8389557a
RK
268 out += '</gpx>' + "\n";
269 break;
270 case "json":
271 out = JSON.stringify(gTrack);
272 break;
273 default:
274 break;
275 }
276 return out;
277}
278
279function saveTrack() {
280 if (gTrack.length) {
281 var outDataURI = "data:application/gpx+xml," +
282 encodeURIComponent(convertTrack("gpx"));
99631a75
RK
283 window.open(outDataURI, 'GPX Track');
284 }
285}
993fd081 286
4b12da3a
RK
287function saveTrackDump() {
288 if (gTrack.length) {
8389557a
RK
289 var outDataURI = "data:application/json," +
290 encodeURIComponent(convertTrack("json"));
4b12da3a
RK
291 window.open(outDataURI, 'JSON dump');
292 }
293}
294
8389557a
RK
295function uploadTrack() {
296 // See http://wiki.openstreetmap.org/wiki/Api06#Uploading_traces
297 var trackBlob = new Blob([convertTrack("gpx")], { "type" : "application/gpx+xml" });
298 var formData = new FormData();
299 formData.append("file", trackBlob);
300 formData.append("description", "Track recorded via Lantea Maps");
301 //formData.append("tags", "");
302 formData.append("visibility", "private");
303 var XHR = new XMLHttpRequest();
304 XHR.onreadystatechange = function() {
8389557a
RK
305 if (XHR.readyState == 4 && XHR.status == 200) {
306 // so far so good
307 reportUploadStatus(true);
308 } else if (XHR.readyState == 4 && XHR.status != 200) {
309 // fetched the wrong page or network error...
310 reportUploadStatus(false);
311 }
312 };
c4d0569c
RK
313 XHR.open("POST", gOSMAPIURL + "api/0.6/gpx/create", true);
314 // Cross-Origin XHR doesn't allow username/password (HTTP Auth), so need to look into OAuth.
315 // But for now, we'll ask the user for entering credentials with this.
316 XHR.withCredentials = true;
8389557a
RK
317 try {
318 XHR.send(formData);
319 }
320 catch (e) {
321 reportUploadStatus(false, e);
322 }
323}
324
325function reportUploadStatus(aSuccess, aMessage) {
326 alert(aMessage ? aMessage : (aSuccess ? "success" : "failure"));
327}
328
993fd081
RK
329var gPrefs = {
330 objStore: "prefs",
331
332 get: function(aKey, aCallback) {
333 if (!mainDB)
334 return;
335 var transaction = mainDB.transaction([this.objStore]);
336 var request = transaction.objectStore(this.objStore).get(aKey);
337 request.onsuccess = function(event) {
338 aCallback(request.result, event);
339 };
340 request.onerror = function(event) {
341 // Errors can be handled here.
342 aCallback(undefined, event);
343 };
344 },
345
346 set: function(aKey, aValue, aCallback) {
347 if (!mainDB)
348 return;
349 var success = false;
d4ccddb8 350 var transaction = mainDB.transaction([this.objStore], "readwrite");
993fd081 351 var objStore = transaction.objectStore(this.objStore);
3610c22d 352 var request = objStore.put(aValue, aKey);
993fd081
RK
353 request.onsuccess = function(event) {
354 success = true;
355 if (aCallback)
356 aCallback(success, event);
357 };
358 request.onerror = function(event) {
359 // Errors can be handled here.
360 if (aCallback)
361 aCallback(success, event);
362 };
363 },
364
365 unset: function(aKey, aCallback) {
366 if (!mainDB)
367 return;
368 var success = false;
d4ccddb8 369 var transaction = mainDB.transaction([this.objStore], "readwrite");
993fd081
RK
370 var request = transaction.objectStore(this.objStore).delete(aKey);
371 request.onsuccess = function(event) {
372 success = true;
373 if (aCallback)
374 aCallback(success, event);
375 };
376 request.onerror = function(event) {
377 // Errors can be handled here.
378 if (aCallback)
379 aCallback(success, event);
380 }
381 }
382};
383
384var gTrackStore = {
385 objStore: "track",
386
387 getList: function(aCallback) {
388 if (!mainDB)
389 return;
390 var transaction = mainDB.transaction([this.objStore]);
391 var objStore = transaction.objectStore(this.objStore);
392 if (objStore.getAll) { // currently Mozilla-specific
393 objStore.getAll().onsuccess = function(event) {
394 aCallback(event.target.result);
395 };
396 }
397 else { // Use cursor (standard method).
398 var tPoints = [];
399 objStore.openCursor().onsuccess = function(event) {
400 var cursor = event.target.result;
401 if (cursor) {
402 tPoints.push(cursor.value);
403 cursor.continue();
404 }
405 else {
406 aCallback(tPoints);
407 }
408 };
409 }
410 },
411
412 push: function(aValue, aCallback) {
413 if (!mainDB)
414 return;
d4ccddb8 415 var transaction = mainDB.transaction([this.objStore], "readwrite");
993fd081
RK
416 var objStore = transaction.objectStore(this.objStore);
417 var request = objStore.add(aValue);
418 request.onsuccess = function(event) {
419 if (aCallback)
420 aCallback(request.result, event);
421 };
422 request.onerror = function(event) {
423 // Errors can be handled here.
424 if (aCallback)
425 aCallback(false, event);
426 };
427 },
428
429 clear: function(aCallback) {
430 if (!mainDB)
431 return;
432 var success = false;
d4ccddb8 433 var transaction = mainDB.transaction([this.objStore], "readwrite");
993fd081
RK
434 var request = transaction.objectStore(this.objStore).clear();
435 request.onsuccess = function(event) {
436 success = true;
437 if (aCallback)
438 aCallback(success, event);
439 };
440 request.onerror = function(event) {
441 // Errors can be handled here.
442 if (aCallback)
443 aCallback(success, event);
444 }
445 }
446};