diff --git a/moonphase@techi-freki/CHANGELOG.md b/moonphase@techi-freki/CHANGELOG.md
new file mode 100644
index 00000000000..9b3a8e597a3
--- /dev/null
+++ b/moonphase@techi-freki/CHANGELOG.md
@@ -0,0 +1,72 @@
+# Changelog
+
+## v1.0.5
+- Fixes issue [#6015](https://github.com/linuxmint/cinnamon-spices-applets/issues/6015)
+
+## v1.0.4 ([#6020](https://github.com/linuxmint/cinnamon-spices-applets/pull/6020))
+- Updates Russian translation
+
+## v1.0.3 ([#5997](https://github.com/linuxmint/cinnamon-spices-applets/pull/5997))
+- Updates French translations
+
+## v1.0.2 ([#5983](https://github.com/linuxmint/cinnamon-spices-applets/pull/5983))
+- Updates Portuguese translations
+
+## v1.0.1 ([#5982](https://github.com/linuxmint/cinnamon-spices-applets/pull/5982))
+- Updates Spanish translations
+
+## v1.0.0 ([#5961](https://github.com/linuxmint/cinnamon-spices-applets/pull/5961))
+- Feature add: Added geolocation features
+- Feature add: Added moon rise, set, and transit times on left click
+- Feature add: Added current moon phase information on left click
+- Swaps out [SunCalc](https://github.com/mourner/suncalc) for [SunCalc3](https://github.com/hypnos3/suncalc3) for geolocation features
+- Heavily refactors and cleans up code base
+- Cleans up versioning (major/minor/patch)
+- Adds LICENSE for icons
+- Updates .pot file for new translations
+
+## v0.2.12 ([#5819](https://github.com/linuxmint/cinnamon-spices-applets/pull/5819))
+- Adds Dutch translations
+
+## v0.2.11 ([#5628](https://github.com/linuxmint/cinnamon-spices-applets/pull/5628))
+- Fixes location bug ([#5610](https://github.com/linuxmint/cinnamon-spices-applets/issues/5610))
+
+## v0.2.10 ([#5306](https://github.com/linuxmint/cinnamon-spices-applets/pull/5306))
+- Adds Danish translations
+
+## v0.2.9 ([#5226](https://github.com/linuxmint/cinnamon-spices-applets/pull/5226))
+- Adds Hungarian translations
+
+## v0.2.8 ([#5223](https://github.com/linuxmint/cinnamon-spices-applets/pull/5223))
+- Fixes day 28 bug ([#5222](https://github.com/linuxmint/cinnamon-spices-applets/issues/5222))
+
+## v0.2.7 ([#5087](https://github.com/linuxmint/cinnamon-spices-applets/issues/5087))
+- Bug fix ([#5072](https://github.com/linuxmint/cinnamon-spices-applets/issues/5072))
+
+## v0.2.6 ([#5086](https://github.com/linuxmint/cinnamon-spices-applets/pull/5086))
+- Updating version
+
+## v0.2.5 ([#5085](https://github.com/linuxmint/cinnamon-spices-applets/pull/5085))
+- Adds Russian translations
+
+## v0.2.4 ([5080](https://github.com/linuxmint/cinnamon-spices-applets/pull/5080))
+- Reviews Italian translations
+
+## v0.2.3 ([#5078](https://github.com/linuxmint/cinnamon-spices-applets/pull/5078))
+- Adds Italian translations
+
+## v0.2.2 ([#5073](https://github.com/linuxmint/cinnamon-spices-applets/pull/5073))
+- Adds Spanish translations
+
+## v0.2.1 ([#5071](https://github.com/linuxmint/cinnamon-spices-applets/pull/5071))
+- Updates .pot file and French translations
+
+## v0.2.0 ([#5058](https://github.com/linuxmint/cinnamon-spices-applets/pull/5058))
+- Feature add: Adds percentage display to label and tooltip
+
+## v0.1.0 ([#5054](https://github.com/linuxmint/cinnamon-spices-applets/pull/5054))
+- Feature add: Translations
+- Adds French translations
+
+## v0.0.1 ([#5052](https://github.com/linuxmint/cinnamon-spices-applets/pull/5052))
+- Initial release
\ No newline at end of file
diff --git a/moonphase@techi-freki/README.md b/moonphase@techi-freki/README.md
index 35630502016..89955a9fae9 100644
--- a/moonphase@techi-freki/README.md
+++ b/moonphase@techi-freki/README.md
@@ -1,7 +1,9 @@
# Moon Phase Cinnamon Applet
-A Cinnamon applet that displays the current moon phase.
+A Cinnamon applet that displays up-to-date moon related information.
## Installation
-Move extract and move moonphase@techi-freki to the ~./local/share/cinnamon/applets directory.
+Extract and move moonphase@techi-freki to the ~/.local/share/cinnamon/applets directory.
+
+Review Changelog for latest updates
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/icons/LICENSE b/moonphase@techi-freki/files/moonphase@techi-freki/icons/LICENSE
new file mode 100644
index 00000000000..b22be90b3d9
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/icons/LICENSE
@@ -0,0 +1,8 @@
+Notice: Icons used are named "weather-icons" available from here: https://github.com/erikflowers/weather-icons
+
+Licence: OFL Licence
+https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL
+
+The warning-outline-svgrepo-com icon is under the MIT license and is available here: https://www.svgrepo.com/svg/326459/warning-outline
+
+no-moonrise-symbolic and no-moonset-symbolic where created by Techi-Freki and released under the OFL license
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-down-left-symbolic.svg b/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-down-left-symbolic.svg
new file mode 100644
index 00000000000..85db8547343
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-down-left-symbolic.svg
@@ -0,0 +1,39 @@
+
+
+
+
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-down-right-symbolic.svg b/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-down-right-symbolic.svg
new file mode 100644
index 00000000000..8885a5b0d60
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-down-right-symbolic.svg
@@ -0,0 +1,39 @@
+
+
+
+
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-down-symbolic.svg b/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-down-symbolic.svg
new file mode 100644
index 00000000000..613c7695514
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-down-symbolic.svg
@@ -0,0 +1,39 @@
+
+
+
+
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-left-symbolic.svg b/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-left-symbolic.svg
new file mode 100644
index 00000000000..f4e99b43ff3
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-left-symbolic.svg
@@ -0,0 +1,39 @@
+
+
+
+
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-right-symbolic.svg b/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-right-symbolic.svg
new file mode 100644
index 00000000000..f63af484ea2
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-right-symbolic.svg
@@ -0,0 +1,18 @@
+
+
+
+
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-up-left-symbolic.svg b/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-up-left-symbolic.svg
new file mode 100644
index 00000000000..0d6c76a3392
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-up-left-symbolic.svg
@@ -0,0 +1,39 @@
+
+
+
+
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-up-right-symbolic.svg b/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-up-right-symbolic.svg
new file mode 100644
index 00000000000..1f3b7d53661
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-up-right-symbolic.svg
@@ -0,0 +1,39 @@
+
+
+
+
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-up-symbolic.svg b/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-up-symbolic.svg
new file mode 100644
index 00000000000..668a15255a6
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/icons/direction-up-symbolic.svg
@@ -0,0 +1,9 @@
+
+
+
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/icons/night-clear-symbolic.svg b/moonphase@techi-freki/files/moonphase@techi-freki/icons/night-clear-symbolic.svg
new file mode 100644
index 00000000000..cb456ce9703
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/icons/night-clear-symbolic.svg
@@ -0,0 +1,47 @@
+
+
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/icons/no-moonrise-symbolic.svg b/moonphase@techi-freki/files/moonphase@techi-freki/icons/no-moonrise-symbolic.svg
new file mode 100644
index 00000000000..038dbc2b845
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/icons/no-moonrise-symbolic.svg
@@ -0,0 +1,47 @@
+
+
+
+
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/icons/no-moonset-symbolic.svg b/moonphase@techi-freki/files/moonphase@techi-freki/icons/no-moonset-symbolic.svg
new file mode 100644
index 00000000000..4a7388200bc
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/icons/no-moonset-symbolic.svg
@@ -0,0 +1,58 @@
+
+
+
+
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/icons/warning-outline-svgrepo-com.svg b/moonphase@techi-freki/files/moonphase@techi-freki/icons/warning-outline-svgrepo-com.svg
new file mode 100644
index 00000000000..7944bbfa8e8
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/icons/warning-outline-svgrepo-com.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/js/calc.js b/moonphase@techi-freki/files/moonphase@techi-freki/js/calc.js
new file mode 100644
index 00000000000..81d8a2f36bb
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/js/calc.js
@@ -0,0 +1,33 @@
+const SunCalc = require('./lib/suncalc3.js');
+
+class Calculator {
+ constructor(lat, lon, date = new Date()) {
+ this.moonDate = date;
+ this.observerLat = Number(lat);
+ this.observerLon = Number(lon);
+ this.moonData = SunCalc.getMoonData(this.moonDate, this.observerLat, this.observerLon);
+ this.times = SunCalc.getMoonTimes(this.moonDate, this.observerLat, this.observerLon);
+ this.transit = SunCalc.moonTransit(this.times.rise, this.times.set, this.observerLat, this.observerLon).main;
+ }
+
+ getMoonIllumination() {
+ return this.moonData.illumination;
+ }
+
+ getRiseSetTimes() {
+ const rise = isNaN(this.times.rise) ? null : this.times.rise;
+ const set = isNaN(this.times.set) ? null : this.times.set;
+
+ return {
+ rise,
+ set,
+ alwaysUp: this.times.alwaysUp,
+ alwaysDown: this.times.alwaysDown,
+ highestPosition: this.times.highest,
+ transit: this.transit,
+ riseAzimuth: SunCalc.getMoonPosition(this.times.rise, this.observerLat, this.observerLon).azimuthDegrees,
+ transitAzimuth: SunCalc.getMoonPosition(this.transit, this.observerLat, this.observerLon).azimuthDegrees,
+ setAzimuth: SunCalc.getMoonPosition(this.times.set, this.observerLat, this.observerLon).azimuthDegrees
+ }
+ }
+}
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/js/compass.js b/moonphase@techi-freki/files/moonphase@techi-freki/js/compass.js
new file mode 100644
index 00000000000..3fde24958a1
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/js/compass.js
@@ -0,0 +1,39 @@
+const TOLERANCE_MET = 'tolerance met';
+const { Direction } = require('./js/direction');
+const { Translator } = require('./js/translator');
+
+class Compass {
+ constructor(app) {
+ this.app = app;
+ this.translator = new Translator(this.app.metadata.uuid);
+ this.compassDegrees = [
+ new Direction(22.5, this.translator.translate('North'), this.app.moon.iconSet.directionUp),
+ new Direction(67.5, this.translator.translate('North East'), this.app.moon.iconSet.directionUpRight),
+ new Direction(112.5, this.translator.translate('East'), this.app.moon.iconSet.directionRight),
+ new Direction(157.5, this.translator.translate('South East'), this.app.moon.iconSet.directionDownRight),
+ new Direction(202.5, this.translator.translate('South'), this.app.moon.iconSet.directionDown),
+ new Direction(247.5, this.translator.translate('South West'), this.app.moon.iconSet.directionDownLeft),
+ new Direction(292.5, this.translator.translate('West'), this.app.moon.iconSet.directionLeft),
+ new Direction(337.5, this.translator.translate('North West'), this.app.moon.iconSet.directionUpLeft)
+ ];
+ }
+
+ getCardinalDirection(degree) {
+ try {
+ this.compassDegrees.forEach((direction) => {
+ const fixedDegree = Math.floor(degree * 100);
+ const fixedTolerance = Math.floor(direction.tolerance * 100);
+
+ if (fixedDegree <= fixedTolerance) {
+ this.direction = direction;
+ throw new Error(TOLERANCE_MET);
+ }
+ });
+ } catch (e) {
+ if (e.message !== TOLERANCE_MET) {
+ throw e;
+ }
+ }
+ return this.direction;
+ }
+}
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/js/config.js b/moonphase@techi-freki/files/moonphase@techi-freki/js/config.js
new file mode 100644
index 00000000000..62c26f1f3e3
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/js/config.js
@@ -0,0 +1,54 @@
+const { Moon } = require('./js/moon');
+
+class Config {
+ constructor(app) {
+ this.app = app;
+ }
+
+ bindSettings() {
+ this.app.settings.bind('useAltIcons', 'useAltIcons', this.updateSettings.bind(this.app));
+
+ this.app.settings.bind('showTooltip', 'showTooltip', this.updateSettings.bind(this.app));
+ this.app.settings.bind('showPhaseTooltip', 'showPhaseTooltip', this.updateSettings.bind(this.app));
+ this.app.settings.bind('showPercentageTooltip', 'showPercentageTooltip', this.updateSettings.bind(this.app));
+
+ this.app.settings.bind('showPhaseLabel', 'showPhaseLabel', this.updateSettings.bind(this.app));
+ this.app.settings.bind('showNameLabel', 'showNameLabel', this.updateSettings.bind(this.app));
+ this.app.settings.bind('showPercentageLabel', 'showPercentageLabel', this.updateSettings.bind(this.app));
+
+ this.app.settings.bind('enableGeolocation', 'enableGeolocation', this.updateSettings.bind(this.app));
+ this.app.settings.bind('latitude', 'latitude', this.updateSettings.bind(this.app));
+ this.app.settings.bind('longitude', 'longitude', this.updateSettings.bind(this.app));
+
+ this.app.settings.bind('enablePopup', 'enablePopup', this.updateSettings.bind(this.app));
+ this.app.settings.bind('showCurrentPhaseInfo', 'showCurrentPhaseInfo', this.updateSettings.bind(this.app));
+ this.app.settings.bind('showRiseSet', 'showRiseSet', this.updateSettings.bind(this.app));
+
+ this.app.settings.bind('updateInterval', 'updateInterval', this.updateSettings.bind(this.app));
+ }
+
+ updateSettings() {
+ this.app.useAltIcons = this.app.settings.getValue('useAltIcons');
+
+ this.app.showTooltip = this.app.settings.getValue('showTooltip');
+ this.app.showPhaseTooltip = this.app.settings.getValue('showPhaseTooltip');
+ this.app.showPercentageTooltip = this.app.settings.getValue('showPercentageTooltip');
+
+ this.app.showPhaseLabel = this.app.settings.getValue('showPhaseLabel');
+ this.app.showNameLabel = this.app.settings.getValue('showNameLabel');
+ this.app.showPercentageLabel = this.app.settings.getValue('showPercentageLabel');
+
+ this.app.enableGeolocation = this.app.settings.getValue('enableGeolocation');
+ this.app.latitude = this.app.settings.getValue('latitude');
+ this.app.longitude = this.app.settings.getValue('longitude');
+
+ this.app.enablePopup = this.app.settings.getValue('enablePopup');
+ this.app.showCurrentPhaseInfo = this.app.settings.getValue('showCurrentPhaseInfo');
+ this.app.showRiseSet = this.app.settings.getValue('showRiseSet');
+
+ this.app.updateInterval = this.app.settings.getValue('updateInterval');
+
+ this.app.buildPopupMenu();
+ this.app.updateApplet();
+ }
+}
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/js/direction.js b/moonphase@techi-freki/files/moonphase@techi-freki/js/direction.js
new file mode 100644
index 00000000000..695cb98fff8
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/js/direction.js
@@ -0,0 +1,7 @@
+class Direction {
+ constructor(tolerance, directionName, iconName) {
+ this.tolerance = tolerance;
+ this.name = directionName;
+ this.icon_name = iconName;
+ }
+}
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/js/iconSet.js b/moonphase@techi-freki/files/moonphase@techi-freki/js/iconSet.js
index 229cd0b5d2a..5b7d05abfa5 100644
--- a/moonphase@techi-freki/files/moonphase@techi-freki/js/iconSet.js
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/js/iconSet.js
@@ -58,11 +58,23 @@ class IconSet {
this.waningCrescent5 = waningCrescent5;
this.waningCrescent6 = waningCrescent6;
this.moonRise = `moonrise-symbolic`;
+ this.noMoonRise = `no-moonrise-symbolic`;
this.moonSet = `moonset-symbolic`;
+ this.noMoonSet = `no-moonset-symbolic`;
+ this.nightClear = `night-clear-symbolic`;
+ this.directionUp = `direction-up-symbolic`;
+ this.directionUpRight = `direction-up-right-symbolic`;
+ this.directionRight = `direction-right-symbolic`;
+ this.directionDownRight = `direction-down-right-symbolic`;
+ this.directionDown = `direction-down-symbolic`;
+ this.directionDownLeft = `direction-down-left-symbolic`;
+ this.directionLeft = `direction-left-symbolic`;
+ this.directionUpLeft = `direction-up-left-symbolic`;
+ this.warning = `warning-outline-svgrepo-com.svg`;
this.lunarEclipse = `lunar-eclipse-symbolic`;
}
- getSet() {
+ getPhaseIcons() {
return [
this.newMoon,
this.waxingCrescent1,
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/js/menu.js b/moonphase@techi-freki/files/moonphase@techi-freki/js/menu.js
new file mode 100644
index 00000000000..70b90c531a4
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/js/menu.js
@@ -0,0 +1,23 @@
+const { HeaderUi } = require('./js/ui/headerUi');
+const { CurrentPhaseUi } = require('./js/ui/currentPhaseUi');
+const { RiseSetUi } = require('./js/ui/riseSetUi');
+
+class Menu {
+ constructor(app) {
+ this.app = app;
+ }
+
+ buildMenu() {
+ const headerUi = new HeaderUi(this.app);
+ const currentPhaseUi = new CurrentPhaseUi(this.app);
+ const riseSetUi = new RiseSetUi(this.app);
+
+ headerUi.rebuild();
+ currentPhaseUi.rebuild();
+ riseSetUi.rebuild();
+
+ this.app.menu.addActor(headerUi.actor);
+ this.app.menu.addActor(currentPhaseUi.actor);
+ this.app.menu.addActor(riseSetUi.actor);
+ }
+}
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/js/moon.js b/moonphase@techi-freki/files/moonphase@techi-freki/js/moon.js
index 091a61eb5e1..b9fb156ceaa 100644
--- a/moonphase@techi-freki/files/moonphase@techi-freki/js/moon.js
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/js/moon.js
@@ -1,59 +1,33 @@
-const SunCalc = require('./lib/suncalc');
const { DefaultIconSet, AltIconSet } = require('./js/iconSet');
-
-const UUID = "moonphase@techi-freki";
-const { get_home_dir } = imports.gi.GLib;
-const Gettext = imports.gettext;
-Gettext.bindtextdomain(UUID, get_home_dir() + "/.local/share/locale")
+const { Calculator } = require('./js/calc');
+const { Translator } = require('./js/translator');
class Moon {
- constructor(currentDate, useAltIcons, showNameLabel, showPercentageLabel, showNameTooltip, showPercentageTooltip) {
- this.currentDate = currentDate;
- this.age = this._getAge();
- this.currentPhaseIcon = this._getCurrentPhaseIcon(useAltIcons);
- this.currentPhaseName = this._getCurrentPhaseName(showNameLabel, showPercentageLabel);
- this.currentTooltip = this._getCurrentPhaseName(showNameTooltip, showPercentageTooltip);
- }
- // translation
- _(str) {
- let translated = Gettext.dgettext(UUID, str);
- if (translated !== str)
- return translated;
- return str;
+ constructor(app) {
+ this.app = app;
+ this.calc = new Calculator(app.latitude, app.longitude);
+ this.translator = new Translator(this.app.metadata.uuid);
+ this.illumination = this.calc.getMoonIllumination();
+ this.age = Math.trunc(this.illumination.phaseValue * 28);
+ this.iconSet = app.useAltIcons ? new AltIconSet() : new DefaultIconSet();
+ this.riseSetTimes = this.calc.getRiseSetTimes();
+ this.currentPhaseIcon = this.iconSet.getPhaseIcons()[this.age];
+ this.currentPhaseName = this._getCurrentPhaseName();
}
- _getAge() {
- return SunCalc.getMoonIllumination(this.currentDate).phase;
- }
- _getCurrentPhaseIcon(useAltIcons = false) {
- const iconSet = useAltIcons ?
- new AltIconSet().getSet() :
- new DefaultIconSet().getSet();
-
- const age = Math.trunc(this.age * 28);
-
- return iconSet[age];
- }
- _getCurrentPhaseName(showName = true, showPercentage = true) {
+ _getCurrentPhaseName() {
let name = "";
- const age = Math.trunc(this.age * 28) / 28;
-
- // method to convert to percentage without rounding to keep precision
- const toPercentage = (n, fixed) => `${n * 100}`.match(new RegExp(`^-?\\d+(?:\.\\d{0,${fixed}})?`))[0] + "%";
- const percent = toPercentage(SunCalc.getMoonIllumination(this.currentDate).fraction, 2);
+ const age = this.age / 28;
- if (age === 0) name = this._("New Moon");
- else if (age < 0.25) name = this._("Waxing Crescent");
- else if (age === 0.25) name = this._("First Quarter");
- else if (age < 0.5) name = this._("Waxing Gibbous");
- else if (age === 0.5) name = this._("Full Moon");
- else if (age < 0.75) name = this._("Waning Gibbous");
- else if (age === 0.75) name = this._("Last Quarter");
- else if (age <= 1) name = this._("Waning Crescent")
- else name = this._("New Moon");
+ if (age === 0) name = this.translator.translate('New Moon');
+ else if (age < 0.25) name = this.translator.translate('Waxing Crescent');
+ else if (age === 0.25) name = this.translator.translate('First Quarter');
+ else if (age < 0.5) name = this.translator.translate('Waxing Gibbous');
+ else if (age === 0.5) name = this.translator.translate('Full Moon');
+ else if (age < 0.75) name = this.translator.translate('Waning Gibbous');
+ else if (age === 0.75) name = this.translator.translate('Last Quarter');
+ else if (age <= 1) name = this.translator.translate('Waning Crescent');
+ else name = this.translator.translate('New Moon');
- if (showName && showPercentage) return name + " (" + percent + ")";
- if (showName) return name;
- if (showPercentage) return percent;
- return _("Moon Phase");
+ return name;
}
-}
+}
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/js/moonPhase.js b/moonphase@techi-freki/files/moonphase@techi-freki/js/moonPhase.js
index c49880efca2..8018c617c62 100644
--- a/moonphase@techi-freki/files/moonphase@techi-freki/js/moonPhase.js
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/js/moonPhase.js
@@ -1,8 +1,11 @@
const Applet = imports.ui.applet;
+const { PopupMenuManager } = imports.ui.popupMenu;
const Mainloop = imports.mainloop;
const Settings = imports.ui.settings;
const Lang = imports.lang;
const { Moon } = require('./js/moon');
+const { Menu } = require('./js/menu');
+const { Config } = require('./js/config');
class MoonPhase extends Applet.TextIconApplet {
constructor(metadata, orientation, panel_height, instance_id) {
@@ -10,62 +13,82 @@ class MoonPhase extends Applet.TextIconApplet {
// setting defaults
this.metadata = metadata;
- this.settings = new Settings.AppletSettings(this, metadata.uuid, instance_id);
+ this.settings = new Settings.AppletSettings(this, this.metadata.uuid, instance_id);
+ this.orientation = orientation;
+ this.config = new Config(this);
+ this.config.bindSettings();
+ this.moon = new Moon(this);
- this.settings.bind('useAltIcons', 'useAltIcons', this._onSettingsChanged.bind(this));
- this.settings.bind('showTooltip', 'showTooltip', this._onSettingsChanged.bind(this));
- this.settings.bind('showNameTooltip', 'showNameTooltip', this._onSettingsChanged.bind(this));
- this.settings.bind('showPercentageTooltip', 'showPercentageTooltip', this._onSettingsChanged.bind(this));
- this.settings.bind('showPhaseLabel', 'showPhaseLabel', this._onSettingsChanged.bind(this));
- this.settings.bind('showNameLabel', 'showNameLabel', this._onSettingsChanged.bind(this));
- this.settings.bind('showPercentageLabel', 'showPercentageLabel', this._onSettingsChanged.bind(this));
-
- this.settings.bind('updateInterval', 'updateInterval', this._onSettingsChanged.bind(this));
-
- this._updateApplet();
+ this.updateApplet();
}
on_applet_removed_from_panel() {
if (this.updateLoopId) {
Mainloop.source_remove(this.updateLoopId);
}
+ this.settings.finalize();
}
- _onSettingsChanged(value) {
- this.useAltIcons = this.settings.getValue('useAltIcons');
- this.showTooltip = this.settings.getValue('showTooltip');
- this.showNameTooltip = this.settings.getValue('showNameTooltip');
- this.showPercentageTooltip = this.settings.getValue('showPercentageTooltip');
- this.showPhaseLabel = this.settings.getValue('showPhaseLabel');
- this.showNameLabel = this.settings.getValue('showNameLabel');
- this.showPercentageLabel = this.settings.getValue('showPercentageLabel');
+ on_applet_clicked() {
+ if (!this.enablePopup) return;
+ if (!this.showCurrentPhaseInfo && !this.showRiseSet) return;
- this.updateInterval = this.settings.getValue('updateInterval');
+ if (this.popupOpen) {
+ this.menu.toggle();
+ this.popupOpen = false;
+ } else {
+ this.menuManager = new PopupMenuManager(this);
+ this.menu = new Applet.AppletPopupMenu(this, this.orientation);
+ this.menuManager.addMenu(this.menu);
+ this.buildPopupMenu();
+ this.menu.toggle();
+ this.popupOpen = true;
+ }
+ }
- this._updateApplet();
+ buildPopupMenu() {
+ const menu = new Menu(this);
+ menu.buildMenu();
}
- _updateApplet() {
+ updateApplet() {
if (this.updateLoopId) {
Mainloop.source_remove(this.updateLoopId);
}
- const moon = new Moon(new Date(), this.useAltIcons, this.showNameLabel, this.showPercentageLabel, this.showNameTooltip, this.showPercentageTooltip);
-
- this.set_applet_icon_symbolic_name(moon.currentPhaseIcon);
+ this.moon = new Moon(this);
+ const phaseLabel = this._createPhaseLabel(this.showNameLabel, this.showPercentageLabel);
+ const phaseTooltip = this._createPhaseTooltip(this.showPhaseTooltip, this.showPercentageTooltip);
+ this.set_applet_icon_symbolic_name(this.moon.currentPhaseIcon);
if (this.showTooltip) {
- this.set_applet_tooltip(moon.currentTooltip);
+ this.set_applet_tooltip(phaseTooltip);
} else {
this.set_applet_tooltip('');
}
if (this.showPhaseLabel) {
- this.set_applet_label(moon.currentPhaseName);
+ this.set_applet_label(phaseLabel);
} else {
this.set_applet_label('');
}
- this.updateLoopId = Mainloop.timeout_add((this.updateInterval * 1000), Lang.bind(this, this._updateApplet));
+ this.updateLoopId = Mainloop.timeout_add((this.updateInterval * 1000), Lang.bind(this, this.updateApplet));
+ }
+
+ _createPhaseLabel(showNameLabel, showPercentageLabel) {
+ return this._createAppletDisplay(showNameLabel, showPercentageLabel);
+ }
+
+ _createPhaseTooltip(showPhaseTooltip, showPercentageTooltip) {
+ return this._createAppletDisplay(showPhaseTooltip, showPercentageTooltip);
+ }
+
+ _createAppletDisplay(showName, showPercentage) {
+ const percent = Math.floor(this.moon.illumination.fraction * 100 * 100) / 100;
+ if (showName && showPercentage) return `${ this.moon.currentPhaseName } (${ percent }%)`;
+ if (showName) return `${ this.moon.currentPhaseName }`;
+ if (showPercentage) return `${ percent }%`;
+ return this.metadata.name;
}
-}
+}
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/js/translator.js b/moonphase@techi-freki/files/moonphase@techi-freki/js/translator.js
new file mode 100644
index 00000000000..10fe89b045f
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/js/translator.js
@@ -0,0 +1,15 @@
+const { get_home_dir } = imports.gi.GLib;
+const GetText = imports.gettext;
+
+class Translator {
+ constructor(uuid) {
+ this.uuid = uuid;
+ }
+
+ translate(str) {
+ GetText.bindtextdomain(this.uuid, `${get_home_dir()}/.local/share/locale`);
+ let translated = GetText.dgettext(this.uuid, str);
+ if (translated !== str) return translated;
+ return str;
+ }
+}
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/currentPhaseUi.js b/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/currentPhaseUi.js
new file mode 100644
index 00000000000..6ccd1b8af4d
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/currentPhaseUi.js
@@ -0,0 +1,32 @@
+const { paddingTop5Strict, margin5, textAlignLeft } = require('./js/ui/styles');
+const { Align, BoxLayout } = imports.gi.St;
+const { ActorAlign } = imports.gi.Clutter;
+const { UiElement } = require('./js/ui/elements/uiElement');
+const { IconTextElementGenerator } = require('./js/ui/elements/iconTextElementGenerator');
+const { Translator } = require('./js/translator');
+
+class CurrentPhaseUi extends UiElement {
+ constructor (app) {
+ super(app);
+ this.actor = new BoxLayout({
+ style_class: margin5,
+ x_align: ActorAlign.CENTER,
+ y_align: Align.MIDDLE
+ });
+ this.elementGenerator = new IconTextElementGenerator();
+ this.translator = new Translator(this.app.metadata.uuid);
+ }
+
+ create() {
+ if (!this.app.showCurrentPhaseInfo) return;
+ const illumLabel = this.elementGenerator.generateLabel(`${ Math.floor(this.app.moon.illumination.fraction * 100 * 100) / 100 }% ` + this.translator.translate('illumination'));
+ const illumLayout = this.elementGenerator.generateLayout([illumLabel], false);
+
+ const phaseLabel = this.elementGenerator.generateLabel(this.app.moon.currentPhaseName);
+ const dateLabel = this.elementGenerator.generateLabel(new Date().toLocaleDateString(), paddingTop5Strict);
+ const timeLabel = this.elementGenerator.generateLabel(new Date().toLocaleTimeString());
+ const infoLayout = this.elementGenerator.generateLayout([phaseLabel, illumLayout, dateLabel, timeLabel], true, `${ margin5 };${ textAlignLeft }`);
+
+ this.actor.add_actor(this.elementGenerator.generateElement(this.app.moon.currentPhaseIcon, 80, [infoLayout], margin5));
+ }
+}
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/elements/iconTextElementGenerator.js b/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/elements/iconTextElementGenerator.js
new file mode 100644
index 00000000000..f9397be9cb2
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/elements/iconTextElementGenerator.js
@@ -0,0 +1,42 @@
+const { BoxLayout, Icon, IconType, Label } = imports.gi.St;
+
+class IconTextElementGenerator {
+ constructor() {}
+
+ generateElement(iconName, iconSize, layouts, rootStyleClass = '', iconStyleClass = '') {
+ const icon = this.generateIcon(iconName, iconSize);
+ const root = new BoxLayout({ style_class: rootStyleClass });
+ const iconParent = new BoxLayout({ style_class: iconStyleClass });
+
+ iconParent.add(icon);
+ root.add(iconParent);
+
+ layouts.forEach((layout) => {
+ root.add(layout);
+ });
+
+ return root;
+ }
+
+ generateLabel(text, styleClass = '') {
+ return new Label({ text: text, style_class: styleClass });
+ }
+
+ generateIcon(iconName, iconSize) {
+ return new Icon({
+ icon_name: iconName,
+ icon_size: iconSize,
+ icon_type: IconType.SYMBOLIC
+ });
+ }
+
+ generateLayout(labels, vertical, styleClass = '') {
+ const parent = new BoxLayout({ vertical: vertical, style_class: styleClass });
+
+ labels.forEach((label) => {
+ parent.add(label);
+ });
+
+ return parent;
+ }
+}
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/elements/noRiseSetElement.js b/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/elements/noRiseSetElement.js
new file mode 100644
index 00000000000..772fcae51fa
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/elements/noRiseSetElement.js
@@ -0,0 +1,63 @@
+const { margin5 } = require('./js/ui/styles');
+const { IconTextElementGenerator } = require('./js/ui/elements/iconTextElementGenerator');
+const { UiElement } = require('./js/ui/elements/uiElement');
+const { RiseSetElement } = require('./js/ui/elements/riseSetElement');
+const { Calculator } = require('./js/calc');
+const { Translator } = require('./js/translator');
+
+class NoRiseSetElement extends UiElement {
+ constructor(app) {
+ super(app);
+ const calc = new Calculator(this.app.latitude, this.app.longitude, this._addDays(new Date(), 1));
+
+ this.elementGenerator = new IconTextElementGenerator();
+ this.label = '';
+ this.iconName = '';
+ this.iconSize = 0;
+ this.moonRise = true;
+ this.tomorrowsRiseSet = calc.getRiseSetTimes();
+ this.translator = new Translator(app.metadata.uuid);
+ }
+
+ create() {
+ const icon = this.elementGenerator.generateIcon(this.iconName, this.iconSize);
+ const label = this.elementGenerator.generateLabel(this.label, margin5);
+ const layout = this.elementGenerator.generateLayout([icon, label], true, margin5);
+ const rootLayout = this.elementGenerator.generateLayout([
+ layout,
+ this.moonRise
+ ? this._createRiseElement()
+ : this._createSetElement()
+ ], false, margin5);
+
+ this.actor.add_actor(rootLayout);
+ }
+
+ _addDays(date, days) {
+ return new Date(date).setDate(date.getDate() + days);
+ }
+
+ _createRiseElement() {
+ const riseElement = new RiseSetElement(this.app);
+ riseElement.iconName = this.app.moon.iconSet.moonRise;
+ riseElement.iconSize = 64;
+ riseElement.header = this.translator.translate('Next Moonrise');
+ riseElement.dateObject = this.tomorrowsRiseSet.rise;
+ riseElement.angle = this.tomorrowsRiseSet.riseAzimuth;
+ riseElement.create();
+
+ return riseElement.actor;
+ }
+
+ _createSetElement() {
+ const setElement = new RiseSetElement(this.app);
+ setElement.iconName = this.app.moon.iconSet.moonSet;
+ setElement.iconSize = 64;
+ setElement.header = this.translator.translate('Next Moonset');
+ setElement.dateObject = this.tomorrowsRiseSet.set;
+ setElement.angle = this.tomorrowsRiseSet.setAzimuth;
+ setElement.create();
+
+ return setElement.actor;
+ }
+}
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/elements/riseSetElement.js b/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/elements/riseSetElement.js
new file mode 100644
index 00000000000..b4989770592
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/elements/riseSetElement.js
@@ -0,0 +1,36 @@
+const { marginBottom5, margin5 } = require('./js/ui/styles');
+const { UiElement } = require('./js/ui/elements/uiElement');
+const { IconTextElementGenerator } = require('./js/ui/elements/iconTextElementGenerator');
+const { Compass } = require('./js/compass');
+
+class RiseSetElement extends UiElement {
+ constructor(app) {
+ super(app);
+ this.compass = new Compass(this.app);
+ this.elementGenerator = new IconTextElementGenerator();
+ this.iconName = null;
+ this.iconSize = 0;
+ this.header = null;
+ this.dateObject = null;
+ this.angle = 0;
+ this.vertical = false;
+ }
+
+ create() {
+ const direction = this.compass.getCardinalDirection(this.angle);
+
+ const headerLabel = this.elementGenerator.generateLabel(this.header, marginBottom5);
+ const dateLabel = this.elementGenerator.generateLabel(this.dateObject.toLocaleDateString());
+ const timeLabel = this.elementGenerator.generateLabel(this.dateObject.toLocaleTimeString(), marginBottom5);
+ const datetimeLayout = this.elementGenerator.generateLayout([headerLabel, dateLabel, timeLabel], true);
+
+ const directionNameLabel = this.elementGenerator.generateLabel(direction.name);
+ const directionArrowIcon = this.elementGenerator.generateIcon(direction.icon_name, 18);
+ const directionAngleLabel = this.elementGenerator.generateLabel(`(${Math.floor(this.angle)}°)`);
+ const directionLayout = this.elementGenerator.generateLayout([directionNameLabel, directionArrowIcon, directionAngleLabel], false);
+
+ const infoLayout = this.elementGenerator.generateLayout([datetimeLayout, directionLayout], true);
+
+ this.actor.add_actor(this.elementGenerator.generateElement(this.iconName, this.iconSize, [infoLayout], margin5, margin5));
+ }
+}
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/elements/uiElement.js b/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/elements/uiElement.js
new file mode 100644
index 00000000000..fcc6632374e
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/elements/uiElement.js
@@ -0,0 +1,21 @@
+const { BoxLayout } = imports.gi.St;
+
+class UiElement {
+ constructor(app) {
+ this.app = app;
+ this.actor = new BoxLayout();
+ }
+
+ destroy() {
+ this.actor.destroy_all_children();
+ }
+
+ create() {
+ throw new Error('Must implement create abstract method');
+ }
+
+ rebuild() {
+ this.destroy();
+ this.create();
+ }
+}
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/headerUi.js b/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/headerUi.js
new file mode 100644
index 00000000000..6ad3607e389
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/headerUi.js
@@ -0,0 +1,23 @@
+const { marginBottom5 } = require('./js/ui/styles');
+const { BoxLayout } = imports.gi.St;
+const { ActorAlign } = imports.gi.Clutter;
+const { UiElement } = require('./js/ui/elements/uiElement');
+const { IconTextElementGenerator } = require('./js/ui/elements/iconTextElementGenerator');
+const { Translator } = require('./js/translator');
+
+class HeaderUi extends UiElement {
+ constructor(app) {
+ super(app);
+ this.actor = new BoxLayout({
+ x_align: ActorAlign.CENTER,
+ style_class: marginBottom5
+ });
+ this.elementGenerator = new IconTextElementGenerator();
+ this.translator = new Translator(this.app.metadata.uuid);
+ }
+
+ create() {
+ const headerLabel = this.elementGenerator.generateLabel(`${ this.translator.translate(this.app.metadata.name) } v${ this.app.metadata.version }`);
+ this.actor.add_actor(headerLabel);
+ }
+}
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/riseSetUi.js b/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/riseSetUi.js
new file mode 100644
index 00000000000..ae379a3a368
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/riseSetUi.js
@@ -0,0 +1,101 @@
+const { Translator } = require('./js/translator');
+const { IconTextElementGenerator } = require('./js/ui/elements/iconTextElementGenerator');
+const { margin5 } = require('./js/ui/styles');
+const { UiElement } = require('./js/ui/elements/uiElement');
+const { RiseSetElement } = require('./js/ui/elements/riseSetElement');
+const { NoRiseSetElement } = require('./js/ui/elements/noRiseSetElement');
+const { Align, BoxLayout, Label } = imports.gi.St;
+const { ActorAlign } = imports.gi.Clutter
+
+class RiseSetUi extends UiElement {
+ constructor(app) {
+ super(app);
+ this.actor = new BoxLayout({
+ style_class: margin5,
+ x_align: ActorAlign.CENTER,
+ y_align: Align.MIDDLE
+ });
+ this.alwaysUp = this.app.moon.riseSetTimes.alwaysUp;
+ this.alwaysDown = this.app.moon.riseSetTimes.alwaysDown;
+ this.elementGenerator = new IconTextElementGenerator();
+ this.translator = new Translator(this.app.metadata.uuid);
+ }
+
+ create() {
+ if (!this.app.showRiseSet) return;
+ if (this.alwaysUp || this.alwaysDown) {
+ this._createNoRiseSetLayout();
+ } else {
+ this._createStandardLayout();
+ }
+ }
+
+ _createNoRiseSetLayout() {
+ if (this.alwaysUp) {
+ this._createNoSetLayout();
+ } else if (this.alwaysDown) {
+ this._createNoRiseLayout();
+ }
+ }
+
+ _createNoRiseLayout() {
+ const noRiseElement = new NoRiseSetElement(this.app);
+ noRiseElement.iconName = this.app.moon.iconSet.noMoonRise;
+ noRiseElement.iconSize = 64;
+ noRiseElement.label = this.translator.translate('The moon is always down and will not rise today');
+ noRiseElement.create();
+
+ this.actor.add_actor(noRiseElement.actor);
+ }
+
+ _createNoSetLayout() {
+ const noSetElement = new NoRiseSetElement(this.app);
+ noSetElement.iconName = this.app.moon.iconSet.noMoonSet;
+ noSetElement.iconSize = 64;
+ noSetElement.label = this.translator.translate('The moon is always up and will not set today');
+ noSetElement.moonRise = false;
+ noSetElement.create();
+
+ this.actor.add_actor(noSetElement.actor);
+ }
+
+ _createStandardLayout() {
+ const riseElement = new RiseSetElement(this.app);
+ riseElement.iconName = this.app.moon.iconSet.moonRise;
+ riseElement.iconSize = 64;
+ riseElement.header = this.translator.translate('Moonrise');
+ riseElement.dateObject = this.app.moon.riseSetTimes.rise;
+ riseElement.angle = this.app.moon.riseSetTimes.riseAzimuth;
+
+ const transitElement = new RiseSetElement(this.app);
+ transitElement.iconName = this.app.moon.iconSet.nightClear;
+ transitElement.iconSize = 48;
+ transitElement.header = this.translator.translate('Lunar Noon');
+ transitElement.dateObject = this.app.moon.riseSetTimes.transit;
+ transitElement.angle = this.app.moon.riseSetTimes.transitAzimuth;
+
+ const setElement = new RiseSetElement(this.app);
+ setElement.iconName = this.app.moon.iconSet.moonSet;
+ setElement.iconSize = 64;
+ setElement.header = this.translator.translate('Moonset');
+ setElement.dateObject = this.app.moon.riseSetTimes.set;
+ setElement.angle = this.app.moon.riseSetTimes.setAzimuth;
+
+ setElement.create();
+ transitElement.create();
+ riseElement.create();
+
+ const elements = [riseElement, transitElement, setElement];
+ const orderedElements = this._orderElementsByDateAsc(elements);
+
+ orderedElements.forEach((element) => {
+ this.actor.add_actor(element.actor);
+ });
+ }
+
+ _orderElementsByDateAsc(elements) {
+ return elements.sort((a, b) => {
+ return a.dateObject - b.dateObject;
+ });
+ }
+}
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/styles.js b/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/styles.js
new file mode 100644
index 00000000000..fac1174faa0
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/js/ui/styles.js
@@ -0,0 +1,20 @@
+// padding styles
+const paddingTop3 = 'padding-top-3';
+const paddingTop5Strict = 'padding-top-5-strict';
+const padding15 = 'padding-15';
+
+// margin styles
+const margin5 = 'margin-5';
+const marginBottom5 = 'margin-bottom-5';
+const marginBottom15 = 'margin-bottom-15';
+const marginTop5 = 'margin-top-5';
+
+// font styles
+const font20 = 'font-20';
+const font15 = 'font-15';
+const font10 = 'font-10';
+
+// alignment styles
+const alignLeft = 'align-left';
+const alignCenter = 'align-center';
+const alignRight = 'align-right';
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/lib/suncalc.js b/moonphase@techi-freki/files/moonphase@techi-freki/lib/suncalc.js
deleted file mode 100644
index c9ca56d205e..00000000000
--- a/moonphase@techi-freki/files/moonphase@techi-freki/lib/suncalc.js
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- (c) 2011-2015, Vladimir Agafonkin
- SunCalc is a JavaScript library for calculating sun/moon position and light phases.
- https://github.com/mourner/suncalc
-*/
-
-(function () { 'use strict';
-
-// shortcuts for easier to read formulas
-
-var PI = Math.PI,
- sin = Math.sin,
- cos = Math.cos,
- tan = Math.tan,
- asin = Math.asin,
- atan = Math.atan2,
- acos = Math.acos,
- rad = PI / 180;
-
-// sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas
-
-
-// date/time constants and conversions
-
-var dayMs = 1000 * 60 * 60 * 24,
- J1970 = 2440588,
- J2000 = 2451545;
-
-function toJulian(date) { return date.valueOf() / dayMs - 0.5 + J1970; }
-function fromJulian(j) { return new Date((j + 0.5 - J1970) * dayMs); }
-function toDays(date) { return toJulian(date) - J2000; }
-
-
-// general calculations for position
-
-var e = rad * 23.4397; // obliquity of the Earth
-
-function rightAscension(l, b) { return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l)); }
-function declination(l, b) { return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l)); }
-
-function azimuth(H, phi, dec) { return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi)); }
-function altitude(H, phi, dec) { return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)); }
-
-function siderealTime(d, lw) { return rad * (280.16 + 360.9856235 * d) - lw; }
-
-function astroRefraction(h) {
- if (h < 0) // the following formula works for positive altitudes only.
- h = 0; // if h = -0.08901179 a div/0 would occur.
-
- // formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
- // 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad:
- return 0.0002967 / Math.tan(h + 0.00312536 / (h + 0.08901179));
-}
-
-// general sun calculations
-
-function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); }
-
-function eclipticLongitude(M) {
-
- var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center
- P = rad * 102.9372; // perihelion of the Earth
-
- return M + C + P + PI;
-}
-
-function sunCoords(d) {
-
- var M = solarMeanAnomaly(d),
- L = eclipticLongitude(M);
-
- return {
- dec: declination(L, 0),
- ra: rightAscension(L, 0)
- };
-}
-
-
-var SunCalc = {};
-
-
-// calculates sun position for a given date and latitude/longitude
-
-SunCalc.getPosition = function (date, lat, lng) {
-
- var lw = rad * -lng,
- phi = rad * lat,
- d = toDays(date),
-
- c = sunCoords(d),
- H = siderealTime(d, lw) - c.ra;
-
- return {
- azimuth: azimuth(H, phi, c.dec),
- altitude: altitude(H, phi, c.dec)
- };
-};
-
-
-// sun times configuration (angle, morning name, evening name)
-
-var times = SunCalc.times = [
- [-0.833, 'sunrise', 'sunset' ],
- [ -0.3, 'sunriseEnd', 'sunsetStart' ],
- [ -6, 'dawn', 'dusk' ],
- [ -12, 'nauticalDawn', 'nauticalDusk'],
- [ -18, 'nightEnd', 'night' ],
- [ 6, 'goldenHourEnd', 'goldenHour' ]
-];
-
-// adds a custom time to the times config
-
-SunCalc.addTime = function (angle, riseName, setName) {
- times.push([angle, riseName, setName]);
-};
-
-
-// calculations for sun times
-
-var J0 = 0.0009;
-
-function julianCycle(d, lw) { return Math.round(d - J0 - lw / (2 * PI)); }
-
-function approxTransit(Ht, lw, n) { return J0 + (Ht + lw) / (2 * PI) + n; }
-function solarTransitJ(ds, M, L) { return J2000 + ds + 0.0053 * sin(M) - 0.0069 * sin(2 * L); }
-
-function hourAngle(h, phi, d) { return acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d))); }
-function observerAngle(height) { return -2.076 * Math.sqrt(height) / 60; }
-
-// returns set time for the given sun altitude
-function getSetJ(h, lw, phi, dec, n, M, L) {
-
- var w = hourAngle(h, phi, dec),
- a = approxTransit(w, lw, n);
- return solarTransitJ(a, M, L);
-}
-
-
-// calculates sun times for a given date, latitude/longitude, and, optionally,
-// the observer height (in meters) relative to the horizon
-
-SunCalc.getTimes = function (date, lat, lng, height) {
-
- height = height || 0;
-
- var lw = rad * -lng,
- phi = rad * lat,
-
- dh = observerAngle(height),
-
- d = toDays(date),
- n = julianCycle(d, lw),
- ds = approxTransit(0, lw, n),
-
- M = solarMeanAnomaly(ds),
- L = eclipticLongitude(M),
- dec = declination(L, 0),
-
- Jnoon = solarTransitJ(ds, M, L),
-
- i, len, time, h0, Jset, Jrise;
-
-
- var result = {
- solarNoon: fromJulian(Jnoon),
- nadir: fromJulian(Jnoon - 0.5)
- };
-
- for (i = 0, len = times.length; i < len; i += 1) {
- time = times[i];
- h0 = (time[0] + dh) * rad;
-
- Jset = getSetJ(h0, lw, phi, dec, n, M, L);
- Jrise = Jnoon - (Jset - Jnoon);
-
- result[time[1]] = fromJulian(Jrise);
- result[time[2]] = fromJulian(Jset);
- }
-
- return result;
-};
-
-
-// moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas
-
-function moonCoords(d) { // geocentric ecliptic coordinates of the moon
-
- var L = rad * (218.316 + 13.176396 * d), // ecliptic longitude
- M = rad * (134.963 + 13.064993 * d), // mean anomaly
- F = rad * (93.272 + 13.229350 * d), // mean distance
-
- l = L + rad * 6.289 * sin(M), // longitude
- b = rad * 5.128 * sin(F), // latitude
- dt = 385001 - 20905 * cos(M); // distance to the moon in km
-
- return {
- ra: rightAscension(l, b),
- dec: declination(l, b),
- dist: dt
- };
-}
-
-SunCalc.getMoonPosition = function (date, lat, lng) {
-
- var lw = rad * -lng,
- phi = rad * lat,
- d = toDays(date),
-
- c = moonCoords(d),
- H = siderealTime(d, lw) - c.ra,
- h = altitude(H, phi, c.dec),
- // formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
- pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H));
-
- h = h + astroRefraction(h); // altitude correction for refraction
-
- return {
- azimuth: azimuth(H, phi, c.dec),
- altitude: h,
- distance: c.dist,
- parallacticAngle: pa
- };
-};
-
-
-// calculations for illumination parameters of the moon,
-// based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and
-// Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
-
-SunCalc.getMoonIllumination = function (date) {
-
- var d = toDays(date || new Date()),
- s = sunCoords(d),
- m = moonCoords(d),
-
- sdist = 149598000, // distance from Earth to Sun in km
-
- phi = acos(sin(s.dec) * sin(m.dec) + cos(s.dec) * cos(m.dec) * cos(s.ra - m.ra)),
- inc = atan(sdist * sin(phi), m.dist - sdist * cos(phi)),
- angle = atan(cos(s.dec) * sin(s.ra - m.ra), sin(s.dec) * cos(m.dec) -
- cos(s.dec) * sin(m.dec) * cos(s.ra - m.ra));
-
- return {
- fraction: (1 + cos(inc)) / 2,
- phase: 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI,
- angle: angle
- };
-};
-
-
-function hoursLater(date, h) {
- return new Date(date.valueOf() + h * dayMs / 24);
-}
-
-// calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article
-
-SunCalc.getMoonTimes = function (date, lat, lng, inUTC) {
- var t = new Date(date);
- if (inUTC) t.setUTCHours(0, 0, 0, 0);
- else t.setHours(0, 0, 0, 0);
-
- var hc = 0.133 * rad,
- h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc,
- h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx;
-
- // go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set)
- for (var i = 1; i <= 24; i += 2) {
- h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc;
- h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc;
-
- a = (h0 + h2) / 2 - h1;
- b = (h2 - h0) / 2;
- xe = -b / (2 * a);
- ye = (a * xe + b) * xe + h1;
- d = b * b - 4 * a * h1;
- roots = 0;
-
- if (d >= 0) {
- dx = Math.sqrt(d) / (Math.abs(a) * 2);
- x1 = xe - dx;
- x2 = xe + dx;
- if (Math.abs(x1) <= 1) roots++;
- if (Math.abs(x2) <= 1) roots++;
- if (x1 < -1) x1 = x2;
- }
-
- if (roots === 1) {
- if (h0 < 0) rise = i + x1;
- else set = i + x1;
-
- } else if (roots === 2) {
- rise = i + (ye < 0 ? x2 : x1);
- set = i + (ye < 0 ? x1 : x2);
- }
-
- if (rise && set) break;
-
- h0 = h2;
- }
-
- var result = {};
-
- if (rise) result.rise = hoursLater(t, rise);
- if (set) result.set = hoursLater(t, set);
-
- if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true;
-
- return result;
-};
-
-
-// export as Node module / AMD module / browser variable
-if (typeof exports === 'object' && typeof module !== 'undefined') module.exports = SunCalc;
-else if (typeof define === 'function' && define.amd) define(SunCalc);
-else window.SunCalc = SunCalc;
-
-}());
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/lib/suncalc3.js b/moonphase@techi-freki/files/moonphase@techi-freki/lib/suncalc3.js
new file mode 100644
index 00000000000..6ccf03e8ff3
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/lib/suncalc3.js
@@ -0,0 +1,1241 @@
+// @ts-check
+/*
+ (c) 2011-2015, Vladimir Agafonkin
+ SunCalc is a JavaScript library for calculating sun/moon position and light phases.
+ https://github.com/mourner/suncalc
+
+ Reworked and enhanced by Robert Gester
+ Additional Copyright (c) 2022 Robert Gester
+ https://github.com/hypnos3/suncalc3
+*/
+
+/**
+ * @typedef {Object} ISunTimeDef
+ * @property {string} name - The Name of the time
+ * @property {Date} value - Date object with the calculated sun-time
+ * @property {number} ts - The time as timestamp
+ * @property {number} pos - The position of the sun on the time
+ * @property {number} [elevation] - Angle of the sun on the time (except for solarNoon / nadir)
+ * @property {number} julian - The time as Julian calendar
+ * @property {boolean} valid - indicates if the time is valid or not
+ * @property {boolean} [deprecated] - indicates if the time is a deprecated time name
+ * @property {string} [nameOrg] - if it is a deprecated name, the original property name
+ * @property {number} [posOrg] - if it is a deprecated name, the original position
+ */
+
+/**
+ * @typedef {Object} ISunTimeSingle
+ * @property {ISunTimeDef} rise - sun-time for sun rise
+ * @property {ISunTimeDef} set - sun-time for sun set
+ * @property {string} [error] - string of an error message if an error occurs
+ */
+
+/**
+ * @typedef {Object} ISunTimeList
+ * @property {ISunTimeDef} solarNoon - The sun-time for the solar noon (sun is in the highest position)
+ * @property {ISunTimeDef} nadir - The sun-time for nadir (darkest moment of the night, sun is in the lowest position)
+ * @property {ISunTimeDef} goldenHourDawnStart - The sun-time for morning golden hour (soft light, best time for photography)
+ * @property {ISunTimeDef} goldenHourDawnEnd - The sun-time for morning golden hour (soft light, best time for photography)
+ * @property {ISunTimeDef} goldenHourDuskStart - The sun-time for evening golden hour starts
+ * @property {ISunTimeDef} goldenHourDuskEnd - The sun-time for evening golden hour starts
+ * @property {ISunTimeDef} sunriseStart - The sun-time for sunrise starts (top edge of the sun appears on the horizon)
+ * @property {ISunTimeDef} sunriseEnd - The sun-time for sunrise ends (bottom edge of the sun touches the horizon)
+ * @property {ISunTimeDef} sunsetStart - The sun-time for sunset starts (bottom edge of the sun touches the horizon)
+ * @property {ISunTimeDef} sunsetEnd - The sun-time for sunset ends (sun disappears below the horizon, evening civil twilight starts)
+ * @property {ISunTimeDef} blueHourDawnStart - The sun-time for blue Hour start (time for special photography photos starts)
+ * @property {ISunTimeDef} blueHourDawnEnd - The sun-time for blue Hour end (time for special photography photos end)
+ * @property {ISunTimeDef} blueHourDuskStart - The sun-time for blue Hour start (time for special photography photos starts)
+ * @property {ISunTimeDef} blueHourDuskEnd - The sun-time for blue Hour end (time for special photography photos end)
+ * @property {ISunTimeDef} civilDawn - The sun-time for dawn (morning nautical twilight ends, morning civil twilight starts)
+ * @property {ISunTimeDef} civilDusk - The sun-time for dusk (evening nautical twilight starts)
+ * @property {ISunTimeDef} nauticalDawn - The sun-time for nautical dawn (morning nautical twilight starts)
+ * @property {ISunTimeDef} nauticalDusk - The sun-time for nautical dusk end (evening astronomical twilight starts)
+ * @property {ISunTimeDef} amateurDawn - The sun-time for amateur astronomical dawn (sun at 12° before sunrise)
+ * @property {ISunTimeDef} amateurDusk - The sun-time for amateur astronomical dusk (sun at 12° after sunrise)
+ * @property {ISunTimeDef} astronomicalDawn - The sun-time for night ends (morning astronomical twilight starts)
+ * @property {ISunTimeDef} astronomicalDusk - The sun-time for night starts (dark enough for astronomical observations)
+ * @property {ISunTimeDef} [dawn] - Deprecated: alternate for civilDawn
+ * @property {ISunTimeDef} [dusk] - Deprecated: alternate for civilDusk
+ * @property {ISunTimeDef} [nightEnd] - Deprecated: alternate for astronomicalDawn
+ * @property {ISunTimeDef} [night] - Deprecated: alternate for astronomicalDusk
+ * @property {ISunTimeDef} [nightStart] - Deprecated: alternate for astronomicalDusk
+ * @property {ISunTimeDef} [goldenHour] - Deprecated: alternate for goldenHourDuskStart
+ * @property {ISunTimeDef} [sunset] - Deprecated: alternate for sunsetEnd
+ * @property {ISunTimeDef} [sunrise] - Deprecated: alternate for sunriseStart
+ * @property {ISunTimeDef} [goldenHourEnd] - Deprecated: alternate for goldenHourDawnEnd
+ * @property {ISunTimeDef} [goldenHourStart] - Deprecated: alternate for goldenHourDuskStart
+ */
+
+/**
+ * @typedef ISunTimeNames
+ * @type {Object}
+ * @property {number} angle - angle of the sun position in degrees
+ * @property {string} riseName - name of sun rise (morning name)
+ * @property {string} setName - name of sun set (evening name)
+ * @property {number} [risePos] - (optional) position at rise
+ * @property {number} [setPos] - (optional) position at set
+ */
+
+
+/**
+ * @typedef {Object} ISunCoordinates
+ * @property {number} dec - The declination of the sun
+ * @property {number} ra - The right ascension of the sun
+ */
+
+/**
+ * @typedef {Object} ISunPosition
+ * @property {number} azimuth - The azimuth above the horizon of the sun in radians
+ * @property {number} altitude - The altitude of the sun in radians
+ * @property {number} zenith - The zenith of the sun in radians
+ * @property {number} azimuthDegrees - The azimuth of the sun in decimal degree
+ * @property {number} altitudeDegrees - The altitude of the sun in decimal degree
+ * @property {number} zenithDegrees - The zenith of the sun in decimal degree
+ * @property {number} declination - The declination of the sun
+ */
+
+/**
+ * @typedef {Object} IMoonPosition
+ * @property {number} azimuth - The moon azimuth in radians
+ * @property {number} altitude - The moon altitude above the horizon in radians
+ * @property {number} azimuthDegrees - The moon azimuth in degree
+ * @property {number} altitudeDegrees - The moon altitude above the horizon in degree
+ * @property {number} distance - The distance of the moon to the earth in kilometers
+ * @property {number} parallacticAngle - The parallactic angle of the moon
+ * @property {number} parallacticAngleDegrees - The parallactic angle of the moon in degree
+ */
+
+
+/**
+ * @typedef {Object} IDateObj
+ * @property {string} date - The Date as a ISO String YYYY-MM-TTTHH:MM:SS.mmmmZ
+ * @property {number} value - The Date as the milliseconds since 1.1.1970 0:00 UTC
+ */
+
+/**
+ * @typedef {Object} IPhaseObj
+ * @property {number} from - The phase start
+ * @property {number} to - The phase end
+ * @property {('newMoon'|'waxingCrescentMoon'|'firstQuarterMoon'|'waxingGibbousMoon'|'fullMoon'|'waningGibbousMoon'|'thirdQuarterMoon'|'waningCrescentMoon')} id - id of the phase
+ * @property {string} emoji - unicode symbol of the phase
+ * @property {string} name - name of the phase
+ * @property {string} id - phase name
+ * @property {number} weight - weight of the phase
+ * @property {string} css - a css value of the phase
+ * @property {string} [nameAlt] - an alernate name (not used by this library)
+ * @property {string} [tag] - additional tag (not used by this library)
+ */
+
+/**
+ * @typedef {Object} IMoonIlluminationNext
+ * @property {string} date - The Date as a ISO String YYYY-MM-TTTHH:MM:SS.mmmmZ of the next phase
+ * @property {number} value - The Date as the milliseconds since 1.1.1970 0:00 UTC of the next phase
+ * @property {string} type - The name of the next phase [newMoon, fullMoon, firstQuarter, thirdQuarter]
+ * @property {IDateObj} newMoon - Date of the next new moon
+ * @property {IDateObj} fullMoon - Date of the next full moon
+ * @property {IDateObj} firstQuarter - Date of the next first quater of the moon
+ * @property {IDateObj} thirdQuarter - Date of the next third/last quater of the moon
+ */
+
+/**
+ * @typedef {Object} IMoonIllumination
+ * @property {number} fraction - illuminated fraction of the moon; varies from `0.0` (new moon) to `1.0` (full moon)
+ * @property {IPhaseObj} phase - moon phase as object
+ * @property {number} phaseValue - The phase of the moon in the current cycle; varies from `0.0` to `1.0`
+ * @property {number} angle - The midpoint angle in radians of the illuminated limb of the moon reckoned eastward from the north point of the disk;
+ * @property {IMoonIlluminationNext} next - object containing information about the next phases of the moon
+ * @remarks the moon is waxing if the angle is negative, and waning if positive
+ */
+
+/**
+ * @typedef {Object} IMoonDataInst
+ * @property {number} zenithAngle - The zenith angle of the moon
+ * @property {IMoonIllumination} illumination - object containing information about the next phases of the moon
+ *
+ * @typedef {IMoonPosition & IMoonDataInst} IMoonData
+ */
+
+/**
+ * @typedef {Object} IMoonTimes
+ * @property {Date|NaN} rise - a Date object if the moon is rising on the given Date, otherwise NaN
+ * @property {Date|NaN} set - a Date object if the moon is setting on the given Date, otherwise NaN
+ * @property {boolean} alwaysUp - is true if the moon never rises/sets and is always _above_ the horizon during the day
+ * @property {boolean} alwaysDown - is true if the moon is always _below_ the horizon
+ * @property {Date} [highest] - Date of the highest position, only avalílable if set and rise is not NaN
+ */
+
+(function () {
+ 'use strict';
+ // sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas
+
+ // shortcuts for easier to read formulas
+ const sin = Math.sin;
+ const cos = Math.cos;
+ const tan = Math.tan;
+ const asin = Math.asin;
+ const atan = Math.atan2;
+ const acos = Math.acos;
+ const rad = Math.PI / 180;
+ const degr = 180 / Math.PI;
+
+ // date/time constants and conversions
+ const dayMs = 86400000; // 1000 * 60 * 60 * 24;
+ const J1970 = 2440587.5;
+ const J2000 = 2451545;
+
+ const lunarDaysMs = 2551442778; // The duration in days of a lunar cycle is 29.53058770576
+ const firstNewMoon2000 = 947178840000; // first newMoon in the year 2000 2000-01-06 18:14
+
+ /**
+ * convert date from Julian calendar
+ * @param {number} j - day number in Julian calendar to convert
+ * @return {number} result date as timestamp
+ */
+ function fromJulianDay(j) {
+ return (j - J1970) * dayMs;
+ }
+
+ /**
+ * get number of days for a dateValue since 2000
+ * @param {number} dateValue date as timestamp to get days
+ * @return {number} count of days
+ */
+ function toDays(dateValue) {
+ return ((dateValue / dayMs) + J1970) - J2000;
+ }
+
+ // general calculations for position
+
+ const e = rad * 23.4397; // obliquity of the Earth
+
+ /**
+ * get right ascension
+ * @param {number} l
+ * @param {number} b
+ * @returns {number}
+ */
+ function rightAscension(l, b) {
+ return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l));
+ }
+
+ /**
+ * get declination
+ * @param {number} l
+ * @param {number} b
+ * @returns {number}
+ */
+ function declination(l, b) {
+ return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l));
+ }
+
+ /**
+ * get azimuth
+ * @param {number} H - siderealTime
+ * @param {number} phi - PI constant
+ * @param {number} dec - The declination of the sun
+ * @returns {number} azimuth in rad
+ */
+ function azimuthCalc(H, phi, dec) {
+ return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi)) + Math.PI;
+ }
+
+ /**
+ * get altitude
+ * @param {number} H - siderealTime
+ * @param {number} phi - PI constant
+ * @param {number} dec - The declination of the sun
+ * @returns {number}
+ */
+ function altitudeCalc(H, phi, dec) {
+ return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H));
+ }
+
+ /**
+ * side real time
+ * @param {number} d
+ * @param {number} lw
+ * @returns {number}
+ */
+ function siderealTime(d, lw) {
+ return rad * (280.16 + 360.9856235 * d) - lw;
+ }
+
+ /**
+ * get astro refraction
+ * @param {number} h
+ * @returns {number}
+ */
+ function astroRefraction(h) {
+ if (h < 0) { // the following formula works for positive altitudes only.
+ h = 0;
+ } // if h = -0.08901179 a div/0 would occur.
+
+ // formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
+ // 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad:
+ return 0.0002967 / Math.tan(h + 0.00312536 / (h + 0.08901179));
+ }
+ // general sun calculations
+ /**
+ * get solar mean anomaly
+ * @param {number} d
+ * @returns {number}
+ */
+ function solarMeanAnomaly(d) {
+ return rad * (357.5291 + 0.98560028 * d);
+ }
+
+ /**
+ * ecliptic longitude
+ * @param {number} M
+ * @returns {number}
+ */
+ function eclipticLongitude(M) {
+ const C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M));
+ // equation of center
+ const P = rad * 102.9372; // perihelion of the Earth
+ return M + C + P + Math.PI;
+ }
+
+ /**
+ * sun coordinates
+ * @param {number} d days in Julian calendar
+ * @returns {ISunCoordinates}
+ */
+ function sunCoords(d) {
+ const M = solarMeanAnomaly(d);
+ const L = eclipticLongitude(M);
+
+ return {
+ dec: declination(L, 0),
+ ra: rightAscension(L, 0)
+ };
+ }
+
+ const SunCalc = {};
+
+ /**
+ * calculates sun position for a given date and latitude/longitude
+ * @param {number|Date} dateValue Date object or timestamp for calculating sun-position
+ * @param {number} lat latitude for calculating sun-position
+ * @param {number} lng longitude for calculating sun-position
+ * @return {ISunPosition} result object of sun-position
+ */
+ SunCalc.getPosition = function (dateValue, lat, lng) {
+ // console.log(`getPosition dateValue=${dateValue} lat=${lat}, lng=${lng}`);
+ if (isNaN(lat)) {
+ throw new Error('latitude missing');
+ }
+ if (isNaN(lng)) {
+ throw new Error('longitude missing');
+ }
+ if (dateValue instanceof Date) {
+ dateValue = dateValue.valueOf();
+ }
+ const lw = rad * -lng;
+ const phi = rad * lat;
+ const d = toDays(dateValue);
+ const c = sunCoords(d);
+ const H = siderealTime(d, lw) - c.ra;
+ const azimuth = azimuthCalc(H, phi, c.dec);
+ const altitude = altitudeCalc(H, phi, c.dec);
+ // console.log(`getPosition date=${date}, M=${H}, L=${H}, c=${JSON.stringify(c)}, d=${d}, lw=${lw}, phi=${phi}`);
+
+ return {
+ azimuth,
+ altitude,
+ zenith: (90*Math.PI/180) - altitude,
+ azimuthDegrees: degr * azimuth,
+ altitudeDegrees: degr * altitude,
+ zenithDegrees: 90 - (degr * altitude),
+ declination: c.dec
+ };
+ };
+
+ /** sun times configuration
+ * @type {Array.}
+ */
+ const sunTimes = SunCalc.times = [
+ { angle: 6, riseName: 'goldenHourDawnEnd', setName: 'goldenHourDuskStart'}, // GOLDEN_HOUR_2
+ { angle: -0.3, riseName: 'sunriseEnd', setName: 'sunsetStart'}, // SUNRISE_END
+ { angle: -0.833, riseName: 'sunriseStart', setName: 'sunsetEnd'}, // SUNRISE
+ { angle: -1, riseName: 'goldenHourDawnStart', setName: 'goldenHourDuskEnd'}, // GOLDEN_HOUR_1
+ { angle: -4, riseName: 'blueHourDawnEnd', setName: 'blueHourDuskStart'}, // BLUE_HOUR
+ { angle: -6, riseName: 'civilDawn', setName: 'civilDusk'}, // DAWN
+ { angle: -8, riseName: 'blueHourDawnStart', setName: 'blueHourDuskEnd'}, // BLUE_HOUR
+ { angle: -12, riseName: 'nauticalDawn', setName: 'nauticalDusk'}, // NAUTIC_DAWN
+ { angle: -15, riseName: 'amateurDawn', setName: 'amateurDusk'},
+ { angle: -18, riseName: 'astronomicalDawn', setName: 'astronomicalDusk'} // ASTRO_DAWN
+ ];
+
+ /** alternate time names for backward compatibility
+ * @type {Array.<[string, string]>}
+ */
+ const suntimesDeprecated = SunCalc.timesDeprecated = [
+ ['dawn', 'civilDawn'],
+ ['dusk', 'civilDusk'],
+ ['nightEnd', 'astronomicalDawn'],
+ ['night', 'astronomicalDusk'],
+ ['nightStart', 'astronomicalDusk'],
+ ['goldenHour', 'goldenHourDuskStart'],
+ ['sunrise', 'sunriseStart'],
+ ['sunset', 'sunsetEnd'],
+ ['goldenHourEnd', 'goldenHourDawnEnd'],
+ ['goldenHourStart', 'goldenHourDuskStart']
+ ];
+
+ /** adds a custom time to the times config
+ * @param {number} angleAltitude - angle of Altitude/elevation above the horizont of the sun in degrees
+ * @param {string} riseName - name of sun rise (morning name)
+ * @param {string} setName - name of sun set (evening name)
+ * @param {number} [risePos] - (optional) position at rise (morning)
+ * @param {number} [setPos] - (optional) position at set (evening)
+ * @param {boolean} [degree=true] defines if the elevationAngle is in degree not in radians
+ * @return {Boolean} true if new time could be added, false if not (parameter missing; riseName or setName already existing)
+ */
+ SunCalc.addTime = function (angleAltitude, riseName, setName, risePos, setPos, degree) {
+ let isValid = (typeof riseName === 'string') && (riseName.length > 0) &&
+ (typeof setName === 'string') && (setName.length > 0) &&
+ (typeof angleAltitude === 'number');
+ if (isValid) {
+ const EXP = /^(?![0-9])[a-zA-Z0-9$_]+$/;
+ // check for invalid names
+ for (let i=0; i= 0; i--) {
+ if (suntimesDeprecated[i][0] === riseName || suntimesDeprecated[i][0] === setName) {
+ suntimesDeprecated.splice(i, 1);
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ };
+
+ /**
+ * add an alternate name for a sun time
+ * @param {string} alternameName - alternate or deprecated time name
+ * @param {string} originalName - original time name from SunCalc.times array
+ * @return {Boolean} true if could be added, false if not (parameter missing; originalName does not exists; alternameName already existis)
+ */
+ SunCalc.addDeprecatedTimeName = function (alternameName, originalName) {
+ let isValid = (typeof alternameName === 'string') && (alternameName.length > 0) &&
+ (typeof originalName === 'string') && (originalName.length > 0);
+ if (isValid) {
+ let hasOrg = false;
+ const EXP = /^(?![0-9])[a-zA-Z0-9$_]+$/;
+ // check for invalid names
+ for (let i=0; i 200) {
+ // let nazi = this.getPosition(dateVal, lat, lng).azimuth;
+ const d = toDays(dateVal);
+ const c = sunCoords(d);
+ const H = siderealTime(d, lw) - c.ra;
+ const nazim = azimuthCalc(H, phi, c.dec);
+
+ addval /= 2;
+ if (nazim < nazimuth) {
+ dateVal += addval;
+ } else {
+ dateVal -= addval;
+ }
+ }
+ return new Date(Math.floor(dateVal));
+ };
+
+ // calculation for solar time based on https://www.pveducation.org/pvcdrom/properties-of-sunlight/solar-time
+
+ /**
+ * Calculaes the solar time of the given date in the given latitude and UTC offset.
+ * @param {number|Date} dateValue Date object or timestamp for calculating solar time
+ * @param {number} lng longitude for calculating sun-time
+ * @param {number} utcOffset offset to the utc time
+ * @returns {Date} Returns the solar time of the given date in the given latitude and UTC offset.
+ */
+ SunCalc.getSolarTime = function (dateValue, lng, utcOffset) {
+ // @ts-ignore
+ const date = new Date(dateValue);
+ // calculate the day of year
+ const start = new Date(date.getFullYear(), 0, 0);
+ const diff = (date.getTime() - start.getTime()) + ((start.getTimezoneOffset() - date.getTimezoneOffset()) * 60 * 1000);
+ const dayOfYear = Math.floor(diff / dayMs);
+
+ const b = 360 / 365 * (dayOfYear - 81) * rad;
+ const equationOfTime = 9.87 * sin(2 * b) - 7.53 * cos(b) - 1.5 * sin(b);
+ const localSolarTimeMeridian = 15 * utcOffset;
+ const timeCorrection = equationOfTime + 4 * (lng - localSolarTimeMeridian);
+ const localSolarTime = date.getHours() + timeCorrection / 60 + date.getMinutes() / 60;
+
+ const solarDate = new Date(0, 0);
+ solarDate.setMinutes(+localSolarTime * 60);
+ return solarDate;
+ };
+
+ // moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas
+
+ /**
+ * calculate the geocentric ecliptic coordinates of the moon
+ * @param {number} d number of days
+ */
+ function moonCoords(d) {
+ const L = rad * (218.316 + 13.176396 * d); // ecliptic longitude
+ const M = rad * (134.963 + 13.064993 * d); // mean anomaly
+ const F = rad * (93.272 + 13.229350 * d); // mean distance
+ const l = L + rad * 6.289 * sin(M); // longitude
+ const b = rad * 5.128 * sin(F); // latitude
+ const dt = 385001 - 20905 * cos(M); // distance to the moon in km
+
+ return {
+ ra: rightAscension(l, b),
+ dec: declination(l, b),
+ dist: dt
+ };
+ }
+
+ /**
+ * calculates moon position for a given date and latitude/longitude
+ * @param {number|Date} dateValue Date object or timestamp for calculating moon-position
+ * @param {number} lat latitude for calculating moon-position
+ * @param {number} lng longitude for calculating moon-position
+ * @return {IMoonPosition} result object of moon-position
+ */
+ SunCalc.getMoonPosition = function (dateValue, lat, lng) {
+ // console.log(`getMoonPosition dateValue=${dateValue} lat=${lat}, lng=${lng}`);
+ if (isNaN(lat)) {
+ throw new Error('latitude missing');
+ }
+ if (isNaN(lng)) {
+ throw new Error('longitude missing');
+ }
+ if (dateValue instanceof Date) {
+ dateValue = dateValue.valueOf();
+ }
+ const lw = rad * -lng;
+ const phi = rad * lat;
+ const d = toDays(dateValue);
+ const c = moonCoords(d);
+ const H = siderealTime(d, lw) - c.ra;
+ let altitude = altitudeCalc(H, phi, c.dec);
+ altitude += astroRefraction(altitude); // altitude correction for refraction
+
+ // formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
+ const pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H));
+
+ const azimuth = azimuthCalc(H, phi, c.dec);
+
+ return {
+ azimuth,
+ altitude,
+ azimuthDegrees: degr * azimuth,
+ altitudeDegrees: degr * altitude,
+ distance: c.dist,
+ parallacticAngle: pa,
+ parallacticAngleDegrees: degr * pa
+ };
+ };
+
+ const fractionOfTheMoonCycle = SunCalc.moonCycles = [{
+ from: 0,
+ to: 0.033863193308711,
+ id: 'newMoon',
+ emoji: '🌚',
+ code: ':new_moon_with_face:',
+ name: 'New Moon',
+ weight: 1,
+ css: 'wi-moon-new'
+ },
+ {
+ from: 0.033863193308711,
+ to: 0.216136806691289,
+ id: 'waxingCrescentMoon',
+ emoji: '🌒',
+ code: ':waxing_crescent_moon:',
+ name: 'Waxing Crescent',
+ weight: 6.3825,
+ css: 'wi-moon-wax-cres'
+ },
+ {
+ from: 0.216136806691289,
+ to: 0.283863193308711,
+ id: 'firstQuarterMoon',
+ emoji: '🌓',
+ code: ':first_quarter_moon:',
+ name: 'First Quarter',
+ weight: 1,
+ css: 'wi-moon-first-quart'
+ },
+ {
+ from: 0.283863193308711,
+ to: 0.466136806691289,
+ id: 'waxingGibbousMoon',
+ emoji: '🌔',
+ code: ':waxing_gibbous_moon:',
+ name: 'Waxing Gibbous',
+ weight: 6.3825,
+ css: 'wi-moon-wax-gibb'
+ },
+ {
+ from: 0.466136806691289,
+ to: 0.533863193308711,
+ id: 'fullMoon',
+ emoji: '🌝',
+ code: ':full_moon_with_face:',
+ name: 'Full Moon',
+ weight: 1,
+ css: 'wi-moon-full'
+ },
+ {
+ from: 0.533863193308711,
+ to: 0.716136806691289,
+ id: 'waningGibbousMoon',
+ emoji: '🌖',
+ code: ':waning_gibbous_moon:',
+ name: 'Waning Gibbous',
+ weight: 6.3825,
+ css: 'wi-moon-wan-gibb'
+ },
+ {
+ from: 0.716136806691289,
+ to: 0.783863193308711,
+ id: 'thirdQuarterMoon',
+ emoji: '🌗',
+ code: ':last_quarter_moon:',
+ name: 'third Quarter',
+ weight: 1,
+ css: 'wi-moon-third-quart'
+ },
+ {
+ from: 0.783863193308711,
+ to: 0.966136806691289,
+ id: 'waningCrescentMoon',
+ emoji: '🌘',
+ code: ':waning_crescent_moon:',
+ name: 'Waning Crescent',
+ weight: 6.3825,
+ css: 'wi-moon-wan-cres'
+ },
+ {
+ from: 0.966136806691289,
+ to: 1,
+ id: 'newMoon',
+ emoji: '🌚',
+ code: ':new_moon_with_face:',
+ name: 'New Moon',
+ weight: 1,
+ css: 'wi-moon-new'
+ }];
+
+ /**
+ * calculations for illumination parameters of the moon,
+ * based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and
+ * Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
+ * @param {number|Date} dateValue Date object or timestamp for calculating moon-illumination
+ * @return {IMoonIllumination} result object of moon-illumination
+ */
+ SunCalc.getMoonIllumination = function (dateValue) {
+ // console.log(`getMoonIllumination dateValue=${dateValue}`);
+ if (dateValue instanceof Date) {
+ dateValue = dateValue.valueOf();
+ }
+ const d = toDays(dateValue);
+ const s = sunCoords(d);
+ const m = moonCoords(d);
+ const sdist = 149598000; // distance from Earth to Sun in km
+ const phi = acos(sin(s.dec) * sin(m.dec) + cos(s.dec) * cos(m.dec) * cos(s.ra - m.ra));
+ const inc = atan(sdist * sin(phi), m.dist - sdist * cos(phi));
+ const angle = atan(cos(s.dec) * sin(s.ra - m.ra), sin(s.dec) * cos(m.dec) -
+ cos(s.dec) * sin(m.dec) * cos(s.ra - m.ra));
+ const phaseValue = 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI;
+
+ // calculates the difference in ms between the sirst fullMoon 2000 and given Date
+ const diffBase = dateValue - firstNewMoon2000;
+ // Calculate modulus to drop completed cycles
+ let cycleModMs = diffBase % lunarDaysMs;
+ // If negative number (date before new moon 2000) add lunarDaysMs
+ if ( cycleModMs < 0 ) { cycleModMs += lunarDaysMs; }
+ const nextNewMoon = (lunarDaysMs - cycleModMs) + dateValue;
+ let nextFullMoon = ((lunarDaysMs/2) - cycleModMs) + dateValue;
+ if (nextFullMoon < dateValue) { nextFullMoon += lunarDaysMs; }
+ const quater = (lunarDaysMs/4);
+ let nextFirstQuarter = (quater - cycleModMs) + dateValue;
+ if (nextFirstQuarter < dateValue) { nextFirstQuarter += lunarDaysMs; }
+ let nextThirdQuarter = (lunarDaysMs - quater - cycleModMs) + dateValue;
+ if (nextThirdQuarter < dateValue) { nextThirdQuarter += lunarDaysMs; }
+ // Calculate the fraction of the moon cycle
+ // const currentfrac = cycleModMs / lunarDaysMs;
+ const next = Math.min(nextNewMoon, nextFirstQuarter, nextFullMoon, nextThirdQuarter);
+ let phase;
+
+ for (let index = 0; index < fractionOfTheMoonCycle.length; index++) {
+ const element = fractionOfTheMoonCycle[index];
+ if ( (phaseValue >= element.from) && (phaseValue <= element.to) ) {
+ phase = element;
+ break;
+ }
+ }
+
+ return {
+ fraction: (1 + cos(inc)) / 2,
+ // fraction2: cycleModMs / lunarDaysMs,
+ // @ts-ignore
+ phase,
+ phaseValue,
+ angle,
+ next : {
+ value: next,
+ date: (new Date(next)).toISOString(),
+ type: (next === nextNewMoon) ? 'newMoon' : ((next === nextFirstQuarter) ? 'firstQuarter' : ((next === nextFullMoon) ? 'fullMoon' : 'thirdQuarter')),
+ newMoon: {
+ value: nextNewMoon,
+ date: (new Date(nextNewMoon)).toISOString()
+ },
+ fullMoon: {
+ value: nextFullMoon,
+ date: (new Date(nextFullMoon)).toISOString()
+ },
+ firstQuarter: {
+ value: nextFirstQuarter,
+ date: (new Date(nextFirstQuarter)).toISOString()
+ },
+ thirdQuarter: {
+ value: nextThirdQuarter,
+ date: (new Date(nextThirdQuarter)).toISOString()
+ }
+ }
+ };
+ };
+
+ /**
+ * calculations moon position and illumination for a given date and latitude/longitude of the moon,
+ * @param {number|Date} dateValue Date object or timestamp for calculating moon-illumination
+ * @param {number} lat latitude for calculating moon-position
+ * @param {number} lng longitude for calculating moon-position
+ * @return {IMoonData} result object of moon-illumination
+ */
+ SunCalc.getMoonData = function (dateValue, lat, lng) {
+ const pos = SunCalc.getMoonPosition(dateValue, lat, lng);
+ const illum = SunCalc.getMoonIllumination(dateValue);
+ return Object.assign({
+ illumination : illum,
+ zenithAngle : illum.angle - pos.parallacticAngle
+ }, pos);
+ };
+
+ /**
+ * add hours to a date
+ * @param {number} dateValue timestamp to add hours
+ * @param {number} h - hours to add
+ * @returns {number} new timestamp with added hours
+ */
+ function hoursLater(dateValue, h) {
+ return dateValue + h * dayMs / 24;
+ }
+
+ /**
+ * calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article
+ * @param {number|Date} dateValue Date object or timestamp for calculating moon-times
+ * @param {number} lat latitude for calculating moon-times
+ * @param {number} lng longitude for calculating moon-times
+ * @param {boolean} [inUTC] defines if the calculation should be in utc or local time (default is local)
+ * @return {IMoonTimes} result object of sunTime
+ */
+ SunCalc.getMoonTimes = function (dateValue, lat, lng, inUTC) {
+ if (isNaN(lat)) {
+ throw new Error('latitude missing');
+ }
+ if (isNaN(lng)) {
+ throw new Error('longitude missing');
+ }
+ const t = new Date(dateValue);
+ if (inUTC) {
+ t.setUTCHours(0, 0, 0, 0);
+ } else {
+ t.setHours(0, 0, 0, 0);
+ }
+ dateValue = t.valueOf();
+ // console.log(`getMoonTimes lat=${lat} lng=${lng} dateValue=${dateValue} t=${t}`);
+
+ const hc = 0.133 * rad;
+ let h0 = SunCalc.getMoonPosition(dateValue, lat, lng).altitude - hc;
+ let rise; let set; let ye; let d; let roots; let x1; let x2; let dx;
+
+ // go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set)
+ for (let i = 1; i <= 26; i += 2) {
+ const h1 = SunCalc.getMoonPosition(hoursLater(dateValue, i), lat, lng).altitude - hc;
+ const h2 = SunCalc.getMoonPosition(hoursLater(dateValue, i + 1), lat, lng).altitude - hc;
+
+ const a = (h0 + h2) / 2 - h1;
+ const b = (h2 - h0) / 2;
+ const xe = -b / (2 * a);
+ ye = (a * xe + b) * xe + h1;
+ d = b * b - 4 * a * h1;
+ roots = 0;
+
+ if (d >= 0) {
+ dx = Math.sqrt(d) / (Math.abs(a) * 2);
+ x1 = xe - dx;
+ x2 = xe + dx;
+ if (Math.abs(x1) <= 1) {
+ roots++;
+ }
+
+ if (Math.abs(x2) <= 1) {
+ roots++;
+ }
+
+ if (x1 < -1) {
+ x1 = x2;
+ }
+ }
+
+ if (roots === 1) {
+ if (h0 < 0) {
+ rise = i + x1;
+ } else {
+ set = i + x1;
+ }
+ } else if (roots === 2) {
+ rise = i + (ye < 0 ? x2 : x1);
+ set = i + (ye < 0 ? x1 : x2);
+ }
+
+ if (rise && set) {
+ break;
+ }
+
+ h0 = h2;
+ }
+
+ const result = {};
+ if (rise) {
+ result.rise = new Date(hoursLater(dateValue, rise));
+ } else {
+ result.rise = NaN;
+ }
+
+ if (set) {
+ result.set = new Date(hoursLater(dateValue, set));
+ } else {
+ result.set = NaN;
+ }
+
+ if (!rise && !set) {
+ if (ye > 0) {
+ result.alwaysUp = true;
+ result.alwaysDown = false;
+ } else {
+ result.alwaysUp = false;
+ result.alwaysDown = true;
+ }
+ } else if (rise && set) {
+ result.alwaysUp = false;
+ result.alwaysDown = false;
+ result.highest = new Date(hoursLater(dateValue, Math.min(rise, set) + (Math.abs(set - rise) / 2)));
+ } else {
+ result.alwaysUp = false;
+ result.alwaysDown = false;
+ }
+ return result;
+ };
+
+ /**
+ * calc moon transit
+ * @param {number} rize timestamp for rise
+ * @param {number} set timestamp for set time
+ * @returns {Date} new moon transit
+ */
+ function calcMoonTransit(rize, set) {
+ if (rize > set) {
+ return new Date(set + (rize - set) / 2);
+ }
+ return new Date(rize + (set - rize) / 2);
+ }
+
+ /**
+ * calculated the moon transit
+ * @param {number|Date} rise rise time as Date object or timestamp for calculating moon-transit
+ * @param {number|Date} set set time as Date object or timestamp for calculating moon-transit
+ * @param {number} lat latitude for calculating moon-times
+ * @param {number} lng longitude for calculating moon-times
+ * @returns {{main: (Date|null), invert: (Date|null)}}
+ */
+ SunCalc.moonTransit = function (rise, set, lat, lng) {
+ /** @type {Date|null} */ let main = null;
+ /** @type {Date|null} */ let invert = null;
+ const riseDate = new Date(rise);
+ const setDate = new Date(set);
+ const riseValue = riseDate.getTime();
+ const setValue = setDate.getTime();
+ const day = setDate.getDate();
+ let tempTransitBefore;
+ let tempTransitAfter;
+
+ if (rise && set) {
+ if (rise < set) {
+ main = calcMoonTransit(riseValue, setValue);
+ } else {
+ invert = calcMoonTransit(riseValue, setValue);
+ }
+ }
+
+ if (rise) {
+ tempTransitAfter = calcMoonTransit(riseValue, SunCalc.getMoonTimes(new Date(riseDate).setDate(day + 1), lat, lng).set.valueOf());
+ if (tempTransitAfter.getDate() === day) {
+ if (main) {
+ invert = tempTransitAfter;
+ } else {
+ main = tempTransitAfter;
+ }
+ }
+ }
+
+ if (set) {
+ tempTransitBefore = calcMoonTransit(setValue, SunCalc.getMoonTimes(new Date(setDate).setDate(day - 1), lat, lng).rise.valueOf());
+ if (tempTransitBefore.getDate() === day) {
+ main = tempTransitBefore;
+ }
+ }
+ return {
+ main,
+ invert
+ };
+ };
+
+ // export as Node module / AMD module / browser variable
+ if (typeof exports === 'object' && typeof module !== 'undefined') {
+ module.exports = SunCalc;
+ // @ts-ignore
+ } else if (typeof define === 'function' && define.amd) {
+ // @ts-ignore
+ define(SunCalc);
+ } else {
+ // @ts-ignore
+ window.SunCalc = SunCalc;
+ }
+
+})();
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/metadata.json b/moonphase@techi-freki/files/moonphase@techi-freki/metadata.json
index 840eff50352..53b75cd27ff 100644
--- a/moonphase@techi-freki/files/moonphase@techi-freki/metadata.json
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/metadata.json
@@ -1,9 +1,8 @@
{
"uuid": "moonphase@techi-freki",
"name": "Moon Phase",
- "description": "A Cinnamon applet that displays the current moon phase.",
- "version": "0.0.6",
+ "description": "A Cinnamon applet that displays up-to-date moon related information.",
+ "version": "1.0.0",
"max-instances": 1,
- "author": "Techi Freki",
- "email": "techifreki@proton.me"
+ "author": "Techi Freki"
}
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/po/moonphase@techi-freki.pot b/moonphase@techi-freki/files/moonphase@techi-freki/po/moonphase@techi-freki.pot
index 5bd878c05ed..97d169a348f 100644
--- a/moonphase@techi-freki/files/moonphase@techi-freki/po/moonphase@techi-freki.pot
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/po/moonphase@techi-freki.pot
@@ -1,7 +1,7 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the PACKAGE package.
-# FIRST AUTHOR , YEAR.
+# Translation file for moonphase@techi-freki
+# Copyright (C) 2023 Techi-Freki
+# This file is distributed under the same license as the moonphase@techi-freki package.
+# D. Bryan Combs (Techi-Freki), 2023
#
#, fuzzy
msgid ""
@@ -17,45 +17,108 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: js/moon.js:41 js/moon.js:49
+#: js/moon.js:22 js/moon.js:30
msgid "New Moon"
msgstr ""
-#: js/moon.js:42
+#: js/moon.js:23
msgid "Waxing Crescent"
msgstr ""
-#: js/moon.js:43
+#: js/moon.js:24
msgid "First Quarter"
msgstr ""
-#: js/moon.js:44
+#: js/moon.js:25
msgid "Waxing Gibbous"
msgstr ""
-#: js/moon.js:45
+#: js/moon.js:26
msgid "Full Moon"
msgstr ""
-#: js/moon.js:46
+#: js/moon.js:27
msgid "Waning Gibbous"
msgstr ""
-#: js/moon.js:47
+#: js/moon.js:28
msgid "Last Quarter"
msgstr ""
-#: js/moon.js:48
+#: js/moon.js:29
msgid "Waning Crescent"
msgstr ""
+#: js/ui/elements/noRiseSetElement.js:40
+msgid "Next Moonrise"
+msgstr ""
+
+#: js/ui/elements/noRiseSetElement.js:52
+msgid "Next Moonset"
+msgstr ""
+
+#: js/ui/elements/noRiseSetElement.js:22
+msgid "illumination"
+msgstr ""
+
+#: js/ui/elements/riseSetUi.js:45
+msgid "The moon is always down and will not rise today"
+msgstr ""
+
+#: js/ui/elements/riseSetUi.js:55
+msgid "The moon is always up and will not set today"
+msgstr ""
+
+#: js/ui/elements/riseSetUi.js:66
+msgid "Moonrise"
+msgstr ""
+
+#: js/ui/elements/riseSetUi.js:73
+msgid "Lunar Noon"
+msgstr ""
+
+#: js/ui/elements/riseSetUi.js:80
+msgid "Moonset"
+msgstr ""
+
+#: js/ui/elements/compass.js:10
+msgid "North"
+msgstr ""
+
+#: js/ui/elements/compass.js:11
+msgid "North East"
+msgstr ""
+
+#: js/ui/elements/compass.js:12
+msgid "East"
+msgstr ""
+
+#: js/ui/elements/compass.js:13
+msgid "South East"
+msgstr ""
+
+#: js/ui/elements/compass.js:14
+msgid "South"
+msgstr ""
+
+#: js/ui/elements/compass.js:15
+msgid "South West"
+msgstr ""
+
+#: js/ui/elements/compass.js:16
+msgid "West"
+msgstr ""
+
+#: js/ui/elements/compass.js:17
+msgid "North West"
+msgstr ""
+
#. metadata.json->name
-#: js/moon.js:54
msgid "Moon Phase"
msgstr ""
#. metadata.json->description
-msgid "A Cinnamon applet that displays the current moon phase."
+msgid "A Cinnamon applet that displays up-to-date moon related information."
msgstr ""
#. settings-schema.json->page-settings->title
@@ -70,8 +133,12 @@ msgstr ""
msgid "Update Settings"
msgstr ""
+#. settings-schema.json->section-geolocation->title
+msgid "Geolocation Settings"
+msgstr ""
+
#. settings-schema.json->showPhaseLabel->description
-msgid "Display the moon phase as a string"
+msgid "Display the applet label"
msgstr ""
#. settings-schema.json->showNameLabel->description
@@ -105,3 +172,27 @@ msgstr ""
#. settings-schema.json->updateInterval->description
msgid "Update interval"
msgstr ""
+
+#. settings-schema.json->enableGeolocation->description
+msgid "Enable geolocation features"
+msgstr ""
+
+#. settings-schema.json->latitude->description
+msgid "Latitude"
+msgstr ""
+
+#. settings-schema.json->longitude->description
+msgid "Longitude"
+msgstr ""
+
+#. settings-schema.json->enablePopup->description
+msgid "Enable popup menu"
+msgstr ""
+
+#. settings-schema.json->showCurrentPhaseInfo->description
+msgid "Display the current phase information"
+msgstr ""
+
+#. settings-schema.json->showRiseSet->description
+msgid "Display the moon rise, transit, and set times"
+msgstr ""
\ No newline at end of file
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/settings-schema.json b/moonphase@techi-freki/files/moonphase@techi-freki/settings-schema.json
index 66da57a9633..7a9dbd1924d 100644
--- a/moonphase@techi-freki/files/moonphase@techi-freki/settings-schema.json
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/settings-schema.json
@@ -9,25 +9,39 @@
"type": "page",
"title": "Settings",
"sections": [
- "section-panel",
- "section-menu"
+ "section-general",
+ "section-geolocation",
+ "section-update"
]
},
- "section-panel": {
+ "section-geolocation": {
+ "type": "section",
+ "title": "Geolocation Settings",
+ "keys": [
+ "enableGeolocation",
+ "latitude",
+ "longitude",
+ "enablePopup",
+ "showCurrentPhaseInfo",
+ "showRiseSet"
+ ]
+ },
+
+ "section-general": {
"type": "section",
"title": "General Settings",
"keys": [
"useAltIcons",
"showTooltip",
- "showNameTooltip",
+ "showPhaseTooltip",
"showPercentageTooltip",
"showPhaseLabel",
"showNameLabel",
"showPercentageLabel"
]
},
- "section-menu": {
+ "section-update": {
"type": "section",
"title": "Update Settings",
"keys": [
@@ -36,10 +50,45 @@
}
},
+ "enableGeolocation": {
+ "type": "checkbox",
+ "default": false,
+ "description": "Enable geolocation features"
+ },
+ "latitude": {
+ "type": "entry",
+ "default": "40.730610",
+ "description": "Latitude",
+ "dependency": "enableGeolocation"
+ },
+ "longitude": {
+ "type": "entry",
+ "default": "-73.935242",
+ "description": "Longitude",
+ "dependency": "enableGeolocation"
+ },
+ "enablePopup": {
+ "type": "checkbox",
+ "default": false,
+ "description": "Enable popup menu",
+ "dependency": "enableGeolocation"
+ },
+ "showCurrentPhaseInfo": {
+ "type": "checkbox",
+ "default": false,
+ "description": "Display the current phase information",
+ "dependency": "enableGeolocation"
+ },
+ "showRiseSet": {
+ "type": "checkbox",
+ "default": false,
+ "description": "Display the moon rise, transit, and set times",
+ "dependency": "enableGeolocation"
+ },
"showPhaseLabel": {
"type": "checkbox",
"default": false,
- "description": "Display the moon phase as a string"
+ "description": "Display the applet label"
},
"showNameLabel": {
"type": "checkbox",
@@ -58,7 +107,7 @@
"default": true,
"description": "Display a tooltip on hover"
},
- "showNameTooltip": {
+ "showPhaseTooltip": {
"type": "checkbox",
"default": true,
"description": "Display the name of the moon phase in the tooltip",
diff --git a/moonphase@techi-freki/files/moonphase@techi-freki/stylesheet.css b/moonphase@techi-freki/files/moonphase@techi-freki/stylesheet.css
new file mode 100644
index 00000000000..ec3fad02ce6
--- /dev/null
+++ b/moonphase@techi-freki/files/moonphase@techi-freki/stylesheet.css
@@ -0,0 +1,52 @@
+.padding-top-3 {
+ margin: 5px;
+ padding-top: 3px;
+}
+
+.padding-top-5-strict {
+ padding-top: 5px;
+}
+
+.padding-15 {
+ padding: 15px;
+}
+
+.margin-5 {
+ margin: 5px;
+}
+
+.margin-bottom-5 {
+ margin-bottom: 5px;
+}
+
+.margin-bottom-15 {
+ margin-bottom: 15px;
+}
+
+.margin-top-5 {
+ margin-top: 5px;
+}
+
+.font-20 {
+ font-size: 20px;
+}
+
+.font-15 {
+ font-size: 15px;
+}
+
+.font-10 {
+ font-size: 10px;
+}
+
+.align-left {
+ text-align: left;
+}
+
+.align-center {
+ text-align: center;
+}
+
+.align-right {
+ text-align: right;
+}
\ No newline at end of file
diff --git a/moonphase@techi-freki/screenshot.png b/moonphase@techi-freki/screenshot.png
index 48f98cbb897..43c77151cea 100644
Binary files a/moonphase@techi-freki/screenshot.png and b/moonphase@techi-freki/screenshot.png differ
diff --git a/moonphase@techi-freki/screenshot_0.png b/moonphase@techi-freki/screenshot_0.png
deleted file mode 100644
index 2653ede8a6d..00000000000
Binary files a/moonphase@techi-freki/screenshot_0.png and /dev/null differ
diff --git a/moonphase@techi-freki/screenshot_1.png b/moonphase@techi-freki/screenshot_1.png
deleted file mode 100644
index 6280814123f..00000000000
Binary files a/moonphase@techi-freki/screenshot_1.png and /dev/null differ
diff --git a/moonphase@techi-freki/screenshot_2.png b/moonphase@techi-freki/screenshot_2.png
deleted file mode 100644
index dfc66df0ee3..00000000000
Binary files a/moonphase@techi-freki/screenshot_2.png and /dev/null differ