diff --git a/src/controls/filter.ts b/src/controls/filter.ts index 7e29a36..330d1e4 100644 --- a/src/controls/filter.ts +++ b/src/controls/filter.ts @@ -220,7 +220,7 @@ export function filterMarkerControl(opts: L.ControlOptions, map: BaseMapType) { ...opts, icon: "filter", cls: "leaflet-control-expandable", - tooltip: t("Filter Markers") + tooltip: t("Filter markers") }; return new FilterMarkers(options, map); } diff --git a/src/controls/gpx.ts b/src/controls/gpx.ts index 8299b1d..9663049 100644 --- a/src/controls/gpx.ts +++ b/src/controls/gpx.ts @@ -245,7 +245,7 @@ class GPXControl extends FontAwesomeControl { if (!heatLines) { } data.createDiv("data-item").createSpan({ - text: `${t("Heart Rate")}: ${this.target.hr.avg}` + text: `${t("Heart rate")}: ${this.target.hr.avg}` }); const li = ul.createDiv("input-item"); const input = li.createEl("input", { @@ -259,7 +259,7 @@ class GPXControl extends FontAwesomeControl { }); li.createEl("label", { attr: { for: "leaflet-gpx-control-hr" }, - text: t("Heart Rate") + text: t("Heart rate") }); input.onclick = (evt) => { diff --git a/src/controls/mapview.ts b/src/controls/mapview.ts index e479e18..6c30ecb 100644 --- a/src/controls/mapview.ts +++ b/src/controls/mapview.ts @@ -21,7 +21,7 @@ export function mapViewControl(opts: L.ControlOptions, map: BaseMapType) { ...opts, icon: "edit", cls: "leaflet-control-edit-parameters", - tooltip: t("Edit View Parameters") + tooltip: t("Edit view parameters") }; return new MapViewControl(options, map); } @@ -46,7 +46,7 @@ export function saveMapParametersControl( ...opts, icon: "save", cls: "leaflet-control-save-param", - tooltip: t("Save Parameters to View") + tooltip: t("Save parameters to view") }; return new SaveMapParametersControl(options, map); } diff --git a/src/controls/zoom.ts b/src/controls/zoom.ts index 3e2a18f..7e88c0b 100644 --- a/src/controls/zoom.ts +++ b/src/controls/zoom.ts @@ -34,7 +34,7 @@ export function zoomControl(opts: L.ControlOptions, map: BaseMapType) { ...opts, icon: "map-marked-alt", cls: "leaflet-control-zoom-markers", - tooltip: t("Show All Markers") + tooltip: t("Show all markers") }; return new ZoomControl(options, map); } diff --git a/src/l10n/locales/en.ts b/src/l10n/locales/en.ts index a71e7e5..c2a0e20 100644 --- a/src/l10n/locales/en.ts +++ b/src/l10n/locales/en.ts @@ -1,7 +1,7 @@ export default { //main.ts "Loading Obsidian Leaflet v%1": "Loading Obsidian Leaflet v%1", //version number - "Open Leaflet Map": "Open Leaflet Map", + "Open Leaflet map": "Open Leaflet map", "Unloading Obsidian Leaflet": "Unloading Obsidian Leaflet", "Obsidian Leaflet maps must have an ID.": "Obsidian Leaflet maps must have an ID.", @@ -74,54 +74,54 @@ export default { "nautical miles": "nautical miles", //settings.ts - "Obsidian Leaflet Settings": "Obsidian Leaflet Settings", - "Default Map Marker": "Default Map Marker", + "Leaflet settings": "Leaflet settings", + "Default map marker": "Default map marker", "This marker is always available.": "This marker is always available.", - "Icon Name": "Icon Name", + "Icon name": "Icon name", "A default marker must be defined.": "A default marker must be defined", "The selected icon does not exist in Font Awesome Free.": "The selected icon does not exist in Font Awesome Free.", - "Upload Image": "Upload Image", - "Marker Color": "Marker Color", - "Layer Base Marker": "Layer Base Marker", + "Upload image": "Upload image", + "Marker color": "Marker color", + "Layer base marker": "Layer base marker", "Use as base layer for additional markers by default.": "Use as base layer for additional markers by default.", - "Additional Map Markers": "Additional Map Markers", - "Add Additional": "Add Additional", + "Additional map markers": "Additional map markers", + "Add additional": "Add additional", "These markers will be available in the right-click menu on the map.": "These markers will be available in the right-click menu on the map.", - "Default Latitude": "Default Latitude", + "Default latitude": "Default latitude", "Real-world maps will open to this latitude if not specified.": "Real-world maps will open to this latitude if not specified.", "Latitude must be a number.": "Latitude must be a number.", - "Default Longitude": "Default Longitude", + "Default longitude": "Default longitude", "Real-world maps will open to this longitude if not specified.": "Real-world maps will open to this longitude if not specified.", "Longitude must be a number.": "Longitude must be a number.", - "Reset to Default": "Reset to Default", + "Reset to default": "Reset to default", "Please back up your data before changing this setting.": "Please back up your data before changing this setting.", "Current directory": "Current directory", - "Default Config Directory": "Default Config Directory", - "Default Marker Tooltip Behavior": "Default Marker Tooltip Behavior", + "Default config directory": "Default config directory", + "Default marker tooltip behavior": "Default marker tooltip behavior", "New markers will be created to this setting by default. Can be overridden per-marker.": "New markers will be created to this setting by default. Can be overridden per-marker.", Always: "Always", Hover: "Hover", Never: "Never", - "Display Note Preview": "Display Note Preview", + "Display note preview": "Display note preview", "Markers linked to notes will show a note preview when hovered.": "Markers linked to notes will show a note preview when hovered.", - "Display Overlay Tooltips": "Display Overlay Tooltips", + "Display overlay tooltips": "Display overlay tooltips", "Overlay tooltips will display when hovered.": "Overlay tooltips will display when hovered.", - "Copy Coordinates on Shift-Click": "Copy Coordinates on Shift-Click", + "Copy coordinates on shift-click": "Copy coordinates on shift-click", "Map coordinates will be copied to the clipboard when shift-clicking.": "Map coordinates will be copied to the clipboard when shift-clicking.", "This setting is experimental and could cause marker data issues. Use at your own risk.": "This setting is experimental and could cause marker data issues. Use at your own risk.", - "Import Marker CSV File": "Import Marker CSV File", - "Choose File": "Choose File", + "Import marker CSV file": "Import marker CSV file", + "Choose file": "Choose file", "Upload CSV File": "Upload CSV File", "Map not specified for line %1": "Map not specified for line %1", //line number in csv "Could not parse latitude for line %1": @@ -131,23 +131,23 @@ export default { "Marker file successfully imported.": "Marker file successfully imported.", "There was an error while importing %1": "There was an error while importing %1", //csv file name - "Export Marker Data": "Export Marker Data", + "Export marker data": "Export marker data", "Export all marker data to a CSV file.": "Export all marker data to a CSV file.", Export: "Export", - "Enable Draw Mode by Default": "Enable Draw Mode by Default", + "Enable draw mode by default": "Enable draw mode by default", "The draw control will be added to maps by default. Can be overridden with the draw map block parameter.": "The draw control will be added to maps by default. Can be overridden with the draw map block parameter.", - "Default Units": "Default Units", + "Default units": "Default units", "Select the default system of units for the map.": "Select the default system of units for the map.", - "Default Tile Server": "Default Tile Server", + "Default tile server": "Default tile server", "It is up to you to ensure you have proper access to this tile server.": "It is up to you to ensure you have proper access to this tile server.", - "Default Tile Server Attribution": "Default Tile Server Attribution", + "Default tile server attribution": "Default tile server attribution", "Please ensure your attribution meets all requirements set by the tile server.": "Please ensure your attribution meets all requirements set by the tile server.", - "Default Tile Server (Dark Mode)": "Default Tile Server (Dark Mode)", + "Default tile server (dark mode)": "Default tile server (dark mode)", Imperial: "Imperial", Metric: "Metric", @@ -156,18 +156,18 @@ export default { "Only display when zooming in below this zoom.": "Only display when zooming in below this zoom.", "Reset": "Reset", - "Default Tile Server Subdomains": "Default Tile Server Subdomains", + "Default tile server subdomains": "Default tile server subdomains", "Available subdomains for this tile server concurrent requests.": "Available subdomains for this tile server concurrent requests. Spilt by ',', etc. 'a,b,c'", //modals/settings.ts - "Marker Name": "Marker Name", + "Marker name": "Marker name", "Marker name already exists.": "Marker name already exists.", "Marker name cannot be empty.": "Marker name cannot be empty.", "Font Awesome icon name (e.g. map-marker).": "Font Awesome icon name (e.g. map-marker).", - "Use Image for Icon": "Use Image for Icon", - "Layer Icon": "Layer Icon", + "Use image for icon": "Use image for icon", + "Layer icon": "Layer icon", "The icon will be layered on the base icon.": "The icon will be layered on the base icon.", "Override default icon color.": "Override default icon color.", @@ -190,44 +190,44 @@ export default { "There was an error parsing the JSON.", //modals/context.ts - "Execute Command": "Execute Command", + "Execute command": "Execute command", "The marker will execute an Obsidian command on click": "The marker will execute an Obsidian command on click", - "Command to Execute": "Command to Execute", - "Name of Obsidian Command to execute": - "Name of Obsidian Command to execute", + "Command to execute": "Command to execute", + "Name of Obsidian command to execute": + "Name of Obsidian command to execute", Command: "Command", - "Note to Open": "Note to Open", + "Note to open": "Note to open", "Path of note to open": "Path of note to open", Path: "Path", - "Marker Type": "Marker Type", + "Marker type": "Marker type", Default: "Default", - "Display Tooltip": "Display Tooltip", - "Min Zoom": "Min Zoom", + "Display tooltip": "Display tooltip", + "Min zoom": "Min zoom", "Only display when zooming in below this zoom. Current map minimum": "Only display when zooming in below this zoom. Current map minimum", "Minimum zoom must be a number.": "Minimum zoom must be a number.", - "Max Zoom": "Max Zoom", + "Max zoom": "Max zoom", "Only display when zooming out above this zoom. Current map maximum": "Only display when zooming out above this zoom. Current map maximum", "Maximum zoom must be a number.": "Maximum zoom must be a number.", - "Associate Tags": "Associate Tags", + "Associate tags": "Associate tags", "Markers created from this tag using ": "Markers created from this tag using ", " will use this marker icon by default.": " will use this marker icon by default.", - "Delete Marker": "Delete Marker", - "Overlay Radius": "Overlay Radius", + "Delete marker": "Delete marker", + "Overlay radius": "Overlay radius", "Circle radius in": "Circle radius in", "Radius must be greater than 0.": "Radius must be greater than 0.", - "Overlay Description": "Overlay Description", - "Overlay Color": "Overlay Color", - "Delete Overlay": "Delete Overlay", + "Overlay description": "Overlay description", + "Overlay color": "Overlay color", + "Delete overlay": "Delete overlay", //modals/geojson.ts - "File Name": "File Name", + "File name": "File name", "Enter a file name.": "Enter a file name.", //map/view.ts - "Leaflet Map": "Leaflet Map", + "Leaflet map": "Leaflet map", //map/map.ts 'Marker type "%1" does not exist, using default.': @@ -238,8 +238,8 @@ export default { "There was an error adding GeoJSON to map", "There was an error adding GPX to map": "There was an error adding GPX to map", - "Edit Overlay": "Edit Overlay", - "Create Marker": "Create Marker", + "Edit overlay": "Edit overlay", + "Create marker": "Create marker", "OpenStreetMap has restricted the use of its tile server in Obsidian. Your map may break at any time. Please switch to a different tile server.": "OpenStreetMap has restricted the use of its tile server in Obsidian. Your map may break at any time. Please switch to a different tile server.", "There was an issue parsing the tile layer: %1": @@ -252,8 +252,8 @@ export default { "This marker cannot be edited because it was defined in the code block.", "This overlay cannot be edited because it was defined in the code block.": "This overlay cannot be edited because it was defined in the code block.", - "Edit Marker": "Edit Marker", - "Convert to Code Block": "Convert to Code Block", + "Edit marker": "Edit marker", + "Convert to code block": "Convert to code block", "Leaflet: Could not create icon for %1 - does this type exist in settings?": "Leaflet: Could not create icon for %1 - does this type exist in settings?", @@ -265,19 +265,19 @@ export default { Speed: "Speed", Pace: "Pace", Temperature: "Temperature", - "Heart Rate": "Heart Rate", + "Heart rate": "Heart rate", Cadence: "Cadence", spm: "spm", //controls/zoom.ts - "Show All Markers": "Show All Markers", + "Show all markers": "Show all markers", //controls/reset.ts - "Reset View": "Reset View", + "Reset view": "Reset view", //controls/mapview.ts - "Edit View Parameters": "Edit View Parameters", - "Save Parameters to View": "Save Parameters to View", + "Edit view parameters": "Edit view parameters", + "Save parameters to view": "Save parameters to view", //controls/gpx.ts "Zoom to %1 GPX Track%2": "Zoom to %1 GPX Track%2", //number of tracks, plural @@ -288,14 +288,14 @@ export default { //controls/filter.ts All: "All", None: "None", - "Filter Markers": "Filter Markers", + "Filter markers": "Filter markers", //control/edit.ts - "Bulk Edit Markers": "Bulk Edit Markers", - "Delete All": "Delete All", + "Bulk edit markers": "Bulk edit markers", + "Delete all": "Delete all", marker: "marker", markers: "markers", - "Add New": "Add New", + "Add new": "Add new", "There was an issue with the provided latitude.": "There was an issue with the provided latitude.", "There was an issue with the provided longitude.": @@ -305,12 +305,12 @@ export default { Polygon: "Polygon", Polyline: "Polyline", Rectangle: "Rectangle", - "Free Draw": "Free Draw", - "Delete Shapes": "Delete Shapes", + "Free sraw": "Free draw", + "Delete shapes": "Delete shapes", Done: "Done", Text: "Text", Color: "Color", - "Fill Color": "Fill Color", - "Move Shapes": "Move Shapes", - "Export Drawing to GeoJSON": "Export Drawing to GeoJSON", + "Fill color": "Fill color", + "Move shapes": "Move shapes", + "Export drawing to GeoJSON": "Export drawing to GeoJSON", }; diff --git a/src/l10n/locales/zh_CN.ts b/src/l10n/locales/zh_CN.ts index 506de0b..7a458e9 100644 --- a/src/l10n/locales/zh_CN.ts +++ b/src/l10n/locales/zh_CN.ts @@ -1,7 +1,7 @@ export default { //main.ts "Loading Obsidian Leaflet v%1": "加载Obsidian Leaflet版本 v%1", //version number - "Open Leaflet Map": "打开 Leaflet 地图", + "Open Leaflet map": "打开 Leaflet 地图", "Unloading Obsidian Leaflet": "卸载 Obsidian Leaflet 中", "Obsidian Leaflet maps must have an ID.": "Obsidian Leaflet 地图必须包含 ID.", @@ -75,54 +75,54 @@ export default { //settings.ts - "Obsidian Leaflet Settings": "Obsidian Leaflet 设置", - "Default Map Marker": "默认地图标记", + "Leaflet settings": "Leaflet 设置", + "Default map marker": "默认地图标记", "This marker is always available.": "此标记始终可用", - "Icon Name": "图标名称", + "Icon name": "图标名称", "A default marker must be defined.": "必须定义默认标记", "The selected icon does not exist in Font Awesome Free.": "所选图标不存在于 Font Awesome Free 中", - "Upload Image": "上传图片", - "Marker Color": "标记颜色", - "Layer Base Marker": "图层基本标记", + "Upload image": "上传图片", + "Marker color": "标记颜色", + "Layer base marker": "图层基本标记", "Use as base layer for additional markers by default.": "默认情况下,将其用作附加标记的基本图层", - "Additional Map Markers": "附加地图标记", - "Add Additional": "添加附加", + "Additional map markers": "附加地图标记", + "Add additional": "添加附加", "These markers will be available in the right-click menu on the map.": "这些标记将在地图上的右键菜单可选", - "Default Latitude": "默认纬度", + "Default latitude": "默认纬度", "Real-world maps will open to this latitude if not specified.": "如果未指定,则使用此纬度作为默认值", "Latitude must be a number.": "纬度必须是数字", - "Default Longitude": "默认经度", + "Default longitude": "默认经度", "Real-world maps will open to this longitude if not specified.": "如果未指定,则使用此经度作为默认值", "Longitude must be a number.": "经度必须是数字", - "Reset to Default": "重置为默认值", + "Reset to default": "重置为默认值", "Please back up your data before changing this setting.": "在更改此设置之前,请先备份您的数据", "Current directory": "当前目录", - "Default Config Directory": "默认配置目录", - "Default Marker Tooltip Behavior": "何时显示默认标记提示", + "Default config directory": "默认配置目录", + "Default marker tooltip behavior": "何时显示默认标记提示", "New markers will be created to this setting by default. Can be overridden per-marker.": "新创建的标记将会加入到下面,在此处对不同的标记进行自定义设置提示方式", //TODO not understand this feature Always: "始终", Hover: "悬停", Never: "从不", - "Display Note Preview": "显示笔记预览", + "Display note preview": "显示笔记预览", "Markers linked to notes will show a note preview when hovered.": "当鼠标悬停在已经关联笔记的标记上时,会显示关联笔记的预览界面", - "Display Overlay Tooltips": "显示叠加层提示", + "Display overlay tooltips": "显示叠加层提示", "Overlay tooltips will display when hovered.": "当鼠标悬停在叠加层上时显示提示", - "Copy Coordinates on Shift-Click": "Shift-单击鼠标左键 时复制坐标", + "Copy coordinates on shift-click": "Shift-单击鼠标左键 时复制坐标", "Map coordinates will be copied to the clipboard when shift-clicking.": "当按下 Shift 并单击鼠标左键时,地图坐标将被复制到剪贴板", "This setting is experimental and could cause marker data issues. Use at your own risk.": "此设置是实验性的,可能会导致标记数据出现问题,请自行承担风险。", - "Import Marker CSV File": "导入标记 CSV 文件", - "Choose File": "选择文件", + "Import marker CSV file": "导入标记 CSV 文件", + "Choose file": "选择文件", "Upload CSV File": "上传 CSV 文件", "Map not specified for line %1": "第 %1 行未指定地图", //line number in csv "Could not parse latitude for line %1": @@ -132,38 +132,38 @@ export default { "Marker file successfully imported.": "标记文件已成功导入", "There was an error while importing %1": "导入 %1 时出错", //csv file name - "Export Marker Data": "导出标记数据", + "Export marker data": "导出标记数据", "Export all marker data to a CSV file.": "将所有标记数据导出到 CSV 文件", Export: "导出", - "Enable Draw Mode by Default": "默认启用绘制模式", + "Enable draw mode by default": "默认启用绘制模式", "The draw control will be added to maps by default. Can be overridden with the draw map block parameter.": "默认情况下,地图会显示绘制控件,可以使用在地图参数配置中自定义关闭控件显示",//TODO not undderstand this feature - "Default Units": "默认单位", + "Default units": "默认单位", "Select the default system of units for the map.": "选择地图的默认单位制", - "Default Tile Server": "默认瓦片服务器(Tile Server)", + "Default tile server": "默认瓦片服务器(Tile Server)", "It is up to you to ensure you have proper access to this tile server.": "请确保您有权访问此瓦片服务器", - "Default Tile Server Attribution": "默认瓦片服务器版权描述", + "Default tile server attribution": "默认瓦片服务器版权描述", "Please ensure your attribution meets all requirements set by the tile server.": "请确保您的版权符合瓦片服务器的所有要求,此段将显示在地图右下角", - "Default Tile Server (Dark Mode)": "默认瓦片服务器(暗黑主题模式)", + "Default tile server (dark mode)": "默认瓦片服务器(暗黑主题模式)", Imperial: "英制", Metric: "公制", "Only display when zooming out above this zoom.": "仅当缩放级别大于此缩放级别时显示", "Only display when zooming in below this zoom.": "仅当缩放级别小于此缩放级别时显示", "Reset": "重置为默认", - "Default Tile Server Subdomains": "默认瓦片服务器子域", + "Default tile server subdomains": "默认瓦片服务器子域", "Available subdomains for this tile server concurrent requests.": "瓦片服务器的子域列表,逗号','作为分隔符,如'a,b,c',主要用来并发请求瓦片服务器,将会替换在瓦片服务器的's'参数", //modals/settings.ts - "Marker Name": "标记名称", + "Marker name": "标记名称", "Marker name already exists.": "标记名称已存在", "Marker name cannot be empty.": "标记名称不能为空", "Font Awesome icon name (e.g. map-marker).": "Font Awesome 图标名称(例如 map-marker)", - "Use Image for Icon": "使用图片作为图标", - "Layer Icon": "图标层", + "Use image for icon": "使用图片作为图标", + "Layer icon": "图标层", "The icon will be layered on the base icon.": "图标将叠加在基础图标上", "Override default icon color.": "覆盖默认图标颜色", Save: "保存", @@ -183,44 +183,44 @@ export default { "解析JSON时出错", //modals/context.ts - "Execute Command": "执行命令", + "Execute command": "执行命令", "The marker will execute an Obsidian command on click": "点击标记将执行Obsidian命令", - "Command to Execute": "要执行的命令", + "Command to execute": "要执行的命令", "Name of Obsidian Command to execute": "要执行的Obsidian命令名称", Command: "命令", - "Note to Open": "要打开的笔记", + "Note to open": "要打开的笔记", "Path of note to open": "要打开的笔记的路径", Path: "路径", - "Marker Type": "标记类型", + "Marker type": "标记类型", Default: "默认", - "Display Tooltip": "显示提示信息", - "Min Zoom": "最小缩放级别", + "Display tooltip": "显示提示信息", + "Min zoom": "最小缩放级别", "Only display when zooming in below this zoom. Current map minimum": "只有在缩放级别低于此级别时才显示。当前地图最小级别", "Minimum zoom must be a number.": "最小缩放级别必须为数字", - "Max Zoom": "最大缩放级别", + "Max zoom": "最大缩放级别", "Only display when zooming out above this zoom. Current map maximum": "只有在缩放级别高于此级别时才显示,当前地图最大级别", "Maximum zoom must be a number.": "最大缩放级别必须为数字", - "Associate Tags": "关联标签", + "Associate tags": "关联标签", "Markers created from this tag using ": "属性", " will use this marker icon by default.":"指定tag中包含此处填写的tag,则从这个tag创建的地图标记将会使用当前标记图标", - "Delete Marker": "删除标记", - "Overlay Radius": "覆盖半径", + "Delete marker": "删除标记", + "Overlay radius": "覆盖半径", "Circle radius in": "圆的半径为", "Radius must be greater than 0.": "半径必须大于0", - "Overlay Description": "覆盖说明", - "Overlay Color": "覆盖颜色", - "Delete Overlay": "删除覆盖", + "Overlay description": "覆盖说明", + "Overlay color": "覆盖颜色", + "Delete overlay": "删除覆盖", //modals/geojson.ts - "File Name": "文件名", + "File name": "文件名", "Enter a file name.": "输入文件名。", //map/view.ts - "Leaflet Map": "Leaflet 地图", + "Leaflet map": "Leaflet 地图", //map/map.ts 'Marker type "%1" does not exist, using default.': '标记类型 "%1" 不存在,使用默认值', //标记类型 @@ -239,8 +239,8 @@ export default { "No command found!": "未找到命令!", "This marker cannot be edited because it was defined in the code block.": "此标记无法编辑,因为它已经在代码块中被使用", "This overlay cannot be edited because it was defined in the code block.": "此覆盖层无法编辑,因为它已经在代码块中被使用", - "Edit Marker": "编辑标记", - "Convert to Code Block": "转换成代码块", + "Edit marker": "编辑标记", + "Convert to code block": "转换成代码块", "Leaflet: Could not create icon for %1 - does this type exist in settings?": "Leaflet:无法为%1创建图标-在设置中是否存在此类型?", @@ -257,14 +257,14 @@ export default { spm: "spm", //controls/zoom.ts - "Show All Markers": "显示所有标记", + "Show all markers": "显示所有标记", //controls/reset.ts - "Reset View": "重置视图", + "Reset view": "重置视图", //controls/mapview.ts - "Edit View Parameters": "编辑视图参数", - "Save Parameters to View": "保存参数到视图", + "Edit view parameters": "编辑视图参数", + "Save parameters to view": "保存参数到视图", //controls/gpx.ts "Zoom to %1 GPX Track%2": "缩放到 %1 条 GPX 轨迹%2", //number of tracks, plural @@ -275,11 +275,11 @@ export default { //controls/filter.ts All: "全部", None: "无", - "Filter Markers": "筛选标记", + "Filter markers": "筛选标记", //control/edit.ts - "Bulk Edit Markers": "批量编辑标记", - "Delete All": "全部删除", + "Bulk edit markers": "批量编辑标记", + "Delete all": "全部删除", marker: "标记", markers: "标记", "Add New": "添加新的", @@ -296,7 +296,7 @@ export default { Done: "完成", Text: "文本", Color: "颜色", - "Fill Color": "填充颜色", - "Move Shapes": "移动形状", - "Export Drawing to GeoJSON": "导出绘制的GeoJSON", + "Fill color": "填充颜色", + "Move shapes": "移动形状", + "Export drawing to GeoJSON": "导出绘制的GeoJSON", }; diff --git a/src/map/view.ts b/src/map/view.ts index e89308a..6574933 100644 --- a/src/map/view.ts +++ b/src/map/view.ts @@ -56,7 +56,7 @@ export class LeafletMapView extends ItemView { } getDisplayText() { - return t("Leaflet Map"); + return t("Leaflet map"); } getViewType() { return VIEW_TYPE; @@ -72,7 +72,7 @@ export class LeafletMapView extends ItemView { onMoreOptionsMenu(menu: Menu): void { menu.addItem((item) => { item.setIcon("pencil") - .setTitle("Edit Map Parameters") + .setTitle("Edit map parameters") .onClick(() => { const modal = new EditParametersModal(this.plugin); modal.onClose = () => {}; diff --git a/src/modals/context.ts b/src/modals/context.ts index 66ff729..4e0d7bd 100644 --- a/src/modals/context.ts +++ b/src/modals/context.ts @@ -46,7 +46,7 @@ export class MarkerContextModal extends Modal { this.contentEl.empty(); new Setting(this.contentEl) - .setName(t("Marker Type")) + .setName(t("Marker type")) .addDropdown((drop) => { drop.addOption("default", t("Default")); this.map.markerIcons.forEach((marker) => { @@ -66,8 +66,8 @@ export class MarkerContextModal extends Modal { }); if (this.tempMarker.command) { new Setting(this.contentEl) - .setName(t("Command to Execute")) - .setDesc(t("Name of Obsidian Command to execute")) + .setName(t("Command to execute")) + .setDesc(t("Name of Obsidian command to execute")) .addText((text) => { let commands = this.app.commands.listCommands(); @@ -95,7 +95,7 @@ export class MarkerContextModal extends Modal { }); } else { new Setting(this.contentEl) - .setName(t("Note to Open")) + .setName(t("Note to open")) .setDesc(t("Path of note to open")) .addText((text) => { let files = this.app.vault.getFiles(); @@ -131,7 +131,7 @@ export class MarkerContextModal extends Modal { ); if (this.advanced) { new Setting(this.contentEl) - .setName(t("Execute Command")) + .setName(t("Execute command")) .setDesc( t("The marker will execute an Obsidian command on click") ) @@ -145,7 +145,7 @@ export class MarkerContextModal extends Modal { ); }); new Setting(this.contentEl) - .setName(t("Display Tooltip")) + .setName(t("Display tooltip")) .addDropdown((drop) => { drop.addOption("hover", t("Hover")); drop.addOption("always", t("Always")); @@ -158,7 +158,7 @@ export class MarkerContextModal extends Modal { }); new Setting(this.contentEl) - .setName(t("Min Zoom")) + .setName(t("Min zoom")) .setDesc( t( "Only display when zooming in below this zoom. Current map minimum" @@ -189,7 +189,7 @@ export class MarkerContextModal extends Modal { }); }); new Setting(this.contentEl) - .setName(t("Max Zoom")) + .setName(t("Max zoom")) .setDesc( t( "Only display when zooming out above this zoom. Current map maximum" @@ -224,7 +224,7 @@ export class MarkerContextModal extends Modal { new Setting(this.contentEl).addButton((b) => { b.setIcon("trash") .setWarning() - .setTooltip(t("Delete Marker")) + .setTooltip(t("Delete marker")) .onClick(() => { this.deleted = true; this.close(); @@ -258,7 +258,7 @@ export class OverlayContextModal extends Modal { radius = radius * this.map.scale; } new Setting(this.contentEl) - .setName(t("Overlay Radius")) + .setName(t("Overlay radius")) .setDesc( `${t("Circle radius in")} ${ UNIT_NAME_ALIASES[this.tempOverlay.unit] ?? t("meters") @@ -294,14 +294,14 @@ export class OverlayContextModal extends Modal { }); const desc = new Setting(this.contentEl) - .setName(t("Overlay Description")) + .setName(t("Overlay description")) .addText((t) => { t.setValue(this.tempOverlay.desc).onChange((v) => { this.tempOverlay.desc = v; }); }); - const color = new Setting(this.contentEl).setName(t("Overlay Color")); + const color = new Setting(this.contentEl).setName(t("Overlay color")); /** convert color to hex */ let colorOfOverlay = this.tempOverlay.color; if (!/#\w{3,6}/.test(colorOfOverlay)) { @@ -326,7 +326,7 @@ export class OverlayContextModal extends Modal { }; new Setting(this.contentEl) - .setName(t("Display Tooltip")) + .setName(t("Display tooltip")) .addDropdown((drop) => { drop.addOption("hover", t("Hover")); drop.addOption("never", t("Never")); @@ -340,7 +340,7 @@ export class OverlayContextModal extends Modal { new Setting(this.contentEl).addButton((b) => { b.setIcon("trash") .setWarning() - .setTooltip(t("Delete Overlay")) + .setTooltip(t("Delete overlay")) .onClick(() => { this.deleted = true; diff --git a/src/modals/geojson.ts b/src/modals/geojson.ts index 3c4d71d..d5a1606 100644 --- a/src/modals/geojson.ts +++ b/src/modals/geojson.ts @@ -17,7 +17,7 @@ export class GeoJSONModal extends Modal { contentEl.createEl("h1", { text: t("Enter a file name.") }); new Setting(contentEl) - .setName(t("File Name")) + .setName(t("File name")) .addText((text) => { text.onChange(value => this.result = value); }); diff --git a/src/modals/settings.ts b/src/modals/settings.ts index 5c2a2e5..22d07f6 100644 --- a/src/modals/settings.ts +++ b/src/modals/settings.ts @@ -53,10 +53,10 @@ export class CreateMarkerModal extends Modal { let typeTextInput: TextComponent; let markerName = new Setting(iconSettings) - .setName(t("Marker Name")) + .setName(t("Marker name")) .addText((text) => { typeTextInput = text - .setPlaceholder(t("Marker Name")) + .setPlaceholder(t("Marker name")) .setValue(this.tempMarker.type); typeTextInput.onChange((new_value) => { if ( @@ -88,10 +88,10 @@ export class CreateMarkerModal extends Modal { let iconTextInput: TextComponent; let iconName = new Setting(iconSettings) - .setName(t("Icon Name")) + .setName(t("Icon name")) .setDesc(t("Font Awesome icon name (e.g. map-marker).")) .addText((text) => { - text.setPlaceholder(t("Icon Name")).setValue( + text.setPlaceholder(t("Icon name")).setValue( !this.tempMarker.isImage ? this.tempMarker.iconName : "" ); @@ -151,10 +151,10 @@ export class CreateMarkerModal extends Modal { } }); new Setting(iconSettings) - .setName(t("Use Image for Icon")) + .setName(t("Use image for icon")) .addButton((b) => { - b.setButtonText(t("Upload Image")).setTooltip( - t("Upload Image") + b.setButtonText(t("Upload image")).setTooltip( + t("Upload image") ); b.buttonEl.addClass("leaflet-file-upload"); b.buttonEl.appendChild(input); @@ -362,7 +362,7 @@ export class CreateMarkerModal extends Modal { } new Setting(createNewMarker) - .setName(t("Layer Icon")) + .setName(t("Layer icon")) .setDesc(t("The icon will be layered on the base icon.")) .addToggle((toggle) => { toggle.setValue(this.tempMarker.layer).onChange((v) => { @@ -371,7 +371,7 @@ export class CreateMarkerModal extends Modal { }); }); let colorInput = new Setting(createNewMarker) - .setName(t("Marker Color")) + .setName(t("Marker color")) .setDesc(t("Override default icon color.")); let colorInputNode = colorInput.controlEl.createEl("input", { attr: { @@ -406,7 +406,7 @@ export class CreateMarkerModal extends Modal { } new Setting(createNewMarker) - .setName(t("Min Zoom")) + .setName(t("Min zoom")) .setDesc(t("Only display when zooming in below this zoom.")) .addText((text) => { let warned = false; @@ -431,7 +431,7 @@ export class CreateMarkerModal extends Modal { }); }); new Setting(createNewMarker) - .setName(t("Max Zoom")) + .setName(t("Max zoom")) .setDesc(t("Only display when zooming out above this zoom.")) .addText((text) => { let warned = false; @@ -586,7 +586,7 @@ export class CreateMarkerModal extends Modal { let tag: string; const tagSetting = new Setting(containerEl) .setHeading() - .setName(t("Associate Tags")) + .setName(t("Associate tags")) .setDesc(t("Markers created from this tag using ")) .addText((t) => { t.setPlaceholder("Add Tag"); diff --git a/src/settings/settings.ts b/src/settings/settings.ts index 9d66269..c7ab179 100644 --- a/src/settings/settings.ts +++ b/src/settings/settings.ts @@ -46,13 +46,7 @@ export class ObsidianLeafletSettingTab extends PluginSettingTab { containerEl.addClass("obsidian-leaflet-settings"); - containerEl.createEl("h2", { text: t("Obsidian Leaflet Settings") }); - - this.createCSVSetting(containerEl.createDiv()); - - this.createMarkerSettings(containerEl.createDiv()); - - this.createMapSettings(containerEl.createDiv()); + this.createSettings(containerEl.createDiv()); let defaultMarker = containerEl.createDiv( "additional-markers-container" @@ -74,268 +68,352 @@ export class ObsidianLeafletSettingTab extends PluginSettingTab { }); await this.plugin.saveSettings(); } - createDefaultMarkerSettings(defaultMarker: HTMLDivElement) { - let defaultSetting = new Setting(defaultMarker) - .setHeading() - .setName(t("Default Map Marker")) - .setDesc(t("This marker is always available.")); - let iconDisplay = defaultSetting.settingEl.createDiv({ - attr: { - style: `align-self: start; margin: 0 18px; font-size: 24px; color: ${this.data.defaultMarker.color};` - } - }); - - iconDisplay.appendChild(getMarkerIcon(this.data.defaultMarker).node); - - let settings = defaultMarker.createDiv({ - cls: "additional-markers" - }); + createSettings(containerEl: HTMLElement) { + const importSetting = new Setting(containerEl); + importSetting + .setName(t("Import marker CSV file")) + .setDesc( + t( + "This setting is experimental and could cause marker data issues. Use at your own risk." + ) + ) const input = createEl("input", { attr: { type: "file", - name: "image", - accept: "image/*" + name: "merge", + accept: ".csv" } }); - const defaultMarkerIconSetting = new Setting(settings) - .setName(t("Icon Name")) - .addText((text) => { - text.setPlaceholder(t("Icon Name")).setValue( - !this.data.defaultMarker.isImage - ? this.data.defaultMarker.iconName - : "" - ); - - const validate = async () => { - const new_value = text.inputEl.value; - - if (!new_value.length) { - setValidationError( - text, - t("A default marker must be defined.") - ); - return; - } - if ( - !findIconDefinition({ - iconName: new_value as IconName, - prefix: "fas" - }) - ) { - setValidationError( - text, - t( - "The selected icon does not exist in Font Awesome Free." - ) - ); - return; - } - - removeValidationError(text); - this.data.defaultMarker.iconName = new_value; - this.data.defaultMarker.isImage = false; - - await this.plugin.saveMarkerTypes(); - - this.display(); - }; - - const modal = new IconSuggestionModal( - this.app, - text, - iconNames - ); - - modal.onClose = validate; - - text.inputEl.onblur = validate; - }) - .addButton((b) => { - b.setButtonText(t("Upload Image")).setTooltip( - t("Upload Image") - ); - b.buttonEl.addClass("leaflet-file-upload"); - b.buttonEl.appendChild(input); - b.onClick(() => input.click()); - }); + importSetting.addButton((b) => { + b.setButtonText(t("Choose file")).setTooltip(t("Upload CSV file")); + b.buttonEl.addClass("leaflet-file-upload"); + b.buttonEl.appendChild(input); + b.onClick(() => input.click()); + }); - /** Image Uploader */ input.onchange = async () => { const { files } = input; if (!files.length) return; + try { + const csv = await files[0].text(), + markersToAdd: Map = + new Map(), + parsed = parseCSV(csv); - const image = files[0]; - const reader = new FileReader(); - reader.onloadend = (evt) => { - var image = new Image(); - image.onload = () => { - // Resize the image - const canvas = document.createElement("canvas"), - max_size = 24; - let width = image.width, - height = image.height; - if (width >= height && width > max_size) { - height *= max_size / width; - width = max_size; - } else if (height >= width && height > max_size) { - width *= max_size / height; - height = max_size; - } - canvas.width = width; - canvas.height = height; - canvas - .getContext("2d") - .drawImage(image, 0, 0, width, height); + if (parsed.data && parsed.data.length) { + for (let i = 0; i < parsed.data.length; i++) { + let data = parsed.data[i]; + if (!data || data.length < 6) continue; + let [map, type, lat, long, link, layer, id] = data.map( + (l) => l.replace(/"/g, "") + ); + if (!map || !map.length || map === "undefined") { + new Notice( + t("Map not specified for line %1", `${i + 1}`) + ); + continue; + } + if ( + !type || + !type.length || + type === "undefined" || + (type != "default" && + !this.data.markerIcons.find( + ({ type: t }) => t == type + )) + ) { + type = "default"; + } + if (!lat || !lat.length || isNaN(Number(lat))) { + new Notice( + t( + "Could not parse latitude for line %1", + `${i + 1}` + ) + ); + continue; + } + if (!long || !long.length || isNaN(Number(long))) { + new Notice( + t( + "Could not parse longitude for line %1", + `${i + 1}` + ) + ); + continue; + } - this.data.defaultMarker.isImage = true; - this.data.defaultMarker.imageUrl = - canvas.toDataURL("image/png"); + if (!link || !link.length || link === "undefined") { + link = undefined; + } else if (/\[\[[\s\S]+\]\]/.test(link)) { + //obsidian wiki-link + [, link] = link.match(/\[\[([\s\S]+)\]\]/); + } + if (!id || !id.length || id === "undefined") { + id = getId(); + } + if (!markersToAdd.has(map)) markersToAdd.set(map, []); + const mapMap = markersToAdd.get(data[0]); + mapMap.push({ + type: type, + loc: [Number(lat), Number(long)], + percent: undefined, + link: link, + layer: layer, + id: id, + command: false, + description: null, + mutable: true, + minZoom: null, + maxZoom: null, + tooltip: "hover" + }); + markersToAdd.set(data[0], mapMap); + } - this.plugin.saveMarkerTypes(); - this.display(); + for (let [id, markers] of [...markersToAdd]) { + if ( + !this.data.mapMarkers.find(({ id: p }) => p == id) + ) { + const map: MapMarkerData = { + id: id, + files: [], + lastAccessed: Date.now(), + markers: [], + overlays: [], + shapes: [], + locked: false + }; + this.data.mapMarkers.push(map); + } - //defaultMarkerIconSetting.settingEl.appendChild(canvas); - }; - image.src = evt.target.result.toString(); - }; - reader.readAsDataURL(image); + if (this.plugin.maps.find(({ id: p }) => p == id)) { + let map = this.plugin.maps.find( + ({ id: p }) => p == id + ).map; + for (let marker of markers) { + map.markers = map.markers.filter( + ({ id }) => id != marker.id + ); + map.createMarker( + marker.type as string, + marker.loc, + undefined, + marker.link, + marker.id, + marker.layer + ); + } + } else { + let map = this.data.mapMarkers.find( + ({ id: p }) => p == id + ); + for (let marker of markers) { + map.markers = map.markers.filter( + ({ id }) => id != marker.id + ); + map.markers.push(marker); + } + } + } + await this.plugin.saveSettings(); + new Notice("Marker file successfully imported."); + } + } catch (e) { + new Notice( + t("There was an error while importing %1", files[0].name) + ); + console.error(e); + } input.value = null; }; - if (!this.data.defaultMarker.isImage) { - let colorInput = new Setting(settings).setName(t("Marker Color")); - let colorInputNode = colorInput.controlEl.createEl("input", { - attr: { - type: "color", - value: this.data.defaultMarker.color - } - }); - colorInputNode.oninput = ({ target }) => { - this.data.defaultMarker.color = ( - target as HTMLInputElement - ).value; + let exportSetting = new Setting(containerEl); + exportSetting + .setName(t("Export marker data")) + .setDesc(t("Export all marker data to a CSV file.")) + .addButton((b) => { + b.setButtonText(t("Export")).onClick(() => { + let csv = []; + for (let { id: mapId, markers } of this.data.mapMarkers) { + for (let { type, loc, link, layer, id } of markers) { + csv.push([ + mapId, + type, + loc[0], + loc[1], + link, + layer, + id + ]); + } + } - iconDisplay.children[0].setAttribute( - "style", - `color: ${this.data.defaultMarker.color}` + let csvFile = new Blob([unparseCSV(csv)], { + type: "text/csv" + }); + let downloadLink = document.createElement("a"); + downloadLink.download = "leaflet_marker_data.csv"; + downloadLink.href = window.URL.createObjectURL(csvFile); + downloadLink.style.display = "none"; + document.body.appendChild(downloadLink); + downloadLink.click(); + document.body.removeChild(downloadLink); + }); + }); + const configSetting = new Setting(containerEl) + .setName(t("Default config directory")) + .addText(async (text) => { + let folders = this.app.vault + .getAllLoadedFiles() + .filter((f) => f instanceof TFolder); + + text.setPlaceholder( + this.data.configDirectory ?? this.app.vault.configDir ); - }; - colorInputNode.onchange = async ({ target }) => { - this.data.defaultMarker.color = ( - target as HTMLInputElement - ).value; - this.display(); - }; + const modal = new FolderSuggestionModal(this.app, text, [ + ...(folders as TFolder[]) + ]); - new Setting(settings) - .setName(t("Layer Base Marker")) - .setDesc( - t("Use as base layer for additional markers by default.") - ) - .addToggle((t) => { - t.setValue(this.data.layerMarkers); - t.onChange(async (v) => { - this.data.layerMarkers = v; - this.data.markerIcons.forEach( - (marker) => (marker.layer = v) + modal.onClose = async () => { + if (!text.inputEl.value) { + this.data.configDirectory = null; + } else { + const exists = await this.app.vault.adapter.exists( + text.inputEl.value ); - await this.plugin.saveMarkerTypes(); + if (!exists) { + //confirm} - this.display(); + this.data.configDirectory = text.inputEl.value; + await this.plugin.saveSettings(); + } + } + }; + + text.inputEl.onblur = async () => { + if (!text.inputEl.value) { return; + } + const exists = await this.app.vault.adapter.exists( + text.inputEl.value + ); + + this.data.configDirectory = text.inputEl.value; + + await this.plugin.saveSettings(); + this.display(); + }; + }) + .addExtraButton((b) => { + b.setTooltip(t("Reset to default")) + .setIcon("undo-glyph") + .onClick(async () => { + this.data.configDirectory = null; + await this.plugin.saveSettings(); + this.display(); }); + }); + configSetting.descEl.createSpan({ + text: t("Please back up your data before changing this setting.") + }); + configSetting.descEl.createEl("br"); + configSetting.descEl.createSpan({ + text: `${t("Current directory")}: ` + }); + const configDirectory = + this.data.configDirectory ?? this.app.vault.configDir; + configSetting.descEl.createEl("code", { + text: configDirectory + }); + + new Setting(containerEl) + .setName(t("Default marker tooltip behavior")) + .setDesc( + t( + "New markers will be created to this setting by default. Can be overridden per-marker." + ) + ) + .addDropdown((drop) => { + drop.addOption("always", t("Always")); + drop.addOption("hover", t("Hover")); + drop.addOption("never", t("Never")); + drop.setValue( + this.plugin.data.displayMarkerTooltips ?? "hover" + ).onChange((value: TooltipDisplay) => { + this.plugin.data.displayMarkerTooltips = value; }); - } - } - createAdditionalMarkerSettings(additionalMarkers: HTMLDivElement) { - new Setting(additionalMarkers) - .setHeading() - .setName(t("Additional Map Markers")) + }); + new Setting(containerEl) + .setName(t("Enable draw mode by default")) .setDesc( t( - "These markers will be available in the right-click menu on the map." + "The draw control will be added to maps by default. Can be overridden with the draw map block parameter." ) ) - .addButton((button: ButtonComponent): ButtonComponent => { - let b = button - .setTooltip(t("Add Additional")) - .onClick(async () => { - const newMarker = - await this.plugin.createNewMarkerType(); - if (!newMarker) return; - this.data.markerIcons.push(newMarker); - await this.plugin.saveMarkerTypes(); + .addToggle((toggle) => + toggle + .setValue(this.data.enableDraw) - this.display(); - }); - b.buttonEl.appendChild( - icon( - findIconDefinition({ - iconName: "plus", - prefix: "fas" - }) - ).node[0] - ); - return b; - }); - let markers = additionalMarkers.createDiv({ - cls: "additional-markers" - }); - this.plugin.markerIcons.slice(1).forEach((marker) => { - let setting = new Setting(markers) - .addExtraButton((b) => - b.onClick(async () => { - const edit = await this.plugin.createNewMarkerType({ - original: marker.markerIcon - }); - if (!edit || !edit.type || !edit.iconName) { - return; - } + .onChange(async (v) => { + this.data.enableDraw = v; - if (edit.type != marker.type) { - this.data.mapMarkers.forEach(({ markers }) => { - markers = markers.map((m) => { - if (m.type == marker.type) { - m.type = edit.type; - } - return m; - }); - }); - } + await this.plugin.saveSettings(); - await this.plugin.saveMarkerTypes(); this.display(); }) + ); + new Setting(containerEl) + .setName(t("Display note preview")) + .setDesc( + t( + "Markers linked to notes will show a note preview when hovered." ) - .addExtraButton((b) => - b.setIcon("trash").onClick(async () => { - this.data.markerIcons = this.data.markerIcons.filter( - (m) => m !== marker.markerIcon - ); - await this.plugin.saveMarkerTypes(); + ) + .addToggle((toggle) => + toggle.setValue(this.data.notePreview).onChange(async (v) => { + this.data.notePreview = v; + + await this.plugin.saveSettings(); + + this.display(); + }) + ); + new Setting(containerEl) + .setName(t("Display overlay tooltips")) + .setDesc(t("Overlay tooltips will display when hovered.")) + .addToggle((toggle) => + toggle + .setValue(this.data.displayOverlayTooltips) + .onChange(async (v) => { + this.data.displayOverlayTooltips = v; + + await this.plugin.saveSettings(); this.display(); }) - ); + ); + new Setting(containerEl) + .setName(t("Copy coordinates on shift-click")) + .setDesc( + t( + "Map coordinates will be copied to the clipboard when shift-clicking." + ) + ) + .addToggle((toggle) => + toggle.setValue(this.data.copyOnClick).onChange(async (v) => { + this.data.copyOnClick = v; - let markerIconDiv = createDiv({ - cls: "marker-icon-display" - }); - markerIconDiv.innerHTML = marker.html; - let name = setting.nameEl.createDiv("marker-type-display"); - name.appendChild(markerIconDiv); - name.appendText(marker.type); - if (marker.markerIcon.tags && marker.markerIcon.tags.length) { - setting.setDesc(marker.markerIcon.tags.join(", ")); - } - }); - } - createMapSettings(containerEl: HTMLElement) { - containerEl.empty(); + await this.plugin.saveSettings(); + this.display(); + }) + ); + + new Setting(containerEl).setName('Map').setHeading(); new Setting(containerEl) - .setName(t("Default Latitude")) + .setName(t("Default latitude")) .setDesc( t( "Real-world maps will open to this latitude if not specified." @@ -359,7 +437,7 @@ export class ObsidianLeafletSettingTab extends PluginSettingTab { }); }); new Setting(containerEl) - .setName(t("Default Longitude")) + .setName(t("Default longitude")) .setDesc( t( "Real-world maps will open to this longitude if not specified." @@ -384,7 +462,7 @@ export class ObsidianLeafletSettingTab extends PluginSettingTab { }); }); new Setting(containerEl) - .setName(t("Default Units")) + .setName(t("Default units")) .setDesc(t("Select the default system of units for the map.")) .addDropdown((d) => { d.addOption("imperial", t("Imperial")) @@ -396,7 +474,7 @@ export class ObsidianLeafletSettingTab extends PluginSettingTab { }); }); new Setting(containerEl) - .setName(t("Default Tile Server")) + .setName(t("Default tile server")) .setDesc( t( "It is up to you to ensure you have proper access to this tile server." @@ -420,7 +498,7 @@ export class ObsidianLeafletSettingTab extends PluginSettingTab { }) ); new Setting(containerEl) - .setName(t("Default Tile Server Subdomains")) + .setName(t("Default tile server subdomains")) .setDesc( t( "Available subdomains for this tile server concurrent requests." @@ -447,7 +525,7 @@ export class ObsidianLeafletSettingTab extends PluginSettingTab { }) ); new Setting(containerEl) - .setName(t("Default Tile Server Attribution")) + .setName(t("Default tile server attribution")) .setDesc( t( "Please ensure your attribution meets all requirements set by the tile server." @@ -474,7 +552,7 @@ export class ObsidianLeafletSettingTab extends PluginSettingTab { }) ); new Setting(containerEl) - .setName(t("Default Tile Server (Dark Mode)")) + .setName(t("Default tile server (dark mode)")) .setDesc( t( "It is up to you to ensure you have proper access to this tile server." @@ -496,365 +574,262 @@ export class ObsidianLeafletSettingTab extends PluginSettingTab { this.plugin.saveSettings(); }) ); + new Setting(containerEl).setName('Markers').setHeading(); } - createMarkerSettings(containerEl: HTMLElement) { - const configSetting = new Setting(containerEl) - .addText(async (text) => { - let folders = this.app.vault - .getAllLoadedFiles() - .filter((f) => f instanceof TFolder); - - text.setPlaceholder( - this.data.configDirectory ?? this.app.vault.configDir - ); - const modal = new FolderSuggestionModal(this.app, text, [ - ...(folders as TFolder[]) - ]); + createDefaultMarkerSettings(defaultMarker: HTMLDivElement) { + let defaultSetting = new Setting(defaultMarker) + .setName(t("Default map marker")) + .setDesc(t("This marker is always available.")); + let iconDisplay = defaultSetting.settingEl.createDiv({ + attr: { + style: `align-self: start; margin: 0 18px; font-size: 24px; color: ${this.data.defaultMarker.color};` + } + }); - modal.onClose = async () => { - if (!text.inputEl.value) { - this.data.configDirectory = null; - } else { - const exists = await this.app.vault.adapter.exists( - text.inputEl.value - ); + iconDisplay.appendChild(getMarkerIcon(this.data.defaultMarker).node); - if (!exists) { - //confirm} + let settings = defaultMarker.createDiv({ + cls: "additional-markers" + }); + const input = createEl("input", { + attr: { + type: "file", + name: "image", + accept: "image/*" + } + }); + const defaultMarkerIconSetting = new Setting(settings) + .setName(t("Icon name")) + .addText((text) => { + text.setPlaceholder(t("Icon name")).setValue( + !this.data.defaultMarker.isImage + ? this.data.defaultMarker.iconName + : "" + ); - this.data.configDirectory = text.inputEl.value; - await this.plugin.saveSettings(); - } - } - }; + const validate = async () => { + const new_value = text.inputEl.value; - text.inputEl.onblur = async () => { - if (!text.inputEl.value) { + if (!new_value.length) { + setValidationError( + text, + t("A default marker must be defined.") + ); + return; + } + if ( + !findIconDefinition({ + iconName: new_value as IconName, + prefix: "fas" + }) + ) { + setValidationError( + text, + t( + "The selected icon does not exist in Font Awesome Free." + ) + ); return; } - const exists = await this.app.vault.adapter.exists( - text.inputEl.value - ); - this.data.configDirectory = text.inputEl.value; + removeValidationError(text); + this.data.defaultMarker.iconName = new_value; + this.data.defaultMarker.isImage = false; + + await this.plugin.saveMarkerTypes(); - await this.plugin.saveSettings(); this.display(); }; - }) - .addExtraButton((b) => { - b.setTooltip(t("Reset to Default")) - .setIcon("undo-glyph") - .onClick(async () => { - this.data.configDirectory = null; - await this.plugin.saveSettings(); - this.display(); - }); - }); - configSetting.descEl.createSpan({ - text: t("Please back up your data before changing this setting.") - }); - configSetting.descEl.createEl("br"); - configSetting.descEl.createSpan({ - text: `${t("Current directory")}: ` - }); - const configDirectory = - this.data.configDirectory ?? this.app.vault.configDir; - configSetting.descEl.createEl("code", { - text: configDirectory - }); - let name = configSetting.nameEl.createDiv(); - name.appendChild( - icon( - findIconDefinition({ - iconName: "exclamation-triangle", - prefix: "fas" - }) - ).node[0] - ); - name.appendChild(createSpan({ text: t("Default Config Directory") })); - new Setting(containerEl) - .setName(t("Default Marker Tooltip Behavior")) - .setDesc( - t( - "New markers will be created to this setting by default. Can be overridden per-marker." - ) - ) - .addDropdown((drop) => { - drop.addOption("always", t("Always")); - drop.addOption("hover", t("Hover")); - drop.addOption("never", t("Never")); - drop.setValue( - this.plugin.data.displayMarkerTooltips ?? "hover" - ).onChange((value: TooltipDisplay) => { - this.plugin.data.displayMarkerTooltips = value; - }); + const modal = new IconSuggestionModal( + this.app, + text, + iconNames + ); + + modal.onClose = validate; + + text.inputEl.onblur = validate; + }) + .addButton((b) => { + b.setButtonText(t("Upload image")).setTooltip( + t("Upload image") + ); + b.buttonEl.addClass("leaflet-file-upload"); + b.buttonEl.appendChild(input); + b.onClick(() => input.click()); }); - new Setting(containerEl) - .setName(t("Enable Draw Mode by Default")) - .setDesc( - t( - "The draw control will be added to maps by default. Can be overridden with the draw map block parameter." - ) - ) - .addToggle((toggle) => - toggle - .setValue(this.data.enableDraw) - .onChange(async (v) => { - this.data.enableDraw = v; + /** Image Uploader */ + input.onchange = async () => { + const { files } = input; - await this.plugin.saveSettings(); + if (!files.length) return; - this.display(); - }) - ); - new Setting(containerEl) - .setName(t("Display Note Preview")) - .setDesc( - t( - "Markers linked to notes will show a note preview when hovered." - ) - ) - .addToggle((toggle) => - toggle.setValue(this.data.notePreview).onChange(async (v) => { - this.data.notePreview = v; + const image = files[0]; + const reader = new FileReader(); + reader.onloadend = (evt) => { + var image = new Image(); + image.onload = () => { + // Resize the image + const canvas = document.createElement("canvas"), + max_size = 24; + let width = image.width, + height = image.height; + if (width >= height && width > max_size) { + height *= max_size / width; + width = max_size; + } else if (height >= width && height > max_size) { + width *= max_size / height; + height = max_size; + } + canvas.width = width; + canvas.height = height; + canvas + .getContext("2d") + .drawImage(image, 0, 0, width, height); - await this.plugin.saveSettings(); + this.data.defaultMarker.isImage = true; + this.data.defaultMarker.imageUrl = + canvas.toDataURL("image/png"); + this.plugin.saveMarkerTypes(); this.display(); - }) - ); - new Setting(containerEl) - .setName(t("Display Overlay Tooltips")) - .setDesc(t("Overlay tooltips will display when hovered.")) - .addToggle((toggle) => - toggle - .setValue(this.data.displayOverlayTooltips) - .onChange(async (v) => { - this.data.displayOverlayTooltips = v; - await this.plugin.saveSettings(); + //defaultMarkerIconSetting.settingEl.appendChild(canvas); + }; + image.src = evt.target.result.toString(); + }; + reader.readAsDataURL(image); + + input.value = null; + }; + if (!this.data.defaultMarker.isImage) { + let colorInput = new Setting(settings).setName(t("Marker color")); + + let colorInputNode = colorInput.controlEl.createEl("input", { + attr: { + type: "color", + value: this.data.defaultMarker.color + } + }); + colorInputNode.oninput = ({ target }) => { + this.data.defaultMarker.color = ( + target as HTMLInputElement + ).value; + + iconDisplay.children[0].setAttribute( + "style", + `color: ${this.data.defaultMarker.color}` + ); + }; + colorInputNode.onchange = async ({ target }) => { + this.data.defaultMarker.color = ( + target as HTMLInputElement + ).value; + this.display(); + }; + + new Setting(settings) + .setName(t("Layer base marker")) + .setDesc( + t("Use as base layer for additional markers by default.") + ) + .addToggle((t) => { + t.setValue(this.data.layerMarkers); + t.onChange(async (v) => { + this.data.layerMarkers = v; + this.data.markerIcons.forEach( + (marker) => (marker.layer = v) + ); + + await this.plugin.saveMarkerTypes(); + this.display(); - }) - ); - new Setting(containerEl) - .setName(t("Copy Coordinates on Shift-Click")) + return; + }); + }); + } + } + createAdditionalMarkerSettings(additionalMarkers: HTMLDivElement) { + new Setting(additionalMarkers) + .setName(t("Additional map markers")) .setDesc( t( - "Map coordinates will be copied to the clipboard when shift-clicking." + "These markers will be available in the right-click menu on the map." ) ) - .addToggle((toggle) => - toggle.setValue(this.data.copyOnClick).onChange(async (v) => { - this.data.copyOnClick = v; + .addButton((button: ButtonComponent): ButtonComponent => { + let b = button + .setTooltip(t("Add Additional")) + .onClick(async () => { + const newMarker = + await this.plugin.createNewMarkerType(); + if (!newMarker) return; + this.data.markerIcons.push(newMarker); + await this.plugin.saveMarkerTypes(); - await this.plugin.saveSettings(); - this.display(); - }) - ); - } - createCSVSetting(containerEl: HTMLElement) { - const importSetting = new Setting(containerEl).setDesc( - t( - "This setting is experimental and could cause marker data issues. Use at your own risk." - ) - ); - let name = importSetting.nameEl.createDiv(); - name.appendChild( - icon( - findIconDefinition({ - iconName: "exclamation-triangle", - prefix: "fas" - }) - ).node[0] - ); - name.appendChild(createSpan({ text: t("Import Marker CSV File") })); - const input = createEl("input", { - attr: { - type: "file", - name: "merge", - accept: ".csv" - } - }); - importSetting.addButton((b) => { - b.setButtonText(t("Choose File")).setTooltip(t("Upload CSV File")); - b.buttonEl.addClass("leaflet-file-upload"); - b.buttonEl.appendChild(input); - b.onClick(() => input.click()); + this.display(); + }); + b.buttonEl.appendChild( + icon( + findIconDefinition({ + iconName: "plus", + prefix: "fas" + }) + ).node[0] + ); + return b; + }); + let markers = additionalMarkers.createDiv({ + cls: "additional-markers" }); - input.onchange = async () => { - const { files } = input; - - if (!files.length) return; - try { - const csv = await files[0].text(), - markersToAdd: Map = - new Map(), - parsed = parseCSV(csv); - - if (parsed.data && parsed.data.length) { - for (let i = 0; i < parsed.data.length; i++) { - let data = parsed.data[i]; - if (!data || data.length < 6) continue; - let [map, type, lat, long, link, layer, id] = data.map( - (l) => l.replace(/"/g, "") - ); - if (!map || !map.length || map === "undefined") { - new Notice( - t("Map not specified for line %1", `${i + 1}`) - ); - continue; - } - if ( - !type || - !type.length || - type === "undefined" || - (type != "default" && - !this.data.markerIcons.find( - ({ type: t }) => t == type - )) - ) { - type = "default"; - } - if (!lat || !lat.length || isNaN(Number(lat))) { - new Notice( - t( - "Could not parse latitude for line %1", - `${i + 1}` - ) - ); - continue; - } - if (!long || !long.length || isNaN(Number(long))) { - new Notice( - t( - "Could not parse longitude for line %1", - `${i + 1}` - ) - ); - continue; - } - - if (!link || !link.length || link === "undefined") { - link = undefined; - } else if (/\[\[[\s\S]+\]\]/.test(link)) { - //obsidian wiki-link - [, link] = link.match(/\[\[([\s\S]+)\]\]/); - } - if (!id || !id.length || id === "undefined") { - id = getId(); - } - if (!markersToAdd.has(map)) markersToAdd.set(map, []); - const mapMap = markersToAdd.get(data[0]); - mapMap.push({ - type: type, - loc: [Number(lat), Number(long)], - percent: undefined, - link: link, - layer: layer, - id: id, - command: false, - description: null, - mutable: true, - minZoom: null, - maxZoom: null, - tooltip: "hover" + this.plugin.markerIcons.slice(1).forEach((marker) => { + let setting = new Setting(markers) + .addExtraButton((b) => + b.onClick(async () => { + const edit = await this.plugin.createNewMarkerType({ + original: marker.markerIcon }); - markersToAdd.set(data[0], mapMap); - } - - for (let [id, markers] of [...markersToAdd]) { - if ( - !this.data.mapMarkers.find(({ id: p }) => p == id) - ) { - const map: MapMarkerData = { - id: id, - files: [], - lastAccessed: Date.now(), - markers: [], - overlays: [], - shapes: [], - locked: false - }; - this.data.mapMarkers.push(map); + if (!edit || !edit.type || !edit.iconName) { + return; } - if (this.plugin.maps.find(({ id: p }) => p == id)) { - let map = this.plugin.maps.find( - ({ id: p }) => p == id - ).map; - for (let marker of markers) { - map.markers = map.markers.filter( - ({ id }) => id != marker.id - ); - map.createMarker( - marker.type as string, - marker.loc, - undefined, - marker.link, - marker.id, - marker.layer - ); - } - } else { - let map = this.data.mapMarkers.find( - ({ id: p }) => p == id - ); - for (let marker of markers) { - map.markers = map.markers.filter( - ({ id }) => id != marker.id - ); - map.markers.push(marker); - } + if (edit.type != marker.type) { + this.data.mapMarkers.forEach(({ markers }) => { + markers = markers.map((m) => { + if (m.type == marker.type) { + m.type = edit.type; + } + return m; + }); + }); } - } - await this.plugin.saveSettings(); - new Notice("Marker file successfully imported."); - } - } catch (e) { - new Notice( - t("There was an error while importing %1", files[0].name) - ); - console.error(e); - } - - input.value = null; - }; - let exportSetting = new Setting(containerEl); - exportSetting - .setName(t("Export Marker Data")) - .setDesc(t("Export all marker data to a CSV file.")) - .addButton((b) => { - b.setButtonText(t("Export")).onClick(() => { - let csv = []; - for (let { id: mapId, markers } of this.data.mapMarkers) { - for (let { type, loc, link, layer, id } of markers) { - csv.push([ - mapId, - type, - loc[0], - loc[1], - link, - layer, - id - ]); - } - } + await this.plugin.saveMarkerTypes(); + this.display(); + }) + ) + .addExtraButton((b) => + b.setIcon("trash").onClick(async () => { + this.data.markerIcons = this.data.markerIcons.filter( + (m) => m !== marker.markerIcon + ); + await this.plugin.saveMarkerTypes(); + this.display(); + }) + ); - let csvFile = new Blob([unparseCSV(csv)], { - type: "text/csv" - }); - let downloadLink = document.createElement("a"); - downloadLink.download = "leaflet_marker_data.csv"; - downloadLink.href = window.URL.createObjectURL(csvFile); - downloadLink.style.display = "none"; - document.body.appendChild(downloadLink); - downloadLink.click(); - document.body.removeChild(downloadLink); - }); + let markerIconDiv = createDiv({ + cls: "marker-icon-display" }); + markerIconDiv.innerHTML = marker.html; + let name = setting.nameEl.createDiv("marker-type-display"); + name.appendChild(markerIconDiv); + name.appendText(marker.type); + if (marker.markerIcon.tags && marker.markerIcon.tags.length) { + setting.setDesc(marker.markerIcon.tags.join(", ")); + } + }); } }