-
-
LY
-
Name
-
Type
-
Mapped Value
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
LY
+
Name
+
Type
+
Mapped Value
+
+
+
+
-
+
diff --git a/journal examples.txt b/journal examples.txt
index 7235a9e..333b050 100644
--- a/journal examples.txt
+++ b/journal examples.txt
@@ -32,6 +32,12 @@ DETAILED SURFACE SCAN - MAPPED BODY
{ "timestamp":"2023-05-08T19:22:20Z", "event":"SAAScanComplete", "BodyName":"LHS 551 1", "SystemAddress":22660650050977, "BodyID":1, "ProbesUsed":8, "EfficiencyTarget":8 }
{ "timestamp":"2023-05-08T19:22:21Z", "event":"Scan", "ScanType":"Detailed", "BodyName":"LHS 551 1", "BodyID":1, "Parents":[ {"Star":0} ], "StarSystem":"LHS 551", "SystemAddress":22660650050977, "DistanceFromArrivalLS":578.392122, "TidalLock":false, "TerraformState":"", "PlanetClass":"Rocky ice body", "Atmosphere":"helium atmosphere", "AtmosphereType":"Helium", "AtmosphereComposition":[ { "Name":"Helium", "Percent":89.334976 }, { "Name":"Hydrogen", "Percent":8.427828 }, { "Name":"Neon", "Percent":2.237205 } ], "Volcanism":"major water geysers volcanism", "MassEM":4.158691, "Radius":10698825.000000, "SurfaceGravity":14.480845, "SurfaceTemperature":58.117901, "SurfacePressure":67337.343750, "Landable":false, "Composition":{ "Ice":0.403397, "Rock":0.397748, "Metal":0.198856 }, "SemiMajorAxis":173410028219.223022, "Eccentricity":0.000081, "OrbitalInclination":-0.013599, "Periapsis":290.186625, "OrbitalPeriod":78148038.387299, "AscendingNode":-3.343060, "MeanAnomaly":332.810795, "RotationPeriod":157634.536311, "AxialTilt":0.224570, "WasDiscovered":true, "WasMapped":true }
+TERRAFORM STATES - TERRAFORMED
+{ "timestamp":"2023-04-27T21:32:51Z", "event":"Scan", "ScanType":"NavBeaconDetail", "BodyName":"Reagan's Legacy", "BodyID":3, "Parents":[ {"Star":0} ], "StarSystem":"Delta Pavonis", "SystemAddress":633608344274, "DistanceFromArrivalLS":688.627081, "TidalLock":false, "TerraformState":"Terraformed", "PlanetClass":"Earthlike body", "Atmosphere":"thick atmosphere", "AtmosphereType":"EarthLike", "AtmosphereComposition":[ { "Name":"Nitrogen", "Percent":96.026627 }, { "Name":"Oxygen", "Percent":3.704388 }, { "Name":"Water", "Percent":0.253592 } ], "Volcanism":"", "MassEM":1.010000, "Radius":6151805.500000, "SurfaceGravity":10.637157, "SurfaceTemperature":318.681152, "SurfacePressure":683817.312500, "Landable":false, "Composition":{ "Ice":0.000000, "Rock":0.700000, "Metal":0.300000 }, "SemiMajorAxis":206445205211.639404, "Eccentricity":0.000000, "OrbitalInclination":2.800000, "Periapsis":197.927366, "OrbitalPeriod":17798399.925232, "AscendingNode":0.000000, "MeanAnomaly":259.923139, "RotationPeriod":133722.362175, "AxialTilt":0.470025, "WasDiscovered":false, "WasMapped":true }
+
+TERRAFORM STATES - TERRAFORMABLE
+{ "timestamp":"2023-04-15T20:02:16Z", "event":"Scan", "ScanType":"Detailed", "BodyName":"HIP 24065 3", "BodyID":16, "Parents":[ {"Null":10}, {"Star":0} ], "StarSystem":"HIP 24065", "SystemAddress":216635803987, "DistanceFromArrivalLS":873.284729, "TidalLock":false, "TerraformState":"Terraformable", "PlanetClass":"High metal content body", "Atmosphere":"hot thick carbon dioxide atmosphere", "AtmosphereType":"CarbonDioxide", "AtmosphereComposition":[ { "Name":"CarbonDioxide", "Percent":95.819931 }, { "Name":"Nitrogen", "Percent":3.221208 }, { "Name":"SulphurDioxide", "Percent":0.958199 } ], "Volcanism":"minor silicate vapour geysers volcanism", "MassEM":1.511658, "Radius":6875047.500000, "SurfaceGravity":12.747104, "SurfaceTemperature":806.785522, "SurfacePressure":24143846.000000, "Landable":false, "Composition":{ "Ice":0.000011, "Rock":0.663949, "Metal":0.335113 }, "SemiMajorAxis":20969787836.074829, "Eccentricity":0.097795, "OrbitalInclination":8.521953, "Periapsis":8.870370, "OrbitalPeriod":11576774.120331, "AscendingNode":160.796119, "MeanAnomaly":5.280380, "RotationPeriod":7718705.210996, "AxialTilt":-0.239401, "Rings":[ { "Name":"HIP 24065 3 A Ring", "RingClass":"eRingClass_Rocky", "MassMT":9.8768e+08, "InnerRad":1.1901e+07, "OuterRad":3.9954e+07 } ], "ReserveLevel":"PristineResources", "WasDiscovered":true, "WasMapped":true }
+
START HYPERSPACE JUMP
{ "timestamp":"2023-05-08T19:11:12Z", "event":"StartJump", "JumpType":"Hyperspace", "StarSystem":"LHS 6427", "SystemAddress":22660650116513, "StarClass":"M" }
diff --git a/src/Eurostile-Roman.woff b/src/assets/Eurostile-Roman.woff
similarity index 100%
rename from src/Eurostile-Roman.woff
rename to src/assets/Eurostile-Roman.woff
diff --git a/src/Eurostile-Roman.woff2 b/src/assets/Eurostile-Roman.woff2
similarity index 100%
rename from src/Eurostile-Roman.woff2
rename to src/assets/Eurostile-Roman.woff2
diff --git a/src/index.css b/src/assets/index.css
similarity index 98%
rename from src/index.css
rename to src/assets/index.css
index de5bb08..d004c48 100644
--- a/src/index.css
+++ b/src/assets/index.css
@@ -18,6 +18,10 @@ body {
opacity: 0;
}
+.hidden {
+ display: none;
+}
+
.system {
margin-top: 1px;
margin-bottom: 1px;
diff --git a/src/assets/ldom.dev.js b/src/assets/ldom.dev.js
new file mode 100644
index 0000000..9ea97d2
--- /dev/null
+++ b/src/assets/ldom.dev.js
@@ -0,0 +1,617 @@
+(function() {
+ var LDOMCache = {
+ eventListenerCounter: 0,
+ eventListenerFunctions: {},
+ eventListenerFunctionsIds: {},
+ functionsUsed: {}
+ };
+
+ function $(input) {
+ if (typeof input === "string" && input[0] === "<" && input[input.length - 1] === ">") {
+ return new LDOMObject(document.createElement(input.substring(1, input.length - 1)));
+ } else if (input === null || !input) {
+ return new LDOMObject([]);
+ } else if (input._LDOM) {
+ return input;
+ } else if (input === window) {
+ return new LDOMWindowObject();
+ } else if (input.nodeType > 0) {
+ return new LDOMObject(input);
+ } else if (typeof input !== "string" && typeof input.length !== "undefined") {
+ var elements = [];
+ for (var i = 0; i < input.length; i++) {
+ var obj = $(input[i]);
+ if (obj.length > 0) {
+ elements.push(obj);
+ }
+ }
+ return new LDOMObject(elements);
+ } else {
+ return $(document).find(input);
+ }
+ }
+ window.LDOM = $;
+ window.$ = window.$ || $;
+ window.getLDOMFunctionUsage = function() {
+ var obj = $("
");
+ var keys = Object.keys(Object.getPrototypeOf(obj));
+ var unused = [];
+ for (var i = 0; i < keys.length; i++) {
+ if (keys[i][0] !== "_" && !LDOMCache.functionsUsed[keys[i]] && typeof obj[keys[i]] === "function") {
+ unused.push(keys[i]);
+ }
+ }
+ return {
+ used: Object.keys(LDOMCache.functionsUsed),
+ unused: unused
+ };
+ };
+
+ function LDOMObject(elem) {
+ this._LDOM = true;
+ if (Array.isArray(elem)) {
+ this.length = elem.length;
+ this._elements = elem;
+ } else {
+ this.length = 1;
+ this._node = elem;
+ }
+ }
+
+ LDOMObject.prototype.each = each;
+ LDOMObject.prototype.equals = equals;
+ LDOMObject.prototype.find = find;
+ LDOMObject.prototype.get = get;
+ LDOMObject.prototype.on = on;
+ LDOMObject.prototype.off = off;
+ LDOMObject.prototype.trigger = trigger;
+ LDOMObject.prototype.hide = hide;
+ LDOMObject.prototype.show = show;
+ LDOMObject.prototype.toggle = toggle;
+ LDOMObject.prototype.css = css;
+ LDOMObject.prototype.html = html;
+ LDOMObject.prototype.outerHTML = outerHTML;
+ LDOMObject.prototype.text = text;
+ LDOMObject.prototype.prop = prop;
+ LDOMObject.prototype.attr = attr;
+ LDOMObject.prototype.removeAttr = removeAttr;
+ LDOMObject.prototype.addClass = addClass;
+ LDOMObject.prototype.removeClass = removeClass;
+ LDOMObject.prototype.hasClass = hasClass;
+ LDOMObject.prototype.parent = parent;
+ LDOMObject.prototype.children = children;
+ LDOMObject.prototype.filter = filter;
+ LDOMObject.prototype.first = first;
+ LDOMObject.prototype.last = last;
+ LDOMObject.prototype.eq = eq;
+ LDOMObject.prototype.insertAfter = insertAfter;
+ LDOMObject.prototype.insertBefore = insertBefore;
+ LDOMObject.prototype.appendChild = appendChild;
+ LDOMObject.prototype.prependChild = prependChild;
+ LDOMObject.prototype.remove = remove;
+
+ function LDOMWindowObject() {
+ this._LDOM = true;
+ this.length = 1;
+ this._node = window;
+ }
+
+ LDOMWindowObject.prototype.each = each;
+ LDOMWindowObject.prototype.equals = equals;
+ LDOMWindowObject.prototype.get = get;
+ LDOMWindowObject.prototype.on = on;
+ LDOMWindowObject.prototype.off = off;
+ LDOMWindowObject.prototype.trigger = trigger;
+ LDOMWindowObject.prototype.prop = prop;
+ LDOMWindowObject.prototype.attr = attr;
+ LDOMWindowObject.prototype.removeAttr = removeAttr;
+
+ function each(funct, reverse) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ var elementsArray = getElementsArray(this);
+ var start = reverse ? elementsArray.length - 1 : 0;
+ var change = reverse ? -1 : 1;
+ var end = (reverse ? 0 : elementsArray.length - 1) + change;
+ for (var i = start; i !== end; i += change) {
+ var shouldContinue = funct.apply(elementsArray[i], [i]);
+ if (shouldContinue === false) {
+ break;
+ }
+ }
+ return this;
+ }
+
+ function equals(ldomObject) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ if (this.length !== ldomObject.length) {
+ return false;
+ }
+ var thisElementsArray = getElementsArray(this);
+ var otherElementsArray = getElementsArray(ldomObject);
+ if (thisElementsArray.length !== otherElementsArray.length) {
+ return false;
+ }
+ var otherNodes = [];
+ for (var i = 0; i < otherElementsArray.length; i++) {
+ otherNodes.push(otherElementsArray[i]._node);
+ }
+ for (var i = 0; i < thisElementsArray.length; i++) {
+ if (otherNodes.indexOf(thisElementsArray[i]._node) === -1) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function find(selector) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ var output = [];
+ this.each(function() {
+ var elems = this._node.querySelectorAll(selector);
+ for (var i = 0; i < elems.length; i++) {
+ output.push(elems[i]);
+ }
+ });
+ return $(output);
+ }
+
+ function get(index) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ if (!isDefined(index)) {
+ var nodes = [];
+ this.each(function() {
+ nodes.push(this._node);
+ });
+ return nodes;
+ } else {
+ var elementsArray = getElementsArray(this);
+ if (index < 0) {
+ index = elementsArray.length + index;
+ }
+ if (!isDefined(elementsArray[index])) {
+ return null;
+ }
+ return elementsArray[index]._node;
+ }
+ }
+
+ function on(eventName, handler) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ var eventId = ++LDOMCache.eventListenerCounter;
+ var handlerWrapper = function(evt) {
+ handler.apply($(this), [evt]);
+ };
+ this.each(function() {
+ this._node.addEventListener(eventName, handlerWrapper);
+ var eventIds = this._node._LDOMEvents || [];
+ eventIds.push(eventId);
+ this._node._LDOMEvents = eventIds;
+ });
+ if (!LDOMCache.eventListenerFunctions[eventName]) {
+ LDOMCache.eventListenerFunctions[eventName] = {};
+ }
+ LDOMCache.eventListenerFunctions[eventName][eventId] = {
+ funct: handlerWrapper,
+ count: this.length
+ };
+ LDOMCache.eventListenerFunctionsIds[eventId] = {
+ name: eventName
+ };
+ return eventId;
+ }
+
+ function off(eventName) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ if (!isDefined(eventName)) {
+ this.each(function() {
+ var eventIds = this._node._LDOMEvents || [];
+ for (var i = eventIds.length - 1; i >= 0; i--) {
+ this.off(eventIds[i]);
+ }
+ });
+ } else if (typeof eventName === "string") {
+ this.each(function() {
+ if (!LDOMCache.eventListenerFunctions[eventName]) {
+ return;
+ }
+ var eventIds = this._node._LDOMEvents || [];
+ for (var i = eventIds.length - 1; i >= 0; i--) {
+ if (LDOMCache.eventListenerFunctionsIds[eventIds[i]].name === eventName) {
+ this.off(eventIds[i]);
+ }
+ }
+ });
+ } else if (typeof eventName === "number") {
+ var eventId = eventName;
+ this.each(function() {
+ if (!LDOMCache.eventListenerFunctionsIds[eventId]) {
+ return;
+ }
+ var eventName = LDOMCache.eventListenerFunctionsIds[eventId].name;
+ if (!LDOMCache.eventListenerFunctions[eventName][eventId]) {
+ return;
+ }
+ var event = LDOMCache.eventListenerFunctions[eventName][eventId];
+ this._node.removeEventListener(eventName, event.funct);
+ var eventIds = this._node._LDOMEvents || [];
+ eventIds.splice(eventIds.indexOf(eventId), 1);
+ if (eventIds.length === 0) {
+ delete this._node._LDOMEvents;
+ } else {
+ this._node._LDOMEvents = eventIds;
+ }
+ if (--event.count === 0) {
+ delete LDOMCache.eventListenerFunctions[eventName][eventId];
+ if (Object.keys(LDOMCache.eventListenerFunctions[eventName]).length === 0) {
+ delete LDOMCache.eventListenerFunctions[eventName];
+ }
+ delete LDOMCache.eventListenerFunctionsIds[eventId];
+ }
+ });
+ }
+ }
+
+ function trigger(eventName, data) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ var event = document.createEvent("Event");
+ event.initEvent(eventName, true, true);
+ for (var key in (data || {})) {
+ event[key] = data[key];
+ }
+ this.each(function() {
+ var that = this;
+ setTimeout(function() {
+ that._node.dispatchEvent(event);
+ }, 0);
+ });
+ return this;
+ }
+
+ function hide() {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ this.each(function() {
+ if (this._node.style.display === "none") {
+ return;
+ }
+ var isImportant = false;
+ if (this._node.style.display !== "") {
+ this._node.setAttribute("data-LDOM-hidden-previous-display", this._node.style.display);
+ if (this._node.style.getPropertyPriority("display") === "important") {
+ this._node.setAttribute("data-LDOM-hidden-previous-display-important", "true");
+ isImportant = true;
+ }
+ }
+ this._node.style.setProperty("display", "none", isImportant ? "important" : "");
+ });
+ return this;
+ }
+
+ function show() {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ this.each(function() {
+ if (this._node.hasAttribute("data-LDOM-hidden-previous-display")) {
+ this._node.style.setProperty("display", this._node.getAttribute("data-LDOM-hidden-previous-display"), this._node.hasAttribute("data-LDOM-hidden-previous-display-important") ? "important" : "");
+ this._node.removeAttribute("data-LDOM-hidden-previous-display");
+ this._node.removeAttribute("data-LDOM-hidden-previous-display-important");
+ } else if (this._node.style.display === "none") {
+ this._node.style.display = "";
+ }
+ });
+ return this;
+ }
+
+ function toggle(show) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ this.each(function() {
+ var shouldShow = this._node.hasAttribute("data-LDOM-hidden-previous-display") || this._node.style.display === "none";
+ if (isDefined(show)) {
+ shouldShow = show;
+ }
+ if (shouldShow) {
+ this.show()
+ } else {
+ this.hide();
+ }
+ });
+ return this;
+ }
+
+ function css(property, value, isImportant) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ if (!isDefined(value)) {
+ var elementsArray = getElementsArray(this);
+ return elementsArray.length > 0 ? window.getComputedStyle(elementsArray[0]._node)[property] : "";
+ } else {
+ this.each(function() {
+ this._node.style.setProperty(property, value, isImportant ? "important" : "");
+ });
+ return this;
+ }
+ }
+
+ function html(htmlString) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ if (!isDefined(htmlString)) {
+ var elementsArray = getElementsArray(this);
+ return elementsArray.length > 0 ? elementsArray[0]._node.innerHTML : "";
+ } else {
+ return setPropertyAndRemoveDetachedNodes(this, "innerHTML", htmlString);
+ }
+ }
+
+ function outerHTML(htmlString) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ if (!isDefined(htmlString)) {
+ var elementsArray = getElementsArray(this);
+ return elementsArray.length > 0 ? elementsArray[0]._node.outerHTML : "";
+ } else {
+ return setPropertyAndRemoveDetachedNodes(this, "outerHTML", htmlString);
+ }
+ }
+
+ function text(textString) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ if (!isDefined(textString)) {
+ var elementsArray = getElementsArray(this);
+ return elementsArray.length > 0 ? elementsArray[0]._node.innerText : "";
+ } else {
+ return setPropertyAndRemoveDetachedNodes(this, "innerText", textString);
+ }
+ }
+
+ function prop(propertyName, value) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ if (!isDefined(value)) {
+ var elementsArray = getElementsArray(this);
+ return elementsArray.length > 0 ? elementsArray[0]._node[propertyName] : "";
+ } else {
+ this.each(function() {
+ this._node[propertyName] = value;
+ });
+ return this;
+ }
+ }
+
+ function attr(attributeName, value) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ if (!isDefined(value)) {
+ var elementsArray = getElementsArray(this);
+ return elementsArray.length > 0 ? elementsArray[0]._node.getAttribute(attributeName) : "";
+ } else {
+ this.each(function() {
+ this._node.setAttribute(attributeName, value);
+ });
+ return this;
+ }
+ }
+
+ function removeAttr(attributeName) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ this.each(function() {
+ this._node.removeAttribute(attributeName);
+ });
+ return this;
+ }
+
+ function addClass(className) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ this.each(function() {
+ var classes = (this._node.getAttribute("class") || "").split(" ");
+ var newClasses = className.split(" ");
+ for (var i = 0; i < newClasses.length; i++) {
+ if (classes.indexOf(newClasses[i]) === -1) {
+ classes.push(newClasses[i]);
+ }
+ }
+ this._node.setAttribute("class", classes.join(" ").trim());
+ });
+ return this;
+ }
+
+ function removeClass(className) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ if (!isDefined(className)) {
+ this.each(function() {
+ this._node.removeAttribute("class");
+ });
+ } else {
+ this.each(function() {
+ var classes = (this._node.getAttribute("class") || "").split(" ");
+ var newClasses = className.split(" ");
+ for (var i = 0; i < newClasses.length; i++) {
+ var classIndex = classes.indexOf(newClasses[i]);
+ if (classIndex !== -1) {
+ classes.splice(classIndex, 1);
+ }
+ }
+ this._node.setAttribute("class", classes.join(" ").trim());
+ });
+ }
+ return this;
+ }
+
+ function hasClass(className, all) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ var doesHaveClass = false;
+ this.each(function() {
+ var classes = (this._node.getAttribute("class") || "").split(" ");
+ if (classes.indexOf(className) !== -1) {
+ doesHaveClass = true;
+ if (!all) {
+ return false;
+ }
+ } else {
+ doesHaveClass = false;
+ if (all) {
+ return false;
+ }
+ }
+ });
+ return doesHaveClass;
+ }
+
+ function parent() {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ var output = [];
+ this.each(function() {
+ if (output.indexOf(this._node.parentNode) === -1) {
+ output.push(this._node.parentNode);
+ }
+ });
+ return $(output);
+ }
+
+ function children() {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ var output = [];
+ this.each(function() {
+ var elems = this._node.children;
+ for (var i = 0; i < elems.length; i++) {
+ output.push(elems[i]);
+ }
+ });
+ return $(output);
+ }
+
+ function filter(selector) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ if (!selector) {
+ return $([]);
+ }
+ var matchesMethod = "matches";
+ if (Element.prototype.matches) {
+ matchesMethod = "matches";
+ } else if (Element.prototype.matchesSelector) {
+ matchesMethod = "matchesSelector";
+ } else if (Element.prototype.msMatchesSelector) {
+ matchesMethod = "msMatchesSelector";
+ } else if (Element.prototype.webkitMatchesSelector) {
+ matchesMethod = "webkitMatchesSelector";
+ }
+ var output = [];
+ this.each(function() {
+ if (this._node[matchesMethod](selector)) {
+ output.push(this);
+ }
+ });
+ return $(output);
+ }
+
+ function first() {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ var elementsArray = getElementsArray(this);
+ if (elementsArray.length === 0) {
+ return $([]);
+ }
+ return elementsArray[0];
+ }
+
+ function last() {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ var elementsArray = getElementsArray(this);
+ if (elementsArray.length === 0) {
+ return $([]);
+ }
+ return elementsArray[elementsArray.length - 1];
+ }
+
+ function eq(index) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ var elementsArray = getElementsArray(this);
+ if (index < 0) {
+ index = elementsArray.length + index;
+ }
+ if (!isDefined(elementsArray[index])) {
+ return $([]);
+ }
+ return elementsArray[index];
+ }
+
+ function insertAfter(ldomObjectTarget) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ this.each(function() {
+ var callingNode = this._node;
+ ldomObjectTarget.each(function() {
+ this._node.parentNode.insertBefore(callingNode.cloneNode(true), this._node.nextSibling);
+ });
+ }, true);
+ return this;
+ }
+
+ function insertBefore(ldomObjectTarget) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ this.each(function() {
+ var callingNode = this._node;
+ ldomObjectTarget.each(function() {
+ this._node.parentNode.insertBefore(callingNode.cloneNode(true), this._node);
+ });
+ });
+ return this;
+ }
+
+ function appendChild(childElement) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ this.each(function() {
+ var callingNode = this._node;
+ childElement.each(function() {
+ callingNode.appendChild(this._node.cloneNode(true));
+ });
+ });
+ return this;
+ }
+
+ function prependChild(childElement) {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ this.each(function() {
+ var callingNode = this._node;
+ childElement.each(function() {
+ callingNode.insertBefore(this._node.cloneNode(true), callingNode.firstChild);
+ }, true);
+ });
+ return this;
+ }
+
+ function remove() {
+ LDOMCache.functionsUsed[arguments.callee.name] = true;
+ this.each(function() {
+ if (isDefined(this.off)) {
+ this.off();
+ }
+ this._node.parentNode.removeChild(this._node);
+ });
+ }
+
+ // Internal Helper Functions
+
+ function setPropertyAndRemoveDetachedNodes(ldomObject, property, value) {
+ ldomObject.each(function() {
+ this.inPage = document.body.contains(this._node);
+ });
+ ldomObject.each(function() {
+ this._node[property] = value;
+ });
+ var output = [];
+ ldomObject.each(function() {
+ if (!this.inPage || document.body.contains(this._node)) {
+ output.push(this);
+ }
+ delete this.inPage;
+ });
+ return $(output);
+ }
+
+ function getElementsArray(obj) {
+ if (obj._elements) {
+ return obj._elements;
+ } else {
+ return [obj];
+ }
+ }
+
+ function isDefined(obj) {
+ if (typeof obj === "undefined") {
+ return false;
+ }
+ return true;
+ }
+})();
diff --git a/src/assets/ldom.dev.js:Zone.Identifier b/src/assets/ldom.dev.js:Zone.Identifier
new file mode 100644
index 0000000..053d112
--- /dev/null
+++ b/src/assets/ldom.dev.js:Zone.Identifier
@@ -0,0 +1,3 @@
+[ZoneTransfer]
+ZoneId=3
+HostUrl=about:internet
diff --git a/src/interfaces/Body.js b/src/interfaces/Body.js
deleted file mode 100644
index 49f6f8e..0000000
--- a/src/interfaces/Body.js
+++ /dev/null
@@ -1,23 +0,0 @@
-export class Body {
- constructor() {}
-
- isAsteroid() {
- return this.BodyName.includes('Belt')
- }
-
- isPlanet() {
- return !!this.PlanetClass
- }
-
- isStar() {
- return !!this.StarType
- }
-
- simpleName() {
- return this.BodyName.replace(this.StarSystem, '')
- }
-
- distance() {
- return Intl.NumberFormat().format(Math.round(this.DistanceFromArrivalLS))
- }
-}
\ No newline at end of file
diff --git a/src/interfaces/JournalInterface.js b/src/interfaces/JournalInterface.js
index 55008ae..927bef6 100644
--- a/src/interfaces/JournalInterface.js
+++ b/src/interfaces/JournalInterface.js
@@ -1,5 +1,5 @@
-import { Body } from './Body'
-import { System } from './System'
+import { Body } from '../models/Body'
+import { System } from '../models/System'
const EventEmitter = require('events')
const fs = require('fs')
@@ -11,6 +11,7 @@ const lineReader = require('reverse-line-reader')
const chokidar = require('chokidar')
const Tail = require('tail').Tail
const find = require('lodash/find')
+const findIndex = require('lodash/findIndex')
// Set log() to console.log() so whenever I get around to setting up a log file, I don't have to
// search and replace all the console.log()'s.
@@ -36,21 +37,14 @@ export class JournalInterface extends EventEmitter {
this.currentJournal = this.getLatestJournal()
// LineReader seems to be async, so start async processes here.
- this.currentLocation = null
+ this.location = null
log('JournalInterface initialized. Attempting to find current location.')
this.getCurrentLocation()
- .then(() => {
- log('Attempting to find scanned bodies in current system.')
- this.getScannedBodies()
- .then(() => {
- log('Scanned bodies found.')
- this.emit('SCANNED_BODIES_FOUND')
- })
- })
-
}
+ /* -------------------------------------------------------------------- getLatestJournal ---- */
+
// https://stackoverflow.com/questions/15696218/get-the-most-recent-file-in-a-directory-node-js
getLatestJournal() {
const journals = globSync(this.journalPattern)
@@ -63,31 +57,38 @@ export class JournalInterface extends EventEmitter {
log(`New journal file found, now watching ${path.basename(this.currentJournal)}.`)
}
+ /* ------------------------------------------------------------------ getCurrentLocation ---- */
+
// Get current location on setup, so if app is restarted, user can pick up where they left off
// Rather than waiting til they jump to the next system to use the program again.
- async getCurrentLocation() {
- return lineReader.eachLine(this.currentJournal, (raw, last) => {
+ getCurrentLocation() {
+ lineReader.eachLine(this.currentJournal, (raw, last) => {
if (raw) { // skip blank line at end of file
const line = JSON.parse(raw)
if (line.event === 'FSDJump') {
- this.currentLocation = new System(line.StarSystem)
- log(`Current location set to ${this.currentLocation.name}.`)
- this.emit('FSDJump')
+ this.location = new System(line.StarSystem)
+ log(`Current location set to ${this.location.name}.`)
+ this.emit('ENTERED_NEW_SYSTEM')
return false
} else if (last) {
log('Warning: unable to find last hyperspace jump. Current location unknown.')
return false
}
}
+ }).then(() => {
+ log('Attempting to find scanned bodies in current system.')
+ this.getScannedBodies()
})
}
+ /* -------------------------------------------------------------------- getScannedBodies ---- */
+
// Look for all scanned bodies before last FSDJump, for same reasons as getCurrentLocation().
- async getScannedBodies() {
+ getScannedBodies() {
let detailedScanLine = null
- return lineReader.eachLine(this.currentJournal, (raw, last) => {
+ lineReader.eachLine(this.currentJournal, (raw, last) => {
if (raw) { // Skip blank line at end of file.
const line = JSON.parse(raw)
@@ -97,15 +98,14 @@ export class JournalInterface extends EventEmitter {
if (line.event === 'SAAScanComplete') {
// This was a DSS, so set the DSS flag to true and add to list.
detailedScanLine.DSSDone = true
- this.currentLocation.bodies.push(Object.assign(new Body, detailedScanLine))
+ this.location.bodies.push(Object.assign(new Body, detailedScanLine))
} else {
// Else, check that the body hasn't already been added (by a DSS scan line).
- let r = find(this.currentLocation.bodies, ['BodyID', detailedScanLine.BodyID])
+ let r = find(this.location.bodies, {'BodyName': detailedScanLine.BodyName, 'BodyID': detailedScanLine.BodyID})
if (r === undefined) {
- // Set DSS flag if body was not already logged, then add to list.
- detailedScanLine.DSSDone = false
- this.currentLocation.bodies.push(Object.assign(new Body, detailedScanLine))
+ // Body was not already logged, so add to list.
+ this.location.bodies.push(Object.assign(new Body, detailedScanLine))
}
}
@@ -122,21 +122,20 @@ export class JournalInterface extends EventEmitter {
detailedScanLine = line
} else if (line.StarType !== undefined) { // Save stars to bodies list.
- this.currentLocation.bodies.push(Object.assign(new Body, line))
+ this.location.bodies.push(Object.assign(new Body, line))
} else if (line.ScanType === 'AutoScan') { // Save auto/discovery scan bodies.
// Check if planet, and then do the duplicate check (otherwise it's an
// astroid, as we've already accounted for stars).
if (line.PlanetClass !== undefined) {
- let r = find(this.currentLocation.bodies, ['BodyID', line.BodyID])
+ let r = find(this.location.bodies, ['BodyID', line.BodyID])
if (r === undefined) {
- line.DSSDone = false
- this.currentLocation.bodies.push(Object.assign(new Body, line))
+ this.location.bodies.push(Object.assign(new Body, line))
}
} else { // Asteroids.
- this.currentLocation.bodies.push(Object.assign(new Body, line))
+ this.location.bodies.push(Object.assign(new Body, line))
}
}
} else if (line.event === 'FSDJump') {
@@ -144,9 +143,14 @@ export class JournalInterface extends EventEmitter {
return false
}
}
+ }).then(() => {
+ log('Scanned bodies found.')
+ this.emit('INIT_COMPLETE')
})
}
+ /* ---------------------------------------------------------------------- watchDirectory ---- */
+
// Set up journal directory watcher to catch new journal files as the game seems to sometimes
// make more than one journal per day.
// Also for instances where UTC day switches over mid-play session.
@@ -158,23 +162,80 @@ export class JournalInterface extends EventEmitter {
log('Watching journal folder for changes...')
}
+ /* ----------------------------------------------------------------------- parseScanLine ---- */
+
+ // Parse and handle scan lines.
+ parseScanLine(line, DSS = false) {
+ const dupChecker = {'BodyName': line.BodyName, 'BodyID': line.bodyID}
+
+ // If it's a DSS scan, then we should have already added the body to the list. But we'll
+ // check to make sure.
+ if (DSS) {
+ // Using findIndex() rather than find() so we can edit the body if found
+ let body = findIndex(this.location.bodies, dupChecker)
+
+ if (body > -1) { // Body was found in list, so simply toggle the DSS flag.
+ this.location.bodies[body].DSSDone = true
+ } else { // Body was missed on initial journal scan, so add it to the list.
+ line.DSSDone = true
+ this.location.bodies.push(Object.assign(new Body, line))
+ }
+
+ } else { // Otherwise it's an FSS or auto scan, and needs to be added to the list.
+ // Probably overkill, but do a duplicate check just in case.
+ let r = find(this.location.bodies, dupChecker)
+
+ if (r === undefined) {
+ this.location.bodies.push(Object.assign(new Body, line))
+ }
+ }
+
+ log(`Scan detected. Body: ${line.BodyName}.`)
+ log(this.location.bodies)
+ }
+
+ /* -----------------------------------------------------------------------0000 parseLine ---- */
+
// Parse and handle journal lines.
parseLine(raw) {
const line = JSON.parse(raw)
-
- if (line.event === 'FSDJump') {
- this.currentLocation = new System(line.StarSystem)
- this.emit('FSDJump')
+ let DSSFlag = false
+
+ switch (line.event) {
+ // CMDR jumped to new system, so update current location.
+ case 'FSDJump': {
+ this.location = new System(line.StarSystem)
+ this.emit('ENTERED_NEW_SYSTEM')
+ break
+ }
+
+ // CMDR completed DSS scan, so set flag for when next line processes and we want to
+ // figure out what kind of scan occurred.
+ case 'SAAScanComplete': {
+ DSSFlag = true
+ break
+ }
+
+ // A scan occurred, so let's hand that info off to the appropriate function and then
+ // reset the DSS flag.
+ case 'Scan': {
+ this.parseScanLine(line, DSSFlag)
+ this.emit('BODY_SCANNED')
+ DSSFlag = false
+ break
+ }
}
}
+ /* ------------------------------------------------------------------------ watchJournal ---- */
+
// Watch the journal for changes.
watchJournal() {
const tail = new Tail(this.currentJournal, {useWatchFile: true})
log(`Watching ${path.basename(this.currentJournal)}...`)
- tail.on('line', data => this.parseLine(data))
- tail.on('error', err => console.log(err))
+ tail.on('line', data => data ? this.parseLine(data) : undefined)
+ tail.on('error', err => log(`Tail error in JournalInterface.watchJournal(): ${err}`))
}
}
\ No newline at end of file
diff --git a/src/models/Body.js b/src/models/Body.js
new file mode 100644
index 0000000..4a423a0
--- /dev/null
+++ b/src/models/Body.js
@@ -0,0 +1,79 @@
+export class Body {
+ constructor() {
+ this.DSSDone = false
+ }
+
+ /* -------------------------------------------------------------------------- isAsteroid ---- */
+
+ isAsteroid() {
+ return this.BodyName.includes('Belt')
+ }
+
+ /* ---------------------------------------------------------------------------- isPlanet ---- */
+
+ isPlanet() {
+ return !!this.PlanetClass
+ }
+
+ /* ------------------------------------------------------------------------------ isStar ---- */
+
+ isStar() {
+ return !!this.StarType
+ }
+
+ /* ---------------------------------------------------------------------------- nameIcon ---- */
+
+ nameIcon() {
+ let nameIcon = null
+
+ if (this.isAsteroid()) {
+ nameIcon = 'asteroid-4'
+ } else if (this.isStar()) {
+ nameIcon = 'star'
+ } else if (this.isPlanet()) {
+ nameIcon = 'jupiter-3'
+ }
+
+ return nameIcon
+ }
+
+ /* -------------------------------------------------------------------------- simpleName ---- */
+
+ simpleName() {
+ return this.BodyName.replace(this.StarSystem, '')
+ }
+
+ /* ---------------------------------------------------------------------------- typeIcon ---- */
+
+ typeIcon() {
+ let typeIcon = null
+
+ if (this.isStar() || this.isAsteroid()) {
+ typeIcon = this.nameIcon()
+ } else {
+ const planetClass = this.PlanetClass.toLowerCase()
+
+ if (planetClass.includes('metal')) {
+ typeIcon = 'ingot'
+ } else if (planetClass.includes('icy')) {
+ typeIcon = 'snowflake'
+ } else if (planetClass.includes('earth')) {
+ typeIcon = 'earth'
+ } else if (planetClass.includes('gas giant')) {
+ typeIcon = 'jupiter-1'
+ } else if (planetClass.includes('rock')) {
+ typeIcon = 'asteroid-3'
+ } else if (planetClass.includes('water') || planetClass.includes('ammonia')) {
+ typeIcon = 'water-drops'
+ }
+ }
+
+ return typeIcon
+ }
+
+ /* ---------------------------------------------------------------------------- distance ---- */
+
+ distance() {
+ return Intl.NumberFormat().format(Math.round(this.DistanceFromArrivalLS))
+ }
+}
\ No newline at end of file
diff --git a/src/interfaces/System.js b/src/models/System.js
similarity index 100%
rename from src/interfaces/System.js
rename to src/models/System.js
diff --git a/src/renderer.js b/src/renderer.js
index 713d6fb..d5fb5b5 100644
--- a/src/renderer.js
+++ b/src/renderer.js
@@ -26,12 +26,13 @@
* ```
*/
-import './index.css'
+import './assets/index.css'
import './icons/flaticon.css'
const { app } = require('electron')
import { createApp, ref } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
import { JournalInterface } from './interfaces/JournalInterface'
+import { createBodyRow } from './ui'
// Grab app.isPackaged from main process
let isPackaged = false
@@ -41,28 +42,32 @@ window.process.argv.forEach((item) => {
}
})
-createApp({
- setup() {
- const journal = new JournalInterface(isPackaged)
+/* ------------------------------------------------------------------------------- app setup ---- */
- // TODO: show warning to user
- if (journal.journalDir === null) {
- return
- }
+const journal = new JournalInterface(isPackaged)
- journal.watchDirectory()
- journal.watchJournal()
+if (journal.journalDir === null) {
+ // handle error
+}
- const currentLocation = ref('Unknown')
- const currentLocationBodies = ref([])
+journal.watchDirectory()
+journal.watchJournal()
- journal.on('FSDJump', () => currentLocation.value = journal.currentLocation)
- journal.on('SCANNED_BODIES_FOUND', () => currentLocationBodies.value = journal.currentLocation.bodies)
+journal.once('INIT_COMPLETE', () => {
+ if (journal.location !== null) {
+ $('#currentSystem')
+ .addClass('charted')
+ .removeClass('highlighted text-center')
+ $('#currentSystemName').text(journal.location.name)
- return {
- currentLocation,
- currentLocationBodies,
- }
+ $('#currentSystemIcon').removeClass('hidden')
}
-}).mount('#app')
+
+ if (journal.location.bodies.length > 0) {
+ journal.location.bodies.forEach((body) => {
+ const row = createBodyRow(body)
+ $('#lowValueScans').appendChild(row)
+ })
+ }
+})
\ No newline at end of file
diff --git a/src/ui.js b/src/ui.js
new file mode 100644
index 0000000..2e1344e
--- /dev/null
+++ b/src/ui.js
@@ -0,0 +1,95 @@
+/* ------------------------------------------------------------------------------ buildRings ---- */
+
+const buildRings = (body) => {
+ const rings = $('')
+ const seperator = $('').text(' ) ')
+
+ body.Rings.forEach((ring) => {
+ const ringClass = ring.RingClass.replace('eRingClass_', '')
+ let icon = null
+
+ switch (ringClass) {
+ case 'MetalRich': {
+ icon = 'gold-bars'
+ break
+ }
+
+ case 'Metalic':
+ case 'Metallic': {
+ icon = 'ingot'
+ break
+ }
+
+ case 'Icy': {
+ icon = 'snowflake'
+ break
+ }
+
+ case 'Rocky': {
+ icon = 'asteroid-3'
+ break
+ }
+ }
+
+ if (icon !== null) {
+ rings.appendChild($('').addClass(`flaticon-${icon}`))
+ rings.appendChild(seperator)
+ }
+ })
+
+ return rings
+}
+
+/* --------------------------------------------------------------------------- createBodyRow ---- */
+
+export const createBodyRow = (body) => {
+ const row = $('').addClass('row ml-1 mr-1')
+ row.attr('id', body.bodyID)
+
+ // spacer
+ row.appendChild($('
').addClass('col-1 system'))
+
+ // name
+ const name = $('
').addClass('col-2 system charted text-left')
+ name.appendChild($('
')).addClass(`flaticon-${body.nameIcon()}`)
+ name.appendChild($('')).text(body.simpleName())
+ row.appendChild(name)
+
+ // type icon
+ const type = $('').addClass('col pr-0 mr-0 system charted')
+ type.appendChild($('
').addClass(`flaticon-${body.typeIcon()}`))
+ // rings
+ if (body.Rings !== undefined) {
+ type.appendChild(buildRings(body))
+ }
+ // type
+ const typeName = body.PlanetClass || body.starType || ''
+ type.appendChild($('').text(typeName))
+ row.appendChild(type)
+
+ // distance
+ const distance = $('').addClass('col-auto pl-2 ml-0 system charted').text(body.distance())
+ row.appendChild(distance)
+
+ // info
+ const info = $('
').addClass('col-1 system charted')
+ // terraformable
+ const terraform = $('
').addClass('flaticon-cooling-tower opacity-0')
+ if (body.isPlanet && body.TerraformState) {
+ terraform.removeClass('opacity-0')
+ }
+ info.appendChild(terraform)
+ // was mapped
+ const mapped = $('').addClass('flaticon-flag-outline-on-a-pole-with-stars-around opacity-0')
+ if (body.isPlanet() && !body.WasMapped) {
+ mapped.removeClass('opacity-0')
+ }
+ info.appendChild(mapped)
+ row.appendChild(info)
+
+ // mapped value
+ const value = $('').addClass('col-2 system charted text-right')
+ row.appendChild(value)
+
+ return row
+}
\ No newline at end of file