don't actually contact remote server when track panel isn't opened (initialize to...
[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
41e2dba2 5// Get the best-available objects for indexedDB and requestAnimationFrame.
3d99a6fd 6window.indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
41e2dba2 7window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
993fd081 8
41e2dba2 9var mainDB;
16e4f664 10var gAppInitDone = false;
e1c3d337 11var firstRun = false;
7a549148 12var gUIHideCountdown = 0;
4b1d0915 13var gWaitCounter = 0;
026c4f46 14var gTrackUpdateInterval;
68afcd96 15var gAction, gActionLabel;
fd6126e2 16var authData = null, userData = null;
8f9306c5
RK
17var gBackendURL = "https://backend.lantea.kairo.at";
18var gAuthClientID = "lantea";
7a549148 19
b47b4a65 20window.onload = function() {
68afcd96
RK
21 gAction = document.getElementById("action");
22 gActionLabel = document.getElementById("actionlabel");
23
b47b4a65
RK
24 var mSel = document.getElementById("mapSelector");
25 for (var mapStyle in gMapStyles) {
26 var opt = document.createElement("option");
27 opt.value = mapStyle;
28 opt.text = gMapStyles[mapStyle].name;
29 mSel.add(opt, null);
30 }
23cd2dcc 31
4018d25a 32 var areas = document.getElementsByClassName("autoFade");
7a549148
RK
33 for (var i = 0; i <= areas.length - 1; i++) {
34 areas[i].addEventListener("mouseup", uiEvHandler, false);
35 areas[i].addEventListener("mousemove", uiEvHandler, false);
36 areas[i].addEventListener("mousedown", uiEvHandler, false);
37 areas[i].addEventListener("mouseout", uiEvHandler, false);
38
39 areas[i].addEventListener("touchstart", uiEvHandler, false);
40 areas[i].addEventListener("touchmove", uiEvHandler, false);
41 areas[i].addEventListener("touchend", uiEvHandler, false);
42 areas[i].addEventListener("touchcancel", uiEvHandler, false);
43 areas[i].addEventListener("touchleave", uiEvHandler, false);
44 }
45
1222624d
RK
46 document.getElementById("body").addEventListener("keydown", uiEvHandler, false);
47
8e901dce 48 if (navigator.platform.length == "") {
b91b74a7
RK
49 // For Firefox OS, don't display the "save" button.
50 // Do this by setting the debugHide class for testing in debug mode.
51 document.getElementById("saveTrackButton").classList.add("debugHide");
c4d0569c
RK
52 }
53
8f9306c5
RK
54 // Set backend URL in a way that it works for testing on localhost as well as
55 // both the lantea.kairo.at and lantea-dev.kairo.at deployments.
56 if (window.location.host == "localhost") {
57 gBackendURL = window.location.protocol + '//' + window.location.host + "/lantea-backend/";
58 }
59 else {
60 gBackendURL = window.location.protocol + '//' + "backend." + window.location.host + "/";
61 }
62 // Make sure to use a different login client ID for the -dev setup.
63 if (/\-dev\./.test(window.location.host)) {
64 gAuthClientID += "-dev";
65 }
66
867ee0af
RK
67 document.getElementById("libCloseButton").onclick = hideLibrary;
68
8f9306c5
RK
69 // Set up the login area.
70 document.getElementById("loginbtn").onclick = startLogin;
71 document.getElementById("logoutbtn").onclick = doLogout;
fd6126e2
RK
72 // Put in a logged-out state by default.
73 // Opening the track drawer will update this correctly.
74 displayLogout();
43255174 75
582d50fc
RK
76 gAction.addEventListener("dbinit-done", initMap, false);
77 gAction.addEventListener("mapinit-done", postInit, false);
78 console.log("starting DB init...");
993fd081 79 initDB();
582d50fc 80}
4b1d0915 81
582d50fc
RK
82function postInit(aEvent) {
83 gAction.removeEventListener(aEvent.type, postInit, false);
84 console.log("init done, draw map.");
85 gMapPrefsLoaded = true;
16e4f664 86 gAppInitDone = true;
14acbcf7
RK
87 //gMap.resizeAndDraw(); <-- HACK: This triggers bug 1001853, work around with a delay.
88 window.setTimeout(gMap.resizeAndDraw, 100);
582d50fc
RK
89 gActionLabel.textContent = "";
90 gAction.style.display = "none";
91 setTracking(document.getElementById("trackCheckbox"));
65946832 92 gPrefs.get("devicename", function(aValue) {
582d50fc 93 if (aValue) {
65946832 94 document.getElementById("uploadDevName").value = aValue;
4b1d0915 95 }
582d50fc 96 });
e1c3d337
RK
97 if (firstRun) {
98 showFirstRunDialog();
99 }
100 else {
101 gPrefs.get("lastInfoShown", function(aValue) {
102 if (!aValue || !parseInt(aValue) || parseInt(aValue) < 1) {
103 showInfoDialog();
104 }
105 });
106 }
107 gPrefs.set("lastInfoShown", 1);
b47b4a65
RK
108}
109
110window.onresize = function() {
ac6286bd 111 gMap.resizeAndDraw();
b47b4a65
RK
112}
113
8f9306c5 114function startLogin() {
fd6126e2
RK
115 if (!authData || !authData["state"]) {
116 // We have no oAuth state, try to fetch it and call ourselves again if it worked.
117 prepareLoginButton(function() {
118 if (authData && authData["state"]) {
119 startLogin();
120 }
121 else if (!userData) {
122 // Only warn if we didn't actually end up being logged in.
123 console.log("No OAuth state and fetching fails, client or server may be offline.");
124 }
125 });
126 return;
127 }
8f9306c5
RK
128 var authURL = authData["url"] + "authorize?response_type=code&client_id=" + gAuthClientID + "&scope=email" +
129 "&state=" + authData["state"] + "&redirect_uri=" + encodeURIComponent(getRedirectURI());
130 if (window.open(authURL, "KaiRoAuth", 'height=450,width=600')) {
131 console.log("Sign In window open.");
132 }
133 else {
134 console.log("Opening Sign In window failed.");
135 }
136}
137
138function getRedirectURI() {
67aadbe8 139 return window.location.protocol + '//' + window.location.host + window.location.pathname.replace("index.html", "") + "login.html";
8f9306c5
RK
140}
141
142function doLogout() {
143 fetchBackend("logout", "GET", null,
144 function(aResult, aStatus) {
145 if (aStatus < 400) {
146 prepareLoginButton();
147 }
148 else {
149 console.log("Backend issue trying to log out.");
150 }
151 },
152 {}
153 );
154}
155
156function prepareLoginButton(aCallback) {
157 fetchBackend("oauth_state", "GET", null,
158 function(aResult, aStatus) {
159 if (aStatus == 200) {
160 if (aResult["logged_in"]) {
161 userData = {
162 "email": aResult["email"],
163 "permissions": aResult["permissions"],
164 };
165 authData = null;
166 displayLogin();
167 }
168 else {
169 authData = {"state": aResult["state"], "url": aResult["url"]};
170 userData = null;
171 displayLogout();
172 }
173 }
174 else {
3c30699f 175 console.log("Backend error " + aStatus + " fetching OAuth state: " + aResult["message"]);
8f9306c5
RK
176 }
177 if (aCallback) { aCallback(); }
178 },
179 {}
180 );
181}
182
8f9306c5
RK
183function finishLogin(aCode, aState) {
184 if (aState == authData["state"]) {
185 fetchBackend("login?code=" + aCode + "&state=" + aState + "&redirect_uri=" + encodeURIComponent(getRedirectURI()), "GET", null,
186 function(aResult, aStatus) {
187 if (aStatus == 200) {
188 userData = {
189 "email": aResult["email"],
190 "permissions": aResult["permissions"],
191 };
192 displayLogin();
193 }
194 else {
195 console.log("Login error " + aStatus + ": " + aResult["message"]);
196 prepareLoginButton();
197 }
198 },
199 {}
200 );
201 }
202 else {
203 console.log("Login state did not match, not continuing with login.");
204 }
205}
206
207function displayLogin() {
208 document.getElementById("loginbtn").classList.add("hidden");
209 document.getElementById("logindesc").classList.add("hidden");
210 document.getElementById("username").classList.remove("hidden");
211 document.getElementById("username").textContent = userData.email;
212 document.getElementById("uploadTrackButton").disabled = false;
867ee0af 213 document.getElementById("libraryShowLine").classList.remove("hidden");
8f9306c5
RK
214 document.getElementById("logoutbtn").classList.remove("hidden");
215}
216
217function displayLogout() {
218 document.getElementById("logoutbtn").classList.add("hidden");
219 document.getElementById("username").classList.add("hidden");
220 document.getElementById("username").textContent = "";
221 document.getElementById("uploadTrackButton").disabled = true;
867ee0af 222 document.getElementById("libraryShowLine").classList.add("hidden");
8f9306c5
RK
223 document.getElementById("loginbtn").classList.remove("hidden");
224 document.getElementById("logindesc").classList.remove("hidden");
225}
226
582d50fc 227function initDB(aEvent) {
993fd081 228 // Open DB.
582d50fc
RK
229 if (aEvent)
230 gAction.removeEventListener(aEvent.type, initDB, false);
1222624d 231 var request = window.indexedDB.open("MainDB-lantea", 2);
993fd081
RK
232 request.onerror = function(event) {
233 // Errors can be handled here. Error codes explain in:
234 // https://developer.mozilla.org/en/IndexedDB/IDBDatabaseException#Constants
915d4271
RK
235 if (gDebug)
236 console.log("error opening mainDB: " + event.target.errorCode);
993fd081
RK
237 };
238 request.onsuccess = function(event) {
993fd081 239 mainDB = request.result;
582d50fc
RK
240 var throwEv = new CustomEvent("dbinit-done");
241 gAction.dispatchEvent(throwEv);
993fd081
RK
242 };
243 request.onupgradeneeded = function(event) {
244 mainDB = request.result;
a8634d37 245 var ver = mainDB.version || 0; // version is empty string for a new DB
915d4271
RK
246 if (gDebug)
247 console.log("mainDB has version " + ver + ", upgrade needed.");
248 if (!mainDB.objectStoreNames.contains("prefs")) {
a8634d37
RK
249 // Create a "prefs" objectStore.
250 var prefsStore = mainDB.createObjectStore("prefs");
e1c3d337 251 firstRun = true;
915d4271
RK
252 }
253 if (!mainDB.objectStoreNames.contains("track")) {
a8634d37
RK
254 // Create a "track" objectStore.
255 var trackStore = mainDB.createObjectStore("track", {autoIncrement: true});
256 }
915d4271 257 if (!mainDB.objectStoreNames.contains("tilecache")) {
a8634d37
RK
258 // Create a "tilecache" objectStore.
259 var tilecacheStore = mainDB.createObjectStore("tilecache");
260 }
993fd081
RK
261 mainDB.onversionchange = function(event) {
262 mainDB.close();
263 mainDB = undefined;
264 initDB();
265 };
266 };
267}
268
7a549148
RK
269function showUI() {
270 if (gUIHideCountdown <= 0) {
4018d25a 271 var areas = document.getElementsByClassName('autoFade');
7a549148
RK
272 for (var i = 0; i <= areas.length - 1; i++) {
273 areas[i].classList.remove("hidden");
274 }
275 setTimeout(maybeHideUI, 1000);
276 }
277 gUIHideCountdown = 5;
278}
279
280function maybeHideUI() {
281 gUIHideCountdown--;
282 if (gUIHideCountdown <= 0) {
4018d25a 283 var areas = document.getElementsByClassName('autoFade');
7a549148
RK
284 for (var i = 0; i <= areas.length - 1; i++) {
285 areas[i].classList.add("hidden");
286 }
287 }
288 else {
289 setTimeout(maybeHideUI, 1000);
290 }
291}
292
026c4f46
RK
293function updateTrackInfo() {
294 document.getElementById("trackLengthNum").textContent = calcTrackLength().toFixed(1);
295 var duration = calcTrackDuration();
296 var durationM = Math.round(duration/60);
297 var durationH = Math.floor(durationM/60); durationM = durationM - durationH * 60;
298 document.getElementById("trackDurationH").style.display = durationH ? "inline" : "none";
299 document.getElementById("trackDurationHNum").textContent = durationH;
300 document.getElementById("trackDurationMNum").textContent = durationM;
301}
302
993fd081
RK
303function toggleTrackArea() {
304 var fs = document.getElementById("trackArea");
123b3142 305 if (fs.classList.contains("hidden")) {
4018d25a 306 prepareLoginButton();
123b3142 307 fs.classList.remove("hidden");
7a549148 308 showUI();
026c4f46 309 gTrackUpdateInterval = setInterval(updateTrackInfo, 1000);
993fd081
RK
310 }
311 else {
026c4f46 312 clearInterval(gTrackUpdateInterval);
123b3142 313 fs.classList.add("hidden");
993fd081
RK
314 }
315}
316
b47b4a65 317function toggleSettings() {
993fd081 318 var fs = document.getElementById("settingsArea");
123b3142
RK
319 if (fs.classList.contains("hidden")) {
320 fs.classList.remove("hidden");
7a549148 321 showUI();
b47b4a65
RK
322 }
323 else {
123b3142 324 fs.classList.add("hidden");
b47b4a65
RK
325 }
326}
99631a75 327
c5378747
RK
328function toggleFullscreen() {
329 if ((document.fullScreenElement && document.fullScreenElement !== null) ||
330 (document.mozFullScreenElement && document.mozFullScreenElement !== null) ||
331 (document.webkitFullScreenElement && document.webkitFullScreenElement !== null)) {
332 if (document.cancelFullScreen) {
333 document.cancelFullScreen();
334 } else if (document.mozCancelFullScreen) {
335 document.mozCancelFullScreen();
336 } else if (document.webkitCancelFullScreen) {
337 document.webkitCancelFullScreen();
338 }
339 }
340 else {
341 var elem = document.getElementById("body");
342 if (elem.requestFullScreen) {
343 elem.requestFullScreen();
344 } else if (elem.mozRequestFullScreen) {
345 elem.mozRequestFullScreen();
346 } else if (elem.webkitRequestFullScreen) {
347 elem.webkitRequestFullScreen();
348 }
349 }
350}
351
43255174 352function showUploadDialog() {
6201b112 353 var dia = document.getElementById("trackDialogArea");
43255174
RK
354 var areas = dia.children;
355 for (var i = 0; i <= areas.length - 1; i++) {
356 areas[i].style.display = "none";
357 }
358 document.getElementById("uploadDialog").style.display = "block";
359 document.getElementById("uploadTrackButton").disabled = true;
360 dia.classList.remove("hidden");
361}
362
e1c3d337
RK
363function cancelTrackDialog() {
364 document.getElementById("trackDialogArea").classList.add("hidden");
365 document.getElementById("uploadTrackButton").disabled = false;
366}
367
ecde0af2
RK
368function showGLWarningDialog() {
369 var dia = document.getElementById("dialogArea");
370 var areas = dia.children;
371 for (var i = 0; i <= areas.length - 1; i++) {
372 areas[i].style.display = "none";
373 }
374 document.getElementById("noGLwarning").style.display = "block";
375 dia.classList.remove("hidden");
376}
377
e1c3d337
RK
378function showFirstRunDialog() {
379 var dia = document.getElementById("dialogArea");
380 var areas = dia.children;
381 for (var i = 0; i <= areas.length - 1; i++) {
382 areas[i].style.display = "none";
383 }
384 document.getElementById("firstRunIntro").style.display = "block";
385 dia.classList.remove("hidden");
386}
387
388function closeDialog() {
389 document.getElementById("dialogArea").classList.add("hidden");
390}
391
392function showInfoDialog() {
393 var dia = document.getElementById("dialogArea");
394 var areas = dia.children;
395 for (var i = 0; i <= areas.length - 1; i++) {
396 areas[i].style.display = "none";
397 }
398 document.getElementById("infoDialog").style.display = "block";
399 dia.classList.remove("hidden");
43255174
RK
400}
401
7a549148
RK
402var uiEvHandler = {
403 handleEvent: function(aEvent) {
404 var touchEvent = aEvent.type.indexOf('touch') != -1;
405
406 switch (aEvent.type) {
407 case "mousedown":
408 case "touchstart":
409 case "mousemove":
410 case "touchmove":
411 case "mouseup":
412 case "touchend":
1222624d 413 case "keydown":
7a549148
RK
414 showUI();
415 break;
416 }
417 }
418};
419
8389557a
RK
420function setUploadField(aField) {
421 switch (aField.id) {
65946832
RK
422 case "uploadDevName":
423 gPrefs.set("devicename", aField.value);
8389557a
RK
424 break;
425 }
426}
427
99631a75
RK
428function makeISOString(aTimestamp) {
429 // ISO time format is YYYY-MM-DDTHH:mm:ssZ
430 var tsDate = new Date(aTimestamp);
362a6833 431 // Note that .getUTCMonth() returns a number between 0 and 11 (0 for January)!
99631a75 432 return tsDate.getUTCFullYear() + "-" +
362a6833 433 (tsDate.getUTCMonth() < 9 ? "0" : "") + (tsDate.getUTCMonth() + 1 ) + "-" +
99631a75
RK
434 (tsDate.getUTCDate() < 10 ? "0" : "") + tsDate.getUTCDate() + "T" +
435 (tsDate.getUTCHours() < 10 ? "0" : "") + tsDate.getUTCHours() + ":" +
436 (tsDate.getUTCMinutes() < 10 ? "0" : "") + tsDate.getUTCMinutes() + ":" +
437 (tsDate.getUTCSeconds() < 10 ? "0" : "") + tsDate.getUTCSeconds() + "Z";
438}
439
8389557a
RK
440function convertTrack(aTargetFormat) {
441 var out = "";
442 switch (aTargetFormat) {
443 case "gpx":
444 out += '<?xml version="1.0" encoding="UTF-8" ?>' + "\n\n";
445 out += '<gpx version="1.0" creator="Lantea" xmlns="http://www.topografix.com/GPX/1/0">' + "\n";
446 if (gTrack.length) {
447 out += ' <trk>' + "\n";
993fd081 448 out += ' <trkseg>' + "\n";
8389557a
RK
449 for (var i = 0; i < gTrack.length; i++) {
450 if (gTrack[i].beginSegment && i > 0) {
451 out += ' </trkseg>' + "\n";
452 out += ' <trkseg>' + "\n";
453 }
454 out += ' <trkpt lat="' + gTrack[i].coords.latitude + '" lon="' +
455 gTrack[i].coords.longitude + '">' + "\n";
456 if (gTrack[i].coords.altitude) {
457 out += ' <ele>' + gTrack[i].coords.altitude + '</ele>' + "\n";
458 }
459 out += ' <time>' + makeISOString(gTrack[i].time) + '</time>' + "\n";
460 out += ' </trkpt>' + "\n";
461 }
462 out += ' </trkseg>' + "\n";
463 out += ' </trk>' + "\n";
993fd081 464 }
8389557a
RK
465 out += '</gpx>' + "\n";
466 break;
467 case "json":
468 out = JSON.stringify(gTrack);
469 break;
470 default:
471 break;
472 }
473 return out;
474}
475
476function saveTrack() {
477 if (gTrack.length) {
478 var outDataURI = "data:application/gpx+xml," +
479 encodeURIComponent(convertTrack("gpx"));
99631a75
RK
480 window.open(outDataURI, 'GPX Track');
481 }
482}
993fd081 483
4b12da3a
RK
484function saveTrackDump() {
485 if (gTrack.length) {
8389557a
RK
486 var outDataURI = "data:application/json," +
487 encodeURIComponent(convertTrack("json"));
4b12da3a
RK
488 window.open(outDataURI, 'JSON dump');
489 }
490}
491
8389557a 492function uploadTrack() {
6ddefbf9 493 // Hide all areas in the dialog.
6201b112 494 var dia = document.getElementById("trackDialogArea");
43255174
RK
495 var areas = dia.children;
496 for (var i = 0; i <= areas.length - 1; i++) {
497 areas[i].style.display = "none";
498 }
6ddefbf9
RK
499 // Reset all the fields in the status area.
500 document.getElementById("uploadStatusCloseButton").disabled = true;
501 document.getElementById("uploadInProgress").style.display = "block";
502 document.getElementById("uploadSuccess").style.display = "none";
d0c62ee0 503 document.getElementById("uploadFailed").style.display = "none";
6ddefbf9 504 document.getElementById("uploadError").style.display = "none";
d0c62ee0 505 document.getElementById("uploadErrorMsg").textContent = "";
6ddefbf9 506 // Now show the status area.
43255174
RK
507 document.getElementById("uploadStatus").style.display = "block";
508
6201b112 509 // Assemble field to post to the backend.
8389557a 510 var formData = new FormData();
6201b112 511 formData.append("jsondata", convertTrack("json"));
43255174 512 var desc = document.getElementById("uploadDesc").value;
6201b112 513 formData.append("comment",
43255174 514 desc.length ? desc : "Track recorded via Lantea Maps");
65946832
RK
515 formData.append("devicename",
516 document.getElementById("uploadDevName").value);
6201b112
RK
517 formData.append("public",
518 document.getElementById("uploadPublic").value);
519
520 fetchBackend("save_track", "POST", formData,
521 function(aResult, aStatusCode) {
522 if (aStatusCode >= 400) {
523 reportUploadStatus(false, aResult);
da6dad24 524 }
5e9f4a24 525 else if (aResult["id"]) {
da6dad24
RK
526 reportUploadStatus(true);
527 }
5e9f4a24
RK
528 else { // If no ID is returned, we assume a general error.
529 reportUploadStatus(false);
530 }
da6dad24
RK
531 }
532 );
8389557a
RK
533}
534
5e9f4a24 535function reportUploadStatus(aSuccess, aResponse) {
43255174
RK
536 document.getElementById("uploadStatusCloseButton").disabled = false;
537 document.getElementById("uploadInProgress").style.display = "none";
538 if (aSuccess) {
539 document.getElementById("uploadSuccess").style.display = "block";
540 }
b5291db1 541 else if (aResponse && aResponse["message"]) {
5e9f4a24
RK
542 document.getElementById("uploadErrorMsg").textContent = aResponse["message"];
543 if (aResponse["errortype"]) {
544 document.getElementById("uploadErrorMsg").textContent += " (" + aResponse["errortype"] + ")";
545 }
546 document.getElementById("uploadError").style.display = "block";
547 }
548 else if (aResponse) {
549 document.getElementById("uploadErrorMsg").textContent = aResponse;
43255174
RK
550 document.getElementById("uploadError").style.display = "block";
551 }
552 else {
553 document.getElementById("uploadFailed").style.display = "block";
554 }
8389557a
RK
555}
556
993fd081
RK
557var gPrefs = {
558 objStore: "prefs",
559
560 get: function(aKey, aCallback) {
561 if (!mainDB)
562 return;
563 var transaction = mainDB.transaction([this.objStore]);
564 var request = transaction.objectStore(this.objStore).get(aKey);
565 request.onsuccess = function(event) {
566 aCallback(request.result, event);
567 };
568 request.onerror = function(event) {
569 // Errors can be handled here.
570 aCallback(undefined, event);
571 };
572 },
573
574 set: function(aKey, aValue, aCallback) {
575 if (!mainDB)
576 return;
577 var success = false;
d4ccddb8 578 var transaction = mainDB.transaction([this.objStore], "readwrite");
993fd081 579 var objStore = transaction.objectStore(this.objStore);
3610c22d 580 var request = objStore.put(aValue, aKey);
993fd081
RK
581 request.onsuccess = function(event) {
582 success = true;
583 if (aCallback)
584 aCallback(success, event);
585 };
586 request.onerror = function(event) {
587 // Errors can be handled here.
588 if (aCallback)
589 aCallback(success, event);
590 };
591 },
592
593 unset: function(aKey, aCallback) {
594 if (!mainDB)
595 return;
596 var success = false;
d4ccddb8 597 var transaction = mainDB.transaction([this.objStore], "readwrite");
993fd081
RK
598 var request = transaction.objectStore(this.objStore).delete(aKey);
599 request.onsuccess = function(event) {
600 success = true;
601 if (aCallback)
602 aCallback(success, event);
603 };
604 request.onerror = function(event) {
605 // Errors can be handled here.
606 if (aCallback)
607 aCallback(success, event);
608 }
609 }
610};
611
612var gTrackStore = {
613 objStore: "track",
614
615 getList: function(aCallback) {
616 if (!mainDB)
617 return;
618 var transaction = mainDB.transaction([this.objStore]);
619 var objStore = transaction.objectStore(this.objStore);
620 if (objStore.getAll) { // currently Mozilla-specific
621 objStore.getAll().onsuccess = function(event) {
622 aCallback(event.target.result);
623 };
624 }
625 else { // Use cursor (standard method).
626 var tPoints = [];
627 objStore.openCursor().onsuccess = function(event) {
628 var cursor = event.target.result;
629 if (cursor) {
630 tPoints.push(cursor.value);
631 cursor.continue();
632 }
633 else {
634 aCallback(tPoints);
635 }
636 };
637 }
638 },
639
6ddefbf9
RK
640 getListStepped: function(aCallback) {
641 if (!mainDB)
642 return;
643 var transaction = mainDB.transaction([this.objStore]);
644 var objStore = transaction.objectStore(this.objStore);
645 // Use cursor in reverse direction (so we get the most recent position first)
646 objStore.openCursor(null, "prev").onsuccess = function(event) {
647 var cursor = event.target.result;
648 if (cursor) {
649 aCallback(cursor.value);
650 cursor.continue();
651 }
652 else {
653 aCallback(null);
654 }
655 };
656 },
657
993fd081
RK
658 push: function(aValue, aCallback) {
659 if (!mainDB)
660 return;
d4ccddb8 661 var transaction = mainDB.transaction([this.objStore], "readwrite");
993fd081
RK
662 var objStore = transaction.objectStore(this.objStore);
663 var request = objStore.add(aValue);
664 request.onsuccess = function(event) {
665 if (aCallback)
666 aCallback(request.result, event);
667 };
668 request.onerror = function(event) {
669 // Errors can be handled here.
670 if (aCallback)
671 aCallback(false, event);
672 };
673 },
674
675 clear: function(aCallback) {
676 if (!mainDB)
677 return;
678 var success = false;
d4ccddb8 679 var transaction = mainDB.transaction([this.objStore], "readwrite");
993fd081
RK
680 var request = transaction.objectStore(this.objStore).clear();
681 request.onsuccess = function(event) {
682 success = true;
683 if (aCallback)
684 aCallback(success, event);
685 };
686 request.onerror = function(event) {
687 // Errors can be handled here.
688 if (aCallback)
689 aCallback(success, event);
690 }
691 }
692};
8f9306c5
RK
693
694function fetchBackend(aEndpoint, aMethod, aSendData, aCallback, aCallbackForwards) {
695 var XHR = new XMLHttpRequest();
696 XHR.onreadystatechange = function() {
697 if (XHR.readyState == 4) {
698 // State says we are fully loaded.
699 var result = {};
700 if (XHR.getResponseHeader("Content-Type") == "application/json") {
701 // Got a JSON object, see if we have success.
65946832
RK
702 try {
703 result = JSON.parse(XHR.responseText);
704 }
705 catch (e) {
706 console.log(e);
707 result = {"error": e,
708 "message": XHR.responseText};
709 }
8f9306c5
RK
710 }
711 else {
712 result = XHR.responseText;
713 }
714 aCallback(result, XHR.status, aCallbackForwards);
715 }
716 };
717 XHR.open(aMethod, gBackendURL + aEndpoint, true);
87be1057 718 XHR.withCredentials = "true";
8f9306c5
RK
719 //XHR.setRequestHeader("Accept", "application/json");
720 try {
721 XHR.send(aSendData); // Send actual form data.
722 }
723 catch (e) {
724 aCallback(e, 500, aCallbackForwards);
725 }
726}