602 lines
19 KiB
JavaScript
602 lines
19 KiB
JavaScript
/*
|
|
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
|
if you want to view the source, please visit the github repository of this plugin
|
|
*/
|
|
|
|
var __create = Object.create;
|
|
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
var __getProtoOf = Object.getPrototypeOf;
|
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
var __commonJS = (cb, mod) => function __require() {
|
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
};
|
|
var __export = (target, all) => {
|
|
for (var name in all)
|
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
};
|
|
var __copyProps = (to, from, except, desc) => {
|
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
for (let key of __getOwnPropNames(from))
|
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
}
|
|
return to;
|
|
};
|
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
// If the importer is in node compatibility mode or this is not an ESM
|
|
// file that has been converted to a CommonJS file using a Babel-
|
|
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
mod
|
|
));
|
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
|
|
// node_modules/deepmerge/dist/cjs.js
|
|
var require_cjs = __commonJS({
|
|
"node_modules/deepmerge/dist/cjs.js"(exports, module2) {
|
|
"use strict";
|
|
var isMergeableObject = function isMergeableObject2(value) {
|
|
return isNonNullObject(value) && !isSpecial(value);
|
|
};
|
|
function isNonNullObject(value) {
|
|
return !!value && typeof value === "object";
|
|
}
|
|
function isSpecial(value) {
|
|
var stringValue = Object.prototype.toString.call(value);
|
|
return stringValue === "[object RegExp]" || stringValue === "[object Date]" || isReactElement(value);
|
|
}
|
|
var canUseSymbol = typeof Symbol === "function" && Symbol.for;
|
|
var REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for("react.element") : 60103;
|
|
function isReactElement(value) {
|
|
return value.$$typeof === REACT_ELEMENT_TYPE;
|
|
}
|
|
function emptyTarget(val) {
|
|
return Array.isArray(val) ? [] : {};
|
|
}
|
|
function cloneUnlessOtherwiseSpecified(value, options) {
|
|
return options.clone !== false && options.isMergeableObject(value) ? deepmerge(emptyTarget(value), value, options) : value;
|
|
}
|
|
function defaultArrayMerge(target, source, options) {
|
|
return target.concat(source).map(function(element) {
|
|
return cloneUnlessOtherwiseSpecified(element, options);
|
|
});
|
|
}
|
|
function getMergeFunction(key, options) {
|
|
if (!options.customMerge) {
|
|
return deepmerge;
|
|
}
|
|
var customMerge = options.customMerge(key);
|
|
return typeof customMerge === "function" ? customMerge : deepmerge;
|
|
}
|
|
function getEnumerableOwnPropertySymbols(target) {
|
|
return Object.getOwnPropertySymbols ? Object.getOwnPropertySymbols(target).filter(function(symbol) {
|
|
return Object.propertyIsEnumerable.call(target, symbol);
|
|
}) : [];
|
|
}
|
|
function getKeys(target) {
|
|
return Object.keys(target).concat(getEnumerableOwnPropertySymbols(target));
|
|
}
|
|
function propertyIsOnObject(object, property) {
|
|
try {
|
|
return property in object;
|
|
} catch (_) {
|
|
return false;
|
|
}
|
|
}
|
|
function propertyIsUnsafe(target, key) {
|
|
return propertyIsOnObject(target, key) && !(Object.hasOwnProperty.call(target, key) && Object.propertyIsEnumerable.call(target, key));
|
|
}
|
|
function mergeObject(target, source, options) {
|
|
var destination = {};
|
|
if (options.isMergeableObject(target)) {
|
|
getKeys(target).forEach(function(key) {
|
|
destination[key] = cloneUnlessOtherwiseSpecified(target[key], options);
|
|
});
|
|
}
|
|
getKeys(source).forEach(function(key) {
|
|
if (propertyIsUnsafe(target, key)) {
|
|
return;
|
|
}
|
|
if (propertyIsOnObject(target, key) && options.isMergeableObject(source[key])) {
|
|
destination[key] = getMergeFunction(key, options)(target[key], source[key], options);
|
|
} else {
|
|
destination[key] = cloneUnlessOtherwiseSpecified(source[key], options);
|
|
}
|
|
});
|
|
return destination;
|
|
}
|
|
function deepmerge(target, source, options) {
|
|
options = options || {};
|
|
options.arrayMerge = options.arrayMerge || defaultArrayMerge;
|
|
options.isMergeableObject = options.isMergeableObject || isMergeableObject;
|
|
options.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified;
|
|
var sourceIsArray = Array.isArray(source);
|
|
var targetIsArray = Array.isArray(target);
|
|
var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray;
|
|
if (!sourceAndTargetTypesMatch) {
|
|
return cloneUnlessOtherwiseSpecified(source, options);
|
|
} else if (sourceIsArray) {
|
|
return options.arrayMerge(target, source, options);
|
|
} else {
|
|
return mergeObject(target, source, options);
|
|
}
|
|
}
|
|
deepmerge.all = function deepmergeAll(array, options) {
|
|
if (!Array.isArray(array)) {
|
|
throw new Error("first argument should be an array");
|
|
}
|
|
return array.reduce(function(prev, next) {
|
|
return deepmerge(prev, next, options);
|
|
}, {});
|
|
};
|
|
var deepmerge_1 = deepmerge;
|
|
module2.exports = deepmerge_1;
|
|
}
|
|
});
|
|
|
|
// src/main.ts
|
|
var main_exports = {};
|
|
__export(main_exports, {
|
|
default: () => GeocodingPlugin
|
|
});
|
|
module.exports = __toCommonJS(main_exports);
|
|
var import_deepmerge = __toESM(require_cjs());
|
|
var import_obsidian6 = require("obsidian");
|
|
|
|
// src/search-modal.ts
|
|
var import_obsidian2 = require("obsidian");
|
|
|
|
// src/results-modal.ts
|
|
var import_obsidian = require("obsidian");
|
|
var GeocodingResultsModal = class extends import_obsidian.SuggestModal {
|
|
constructor(plugin, results) {
|
|
super(plugin.app);
|
|
this.plugin = plugin;
|
|
this.results = results;
|
|
this.setPlaceholder("Select result");
|
|
}
|
|
getSuggestions(query) {
|
|
return this.results.filter(
|
|
(result) => result.address.toLowerCase().includes(query.toLowerCase())
|
|
);
|
|
}
|
|
onChooseSuggestion(result) {
|
|
this.plugin.insertProperties(result);
|
|
}
|
|
renderSuggestion({ address, lat, lng, info }, el) {
|
|
el.createEl("div", {
|
|
text: `${address} (${lat}, ${lng})`
|
|
});
|
|
if (info) {
|
|
el.createEl("small", {
|
|
text: info
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
// src/search-modal.ts
|
|
var GeocodingSearchModal = class extends import_obsidian2.Modal {
|
|
constructor(plugin, searchTerm) {
|
|
super(plugin.app);
|
|
this.plugin = plugin;
|
|
this.searchTerm = searchTerm;
|
|
}
|
|
async onSubmit() {
|
|
this.close();
|
|
const results = await this.plugin.getResults(this.searchTerm);
|
|
new GeocodingResultsModal(this.plugin, results).open();
|
|
}
|
|
onOpen() {
|
|
const { contentEl } = this;
|
|
contentEl.createEl("h1", {
|
|
text: "Confirm search term"
|
|
});
|
|
new import_obsidian2.Setting(contentEl).setName("Name").addText((text) => {
|
|
const component = text.setValue(this.searchTerm).onChange((value) => {
|
|
this.searchTerm = value;
|
|
});
|
|
component.inputEl.style.width = "100%";
|
|
});
|
|
new import_obsidian2.Setting(contentEl).addButton(
|
|
(btn) => btn.setButtonText("Submit").setCta().onClick(async () => {
|
|
await this.onSubmit();
|
|
})
|
|
);
|
|
contentEl.addEventListener("keypress", async (e) => {
|
|
if (e.key === "Enter") {
|
|
e.preventDefault();
|
|
await this.onSubmit();
|
|
}
|
|
});
|
|
}
|
|
onClose() {
|
|
const { contentEl } = this;
|
|
contentEl.empty();
|
|
}
|
|
};
|
|
|
|
// src/settings.ts
|
|
var propertyDescriptions = {
|
|
address: {
|
|
name: "Address",
|
|
detail: "Format varies by provider"
|
|
},
|
|
lat: {
|
|
name: "Latitude"
|
|
},
|
|
lng: {
|
|
name: "Longitude"
|
|
},
|
|
location: {
|
|
name: "Location",
|
|
detail: "Coordinates in [lat, lng] format"
|
|
},
|
|
map_link: {
|
|
name: "Map link"
|
|
},
|
|
map_view_link: {
|
|
name: "Map view link",
|
|
detail: "A link in [](geo:lat,lng) format"
|
|
}
|
|
};
|
|
var defaultSettings = {
|
|
properties: {
|
|
address: {
|
|
frontmatterKey: "address",
|
|
enabled: true
|
|
},
|
|
lat: {
|
|
frontmatterKey: "lat",
|
|
enabled: false
|
|
},
|
|
lng: {
|
|
frontmatterKey: "lng",
|
|
enabled: false
|
|
},
|
|
location: {
|
|
frontmatterKey: "location",
|
|
enabled: false
|
|
},
|
|
map_link: {
|
|
frontmatterKey: "map_link",
|
|
enabled: false
|
|
},
|
|
map_view_link: {
|
|
frontmatterKey: "map_view_link",
|
|
enabled: false
|
|
}
|
|
},
|
|
overrideExistingProperties: false,
|
|
mapLinkProvider: "google",
|
|
apiProvider: "free-geocoding-api",
|
|
apiKey: ""
|
|
};
|
|
|
|
// src/settings-tab.ts
|
|
var import_obsidian3 = require("obsidian");
|
|
var GeocodingPluginSettingTab = class extends import_obsidian3.PluginSettingTab {
|
|
constructor(app, plugin) {
|
|
super(app, plugin);
|
|
this.plugin = plugin;
|
|
}
|
|
display() {
|
|
const { containerEl } = this;
|
|
containerEl.empty();
|
|
containerEl.createEl("h2", { text: "Properties" });
|
|
for (const [key, description] of Object.entries(
|
|
propertyDescriptions
|
|
)) {
|
|
const property = this.plugin.settings.properties[key];
|
|
new import_obsidian3.Setting(containerEl).setName(description.name || key).setDesc(description.detail || "").addText(
|
|
(text) => text.setValue(property.frontmatterKey).onChange(async (value) => {
|
|
if (!value) {
|
|
return;
|
|
}
|
|
property.frontmatterKey = value;
|
|
await this.plugin.saveSettings();
|
|
})
|
|
).addToggle(
|
|
(toggle) => toggle.setValue(property.enabled).onChange(async (value) => {
|
|
property.enabled = value;
|
|
await this.plugin.saveSettings();
|
|
})
|
|
);
|
|
}
|
|
containerEl.createEl("h2", { text: "Behavior" });
|
|
new import_obsidian3.Setting(containerEl).setName("Override existing properties").setDesc(
|
|
"Whether to override existing properties with the same name"
|
|
).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.settings.overrideExistingProperties).onChange(async (value) => {
|
|
this.plugin.settings.overrideExistingProperties = value;
|
|
await this.plugin.saveSettings();
|
|
})
|
|
);
|
|
new import_obsidian3.Setting(containerEl).setName("Map link provider").setDesc("Provider for the map_link property, if enabled").addDropdown(
|
|
(dropdown) => dropdown.addOptions({
|
|
google: "Google Maps",
|
|
apple: "Apple Maps",
|
|
osm: "OpenStreetMap"
|
|
}).setValue(this.plugin.settings.mapLinkProvider).onChange(async (value) => {
|
|
switch (value) {
|
|
case "google":
|
|
case "apple":
|
|
case "osm":
|
|
this.plugin.settings.mapLinkProvider = value;
|
|
break;
|
|
}
|
|
await this.plugin.saveSettings();
|
|
})
|
|
);
|
|
containerEl.createEl("h2", { text: "API" });
|
|
new import_obsidian3.Setting(containerEl).setName("API provider").addDropdown(
|
|
(dropdown) => dropdown.addOptions({
|
|
["free-geocoding-api"]: "Free Geocoding API",
|
|
["google-geocoding"]: "Google Geocoding"
|
|
}).setValue(this.plugin.settings.apiProvider).onChange(async (value) => {
|
|
switch (value) {
|
|
case "free-geocoding-api":
|
|
case "google-geocoding":
|
|
this.plugin.settings.apiProvider = value;
|
|
break;
|
|
}
|
|
await this.plugin.saveSettings();
|
|
})
|
|
);
|
|
new import_obsidian3.Setting(containerEl).setName("API key").setDisabled(
|
|
this.plugin.settings.apiProvider !== "google-geocoding"
|
|
).addText(
|
|
(text) => text.setValue(this.plugin.settings.apiKey).onChange(async (value) => {
|
|
this.plugin.settings.apiKey = value;
|
|
await this.plugin.saveSettings();
|
|
})
|
|
);
|
|
}
|
|
};
|
|
|
|
// src/utils/fetch-free-geocoding-api-results.ts
|
|
var import_obsidian4 = require("obsidian");
|
|
var fetchFreeGeocodingAPIResults = async (searchTerm, apiKey) => {
|
|
const params = new URLSearchParams({
|
|
q: searchTerm,
|
|
api_key: apiKey
|
|
});
|
|
const url = `https://geocode.maps.co/search?${params.toString()}`;
|
|
const response = await (0, import_obsidian4.requestUrl)({
|
|
url,
|
|
throw: false
|
|
});
|
|
const retryAfter = response.headers["Retry-After"];
|
|
switch (response.status) {
|
|
case 200:
|
|
break;
|
|
case 401:
|
|
throw new Error("Unauthorized. Please check your API key.");
|
|
case 409:
|
|
case 503:
|
|
if (retryAfter) {
|
|
throw new Error(
|
|
`Too many requests. Please try again in ${retryAfter} seconds.`
|
|
);
|
|
}
|
|
throw new Error("Too many requests. Please try again later.");
|
|
default:
|
|
throw new Error(`Server responded with ${response.status}`);
|
|
}
|
|
const results = response.json;
|
|
return results.map((result) => ({
|
|
address: result.display_name,
|
|
lat: Number(result.lat),
|
|
lng: Number(result.lon),
|
|
info: `${result.class} ${result.type}`,
|
|
id: result.osm_id.toString(),
|
|
provider: "free-geocoding-api"
|
|
}));
|
|
};
|
|
|
|
// src/utils/fetch-google-geocoding-results.ts
|
|
var import_obsidian5 = require("obsidian");
|
|
var fetchGoogleGeocodingResults = async (searchTerm, apiKey) => {
|
|
const params = new URLSearchParams({
|
|
address: searchTerm,
|
|
key: apiKey
|
|
});
|
|
const url = `https://maps.googleapis.com/maps/api/geocode/json?${params.toString()}`;
|
|
const response = await (0, import_obsidian5.requestUrl)({
|
|
url,
|
|
throw: false
|
|
});
|
|
if (response.status !== 200) {
|
|
throw new Error(`Server responded with ${response.status}`);
|
|
}
|
|
const { status, results } = response.json;
|
|
switch (status) {
|
|
case "OK":
|
|
break;
|
|
case "ZERO_RESULTS":
|
|
throw new Error("No results found");
|
|
case "OVER_DAILY_LIMIT":
|
|
throw new Error("Over daily limit");
|
|
case "OVER_QUERY_LIMIT":
|
|
throw new Error("Over query limit");
|
|
case "REQUEST_DENIED":
|
|
throw new Error("Request denied (invalid API key?)");
|
|
default:
|
|
throw new Error("Unknown API response");
|
|
}
|
|
return results.map((result) => ({
|
|
address: result.formatted_address,
|
|
lat: result.geometry.location.lat,
|
|
lng: result.geometry.location.lng,
|
|
info: result.types.join(", "),
|
|
id: result.place_id,
|
|
provider: "google-geocoding"
|
|
}));
|
|
};
|
|
|
|
// src/utils/make-apple-maps-link.ts
|
|
var makeAppleMapsLink = ({ address, lat, lng }) => {
|
|
const params = new URLSearchParams({
|
|
ll: `${lat},${lng}`,
|
|
address
|
|
// used only for display
|
|
});
|
|
return `https://maps.apple.com/?${params.toString()}`;
|
|
};
|
|
|
|
// src/utils/make-google-maps-link.ts
|
|
var makeGoogleMapsLink = ({
|
|
id,
|
|
provider,
|
|
lat,
|
|
lng
|
|
}) => {
|
|
if (provider === "google-geocoding") {
|
|
return `https://www.google.com/maps/search/?api=1&query=Google&query_place_id=${id}`;
|
|
}
|
|
const params = new URLSearchParams({
|
|
api: "1",
|
|
// we can only query by lat,lng or address, so we choose the more precise option
|
|
query: `${lat},${lng}`
|
|
});
|
|
return `https://www.google.com/maps/search/?${params.toString()}`;
|
|
};
|
|
|
|
// src/utils/make-osm-link.ts
|
|
var makeOsmLink = ({ id, provider, lat, lng }) => {
|
|
if (provider === "free-geocoding-api") {
|
|
}
|
|
const params = new URLSearchParams({
|
|
mlat: lat.toString(),
|
|
mlon: lng.toString()
|
|
});
|
|
return `https://openstreetmap.org/?${params.toString()}`;
|
|
};
|
|
|
|
// src/main.ts
|
|
var GeocodingPlugin = class extends import_obsidian6.Plugin {
|
|
async onload() {
|
|
await this.loadSettings();
|
|
this.addSettingTab(new GeocodingPluginSettingTab(this.app, this));
|
|
this.addCommand({
|
|
id: "insert-into-current-note",
|
|
name: "Insert properties into current note",
|
|
editorCallback: async (_, ctx) => {
|
|
const currentFile = ctx.file;
|
|
if (!currentFile) {
|
|
return;
|
|
}
|
|
const searchTerm = this.getSearchTerm(currentFile);
|
|
new GeocodingSearchModal(this, searchTerm).open();
|
|
}
|
|
});
|
|
this.addCommand({
|
|
id: "insert-into-current-note-no-confirmation",
|
|
name: "Insert properties into current note (no confirmation)",
|
|
editorCallback: async (_, ctx) => {
|
|
const currentFile = ctx.file;
|
|
if (!currentFile) {
|
|
return;
|
|
}
|
|
const searchTerm = this.getSearchTerm(currentFile);
|
|
const results = await this.getResults(searchTerm);
|
|
await this.insertProperties(results[0]);
|
|
}
|
|
});
|
|
}
|
|
getSearchTerm(file) {
|
|
let searchTerm = file.basename;
|
|
const metadataCache = this.app.metadataCache.getFileCache(file);
|
|
if (metadataCache == null ? void 0 : metadataCache.frontmatter) {
|
|
searchTerm = metadataCache.frontmatter.address || metadataCache.frontmatter.title || searchTerm;
|
|
}
|
|
return searchTerm;
|
|
}
|
|
async getResults(searchTerm) {
|
|
const results = [];
|
|
try {
|
|
const { apiProvider, apiKey } = this.settings;
|
|
switch (apiProvider) {
|
|
case "free-geocoding-api":
|
|
results.push(
|
|
...await fetchFreeGeocodingAPIResults(
|
|
searchTerm,
|
|
apiKey
|
|
)
|
|
);
|
|
break;
|
|
case "google-geocoding":
|
|
results.push(
|
|
...await fetchGoogleGeocodingResults(
|
|
searchTerm,
|
|
apiKey
|
|
)
|
|
);
|
|
break;
|
|
default:
|
|
throw new Error(`Invalid API provider: ${apiProvider}`);
|
|
}
|
|
} catch (error) {
|
|
new import_obsidian6.Notice(String(error));
|
|
throw error;
|
|
}
|
|
if (!(results == null ? void 0 : results.length)) {
|
|
new import_obsidian6.Notice(`No results found for "${searchTerm}"`);
|
|
}
|
|
return results;
|
|
}
|
|
async insertProperties(result) {
|
|
const currentFile = this.app.workspace.getActiveFile();
|
|
if (!currentFile) {
|
|
return;
|
|
}
|
|
const { overrideExistingProperties, mapLinkProvider, properties } = this.settings;
|
|
this.app.fileManager.processFrontMatter(currentFile, (frontmatter) => {
|
|
for (const [key, property] of Object.entries(properties)) {
|
|
const shouldInsert = property.enabled && (overrideExistingProperties || frontmatter[property.frontmatterKey] === void 0);
|
|
if (!shouldInsert) {
|
|
continue;
|
|
}
|
|
switch (key) {
|
|
case "location":
|
|
frontmatter[property.frontmatterKey] = [
|
|
result.lat.toString(),
|
|
result.lng.toString()
|
|
];
|
|
break;
|
|
case "map_link":
|
|
switch (mapLinkProvider) {
|
|
case "google":
|
|
frontmatter[property.frontmatterKey] = makeGoogleMapsLink(result);
|
|
break;
|
|
case "apple":
|
|
frontmatter[property.frontmatterKey] = makeAppleMapsLink(result);
|
|
break;
|
|
case "osm":
|
|
frontmatter[property.frontmatterKey] = makeOsmLink(result);
|
|
break;
|
|
}
|
|
break;
|
|
case "map_view_link": {
|
|
frontmatter[property.frontmatterKey] = `[](geo:${result.lat},${result.lng})`;
|
|
break;
|
|
}
|
|
default:
|
|
frontmatter[property.frontmatterKey] = result[key];
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
async loadSettings() {
|
|
this.settings = (0, import_deepmerge.default)(defaultSettings, await this.loadData() || {});
|
|
}
|
|
async saveSettings() {
|
|
await this.saveData(this.settings);
|
|
}
|
|
};
|
|
|
|
/* nosourcemap */ |