Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { NewNote } from "./parser";
import { getSelectedFolder } from "./utils/folders";
import { applyTagToNote, getAnyTagWithTitle } from "./utils/tags";
import { ApplyTagsWhileInsertingSetting } from "./settings";
import { getGeoLocationForNote } from "./utils/geolocation";

export enum TemplateAction {
NewNote = "newNote",
Expand All @@ -25,12 +26,21 @@ const performInsertTextAction = async (template: NewNote) => {

const performNewNoteAction = async (template: NewNote, isTodo: 0 | 1) => {
const folderId = template.folder ? template.folder : await getSelectedFolder();
const notePayload = { body: template.body, parent_id: folderId, title: template.title, is_todo: isTodo };
const notePayload: Record<string, unknown> = { body: template.body, parent_id: folderId, title: template.title, is_todo: isTodo };

if (isTodo && template.todo_due) {
notePayload["todo_due"] = template.todo_due;
}

const geoLocation = await getGeoLocationForNote();
if (geoLocation) {
notePayload["latitude"] = geoLocation.latitude;
notePayload["longitude"] = geoLocation.longitude;
if (geoLocation.altitude !== undefined) {
notePayload["altitude"] = geoLocation.altitude;
}
}

const note = await joplin.data.post(["notes"], null, notePayload);
await joplin.commands.execute("openNote", note.id);
for (const tag of template.tags) {
Expand Down
62 changes: 62 additions & 0 deletions src/utils/geolocation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import joplin from "api";

export interface GeoLocation {
latitude: number;
longitude: number;
altitude?: number;
}

/**
* Checks whether the user has enabled "Save geo-location with notes" in Joplin settings.
*/
export const isGeoLocationEnabled = async (): Promise<boolean> => {
try {
const value = await joplin.settings.globalValue("note.saveGeolocation");
return value === true;
} catch {
// If the setting key is unavailable, default to false
return false;
}
};

/**
* Gets the current GPS coordinates using the browser's geolocation API.
* Joplin runs on Electron, so navigator.geolocation is available.
* Returns null if geolocation is unavailable or the user denies permission.
*/
export const getCurrentLocation = (): Promise<GeoLocation | null> => {
return new Promise((resolve) => {
if (typeof navigator === "undefined" || !navigator.geolocation) {
resolve(null);
return;
}

navigator.geolocation.getCurrentPosition(
(position) => {
resolve({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
altitude: position.coords.altitude ?? undefined,
});
},
() => {
// User denied or error — resolve with null gracefully
resolve(null);
},
{
timeout: 5000,
maximumAge: 60000,
}
);
});
};

/**
* Returns geo-location data to attach to a note, respecting the Joplin setting.
* Returns null if the setting is disabled or location cannot be determined.
*/
export const getGeoLocationForNote = async (): Promise<GeoLocation | null> => {
const enabled = await isGeoLocationEnabled();
if (!enabled) return null;
return await getCurrentLocation();
};