diff --git a/index.html b/index.html index 593ea03..88f7cbd 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> @@ -41,6 +41,7 @@ + + + @@ -284,16 +327,20 @@ // get browser location when button "locate" is clicked $("#locate").on("click", function() { - if (navigator.geolocation) { - navigator.geolocation.getCurrentPosition(function(position) { - var item = { - lat: position.coords.latitude, - lon: position.coords.longitude - } - SL.Calendar.getGeoCode(item); - }); + if ( $("body").attr("use") == "offline" ) { + SL.App.geoLocate(); } else { - alert("Geolocation is not supported by this browser."); + if (navigator.geolocation) { + navigator.geolocation.getCurrentPosition(function(position) { + var item = { + lat: position.coords.latitude, + lon: position.coords.longitude + } + SL.Calendar.getGeoCode(item); + }); + } else { + alert("Geolocation is not supported by this browser."); + } } }); @@ -312,7 +359,7 @@ }); // "About" modal - $('#about').on('click', SL.Calendar.about); + SL.Calendar.about(); // "Generate" button in Settings $('#generate').on("click", function(e) { @@ -337,14 +384,14 @@ // "Reset" button in navbar menu bar $('#filterreset').on('click', function() { - if ( $("body").attr("use") == "offline" ) { + if ( $("body").attr("use") == "offline" && document.getElementById("loadpreset") != null ) { $("#grid").empty(); - if ( $('#calendar').data('isotope') ) $('#calendar').isotope('destroy'); } $('.actionlistfilter input').prop('checked', false); $('.filteroptions input').prop('checked', false); filters = {}; $('#calendar').isotope({ filter: '*' }); + if ( $('#calendar').data('isotope') ) $('#calendar').isotope('destroy'); }); /*-- @@ -403,6 +450,10 @@ }); }); + if ( $("body").attr("use") == "offline" ) { + SL.App.authorize(); + } + diff --git a/js/SL.App.js b/js/SL.App.js new file mode 100644 index 0000000..6dfb341 --- /dev/null +++ b/js/SL.App.js @@ -0,0 +1,336 @@ +/** + * @preserve Copyright (c) 2018 T. F. Raaion, www.sublunar.space + * License MIT: http://www.opensource.org/licenses/MIT + * + * SUBLUNAR ALMANAC + */ + +var SL = SL || {}; + +/** + * Offline App Functions + */ +SL.App = (function() { + + const fs = require('fs'); + const path = require('path'); + const http = require('http'); + const AutoUpdater = require( "nw-autoupdater" ); + const mid = require( "node-machine-id" ); + const crypto = require('crypto'); + const config = path.normalize(nw.App.dataPath+'/config.json'); + + var editJson = ''; + + var waiting = false; + + function downloadStatus(file, response) { + var num = parseInt($(".stoke span").text()); + $(".stoke span").html(++num); + if ( num == 4 ) { + waiting = false; + file.hasFiles = true; + writeHash(file, response); + } + } + + function downloadPreset(file, url, filename, response) { + var p = path.normalize(nw.App.dataPath+"/presets/"+filename); + waiting = true; + http.get(url, function(r) { + r.pipe(fs.createWriteStream(p)).on('finish', function () { + downloadStatus(file, response); + }); + }); + } + + function writeHash(file, response) { + if ( waiting == false) { + file.hash = response.hash; + fs.writeFile(config, JSON.stringify(file, null, 2), 'utf8', function(err) { + if(err) { + return console.log(err); + } else { + $('#caption .stoke').html('All set. Restarting application...'); + console.log(file); + window.setTimeout(chrome.runtime.reload,2000); + } + }); + } else { + console.log("still waiting for download..."); + } + } + + function authorize() { + $("#navigation").css({"visibility":"hidden"}); + if (!fs.existsSync(config)){ + fs.writeFile(config, JSON.stringify({"config" : "Sublunar Almanac"}), 'utf8', function(err) { + if(err) { + return console.log(err); + } else { + $('#caption .stoke').html('Created configuration file... Restarting application...'); + window.setTimeout(chrome.runtime.reload,2000); + } + }); + } else { + editJson = require(config); + let file = editJson; + if ( !file.hasOwnProperty("userEmail") ) { + if ( !navigator.onLine) { + $('#caption .stoke').html('You need to be online for activation...'); + return; + } + var email = prompt("Please enter the email address you registered with"); + file.userEmail = email; + /* + fs.writeFile(config, JSON.stringify(file, null, 2), 'utf8', function(err) { + if(err) { + return console.log(err); + } + }); + */ + } + if ( !file.hasOwnProperty("hash") ) { + if ( !navigator.onLine) { + $('#caption .stoke').html('You need to be online for activation...'); + return; + } + $.ajax({ + url : "http://release.sublunar.space/index.php", + type: "POST", + data: { + email: file.userEmail, + mid: mid.machineIdSync({original: true}) + }, + success:function(response) { + console.log(response); + if ( response.status == "authorized") { + var dir = path.normalize(nw.App.dataPath+"/presets"); + if (!fs.existsSync(dir)){ + fs.mkdirSync(dir); + } + if ( response.hasOwnProperty("files") ) { + var url = "http://release.sublunar.space/presets/"; + $('#caption .stoke').html('downloaded preset file 0 of 4'); + downloadPreset(file, url+response.files.file1, "modals.html", response); + downloadPreset(file, url+response.files.file2, "filtermenu.html", response); + downloadPreset(file, url+response.files.file3, "grid.html", response); + downloadPreset(file, url+response.files.file4, "ephemeris.json", response); + } else { + writeHash(file, response); + } + } else { + $('#caption .stoke').html('Sorry, there is something wrong with your authorization. Reset?'); + } + }, + error:function(){ + console.log("error"); + } + }); + } else { + const check = crypto.createHash('sha256'); + check.update(mid.machineIdSync({original: true})); + if ( file.hash == check.digest('hex') ) { + $("#navigation").css({"visibility":"visible"}); + if ( file.hasOwnProperty("hasFiles") && file.hasFiles == true ) + $("#filterreset").closest('li').before('
  • '); + if ( !navigator.onLine ) { + offlineUse(); + } else { + updateApp(); + } + } else { + $('#caption .stoke').html('Sorry, there is something wrong with your authorization. Reset?'); + } + } + } + } + + function reset() { + file = require(config); + if ( file.hasOwnProperty("userEmail") ) delete file.userEmail; + if ( file.hasOwnProperty("hash") ) delete file.hash; + if ( file.hasOwnProperty("hasFiles") ) delete file.hasFiles; + var presetfiles = ['/presets/modals.html', '/presets/filtermenu.html', '/presets/grid.html', '/presets/ephemeris.json', '/config.json']; + presetfiles.forEach( function(fn) { + var p = path.normalize(nw.App.dataPath+fn); + fs.unlink(p, (err) => { + if (err) throw err; + console.log(p+' was deleted'); + }); + }); + $('#caption .stoke').html('App has been reset. Reload?'); + fs.writeFile(config, JSON.stringify(file, null, 2), 'utf8', function(err) { + if(err) { + return console.log(err); + } + }); + $('#aboutSLC').modal('hide'); + } + + function geoLocate() { + $.ajax({ type : 'POST', data: '', url: "https://www.googleapis.com/geolocation/v1/geolocate?key=AIzaSyA7DG6Kz0VawkYVONoq7Yk8igTAQFGxGN4", success: function(data){ + var item = { + lat: data.location.lat, + lon: data.location.lng + } + SL.Calendar.getGeoCode(item); + } + }); + } + + /** + * loadPreset loads precalculated menubar, modals and hour grid + */ + function loadPreset() { + $('#caption .stoke').html('loading preset...please wait.'); + fs.readFile(path.normalize(nw.App.dataPath+"/presets/filtermenu.html"), "utf8", function(err, html) { + if (err) throw err; + $("#filterList").empty(); + $("#filterList").append(html); + }); + fs.readFile(path.normalize(nw.App.dataPath+"/presets/modals.html"), "utf8", function(err, html) { + if (err) throw err; + $("#modals").empty(); + $("#modals").append(html); + SL.Calendar.about(); + }); + fs.readFile(path.normalize(nw.App.dataPath+"/presets/grid.html"), "utf8", function(err, html) { + if (err) throw err; + $("#grid").empty(); + $("#grid").append(html); + $('#caption .stoke').empty(); + $('#moduleSelect input:checkbox').prop('checked', true); + $(".planetaryhour").each(function() { + if ( $(this).attr("ts") < (moment.utc().startOf("day").unix()) ) $(this).remove(); + }); + $('.planetaryhour').on('click', SL.Calendar.hourInfo); + }); + fs.readFile(path.normalize(nw.App.dataPath+"/presets/ephemeris.json"), "utf8", function(err, data) { + if (err) throw err; + var json = JSON.parse(data); + SL.Calendar.load(json.query); + }); + if ( $('#calendar').data('isotope') ) $('#calendar').isotope('destroy'); + } + + /** + * updateApp function updates the offline App + * from https://github.com/dsheiko/nw-autoupdater/blob/master/example/client-strategy-app/index.html + */ + async function updateApp() { + const updater = new AutoUpdater( require( "./package.json" ) ), + output = $("#caption .stoke"); + try { + // Update copy is running to replace app with the update + if ( updater.isSwapRequest() ) { + output.html("Swapping..."); + await updater.swap(); + output.html("Done."); + await updater.restart(); + return; + } + // Download/unpack update if any available + const rManifest = await updater.readRemoteManifest(); + const needsUpdate = await updater.checkNewVersion( rManifest ); + if ( !needsUpdate ) { + return; + } + if ( !confirm( "New release is available. Do you want to upgrade?" ) ) { + return; + } + // Subscribe for progress events + updater.on( "download", ( downloadSize, totalSize ) => { + output.html("Downloading "+Math.floor( downloadSize / totalSize * 100 )+"%" ); + }); + updater.on( "install", ( installFiles, totalFiles ) => { + output.html("Installing "+Math.floor( installFiles / totalFiles * 100 )+"%" ); + }); + reset(); + const updateFile = await updater.download( rManifest ); + await updater.unpack( updateFile ); + alert( `The application will automatically restart to finish installing the update` ); + await updater.restartToSwap(); + } catch ( e ) { + console.error( e ); + } + } + + function offlineUse() { + $(".autolocate label").html("Save Coordinates"); + $(".autolocate button").attr('id', 'savePlace').html("Save Place"); + $(".manuallocate label").html("Last Searched & Saved Places"); + $(".manuallocate input").remove(); + $(".manuallocate").append("
    "); + $('