98 lines
2.7 KiB
JavaScript
98 lines
2.7 KiB
JavaScript
(() => {
|
|
const t = (key, vars) => window.I18n?.t(key, vars) ?? key;
|
|
|
|
function fileStem(name) {
|
|
const base = String(name).replace(/^.*[/\\]/, "");
|
|
const dot = base.lastIndexOf(".");
|
|
return dot >= 0 ? base.slice(0, dot) : base;
|
|
}
|
|
|
|
function isYamlFile(file) {
|
|
return /\.ya?ml$/i.test(file.name);
|
|
}
|
|
|
|
function isMapImageFile(file) {
|
|
return /\.(png|pgm)$/i.test(file.name);
|
|
}
|
|
|
|
async function matchRosMapFiles(fileList) {
|
|
const files = Array.from(fileList || []);
|
|
const yamlFile = files.find(isYamlFile);
|
|
if (!yamlFile) {
|
|
throw new Error(t("maps.importNeedYaml"));
|
|
}
|
|
|
|
let imageFile = files.find((f) => f !== yamlFile && isMapImageFile(f));
|
|
try {
|
|
const yamlText = await yamlFile.text();
|
|
const imageRef = yamlText.match(/^image:\s*(\S+)/m)?.[1];
|
|
if (imageRef) {
|
|
const refStem = fileStem(imageRef);
|
|
const matched = files.find(
|
|
(f) => f !== yamlFile && isMapImageFile(f) && fileStem(f.name) === refStem,
|
|
);
|
|
if (matched) imageFile = matched;
|
|
}
|
|
} catch {
|
|
/* best-effort stem match */
|
|
}
|
|
|
|
if (!imageFile) {
|
|
throw new Error(t("maps.importNeedImage"));
|
|
}
|
|
|
|
return { yamlFile, imageFile };
|
|
}
|
|
|
|
function buildFormData(yamlFile, imageFile, extras = {}) {
|
|
const form = new FormData();
|
|
form.append("yaml", yamlFile, yamlFile.name);
|
|
form.append("image", imageFile, imageFile.name);
|
|
Object.entries(extras).forEach(([key, value]) => {
|
|
if (value != null && value !== "") form.append(key, value);
|
|
});
|
|
return form;
|
|
}
|
|
|
|
async function apiImport(path, form) {
|
|
const res = await fetch(path, { method: "POST", credentials: "include", body: form });
|
|
if (!res.ok) {
|
|
let msg = res.statusText;
|
|
try {
|
|
const err = await res.json();
|
|
if (err.error) msg = err.error;
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
throw new Error(msg);
|
|
}
|
|
return res.json();
|
|
}
|
|
|
|
async function importNewMap(fileList, extras = {}) {
|
|
const { yamlFile, imageFile } = await matchRosMapFiles(fileList);
|
|
const form = buildFormData(yamlFile, imageFile, {
|
|
name: extras.name || fileStem(yamlFile.name),
|
|
site_id: extras.site_id || "",
|
|
created_by: extras.created_by || "",
|
|
description: extras.description || "",
|
|
});
|
|
return apiImport("/api/maps/import", form);
|
|
}
|
|
|
|
async function importOverwriteMap(mapId, fileList) {
|
|
const { yamlFile, imageFile } = await matchRosMapFiles(fileList);
|
|
const form = buildFormData(yamlFile, imageFile);
|
|
return apiImport(`/api/maps/${encodeURIComponent(mapId)}/import`, form);
|
|
}
|
|
|
|
window.MapImport = {
|
|
fileStem,
|
|
isYamlFile,
|
|
isMapImageFile,
|
|
matchRosMapFiles,
|
|
importNewMap,
|
|
importOverwriteMap,
|
|
};
|
|
})();
|