From 1495a79dd29e0d4c370086aec9dfb146c7f24bc3 Mon Sep 17 00:00:00 2001 From: Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> Date: Thu, 29 Oct 2026 14:44:18 +0900 Subject: park-editor: 列の追加と文字化け項目の表示 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit スイング遊具にロッキンパッピー等を含め、シェルター列を2行に、緯度・経度を最小幅にした。草地広場・多目的広場の列を追加。文字化けした項目名をバナー表示し、古い画面からの保存で新項目・新レコードが消えないようマージする。 --- scripts/park-editor.html | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) (limited to 'scripts/park-editor.html') diff --git a/scripts/park-editor.html b/scripts/park-editor.html index e320e5e..2bcb7ea 100644 --- a/scripts/park-editor.html +++ b/scripts/park-editor.html @@ -47,6 +47,8 @@ #clear-checks { padding: .3rem .6rem; } td.mapcell { text-align: center; } td.mapcell a { text-decoration: none; padding: 0 .4rem; cursor: pointer; } + th.c-coord, td.c-coord { width: 6ch; max-width: 6ch; overflow: hidden; } + td.c-coord input { width: 6ch; min-width: 0; font-size: .72rem; } @@ -79,7 +81,7 @@ const TOY_ORDER = [ ["slide", "滑台"], ["sand", "砂場"], ["bar", "鉄棒"], - ["spring", "スプリング遊具"], + ["spring", "スイング遊具"], ["complex", "複合遊具"], ["other", "その他遊具"], ]; @@ -89,7 +91,7 @@ const TOY_TOKENS = { slide: ["滑台", "滑り台", "すべり台"], sand: ["砂場"], bar: ["鉄棒"], - spring: ["スプリング"], + spring: ["スプリング", "スイング", "ロッキンパッピー"], complex: ["複合遊具"], }; @@ -101,9 +103,10 @@ const DATASETS = { FIELD("面積㎡", "面積㎡"), FIELD("種別", "種別"), FIELD("設置者", "設置者"), FIELD("状態", "状態"), FIELD("トイレ", "トイレ"), FIELD("水飲み場", "水飲み場"), FIELD("ベンチ・椅子", "ベンチ・椅子"), - FIELD("テーブル", "テーブル"), FIELD("シェルター等", "シェルター・パーゴラ・東屋"), + FIELD("テーブル", "テーブル"), FIELD("シェルター等", "シェルター・パーゴラ・
東屋"), FIELD("防災用具", "防災用具"), FIELD("ボール遊び", "ボール遊び"), ...TOY_ORDER.map(([toy, label]) => ({ key: `__toy_${toy}`, label, toy })), + FIELD("草地広場", "草地広場"), FIELD("多目的広場", "多目的広場"), FIELD("時計", "時計"), FIELD("緯度", "緯度"), FIELD("経度", "経度"), FIELD("備考", "備考"), ], @@ -394,6 +397,7 @@ async function load(id) { isFC = data.type === "FeatureCollection"; rows = isFC ? data.features : data; render(); + showCorruptKeys(); statusEl.textContent = `${DATASETS[id].label}: ${rows.length}件`; } catch (e) { statusEl.textContent = "読み込みに失敗: " + e.message; @@ -401,7 +405,16 @@ async function load(id) { } function render() { - thead.innerHTML = "" + ["#", "確認", "地図"].concat(fields.map((f) => f.label)).map((label) => "" + label + "").join("") + ""; + const COORD_KEYS = new Set(["緯度", "経度"]); + const headCols = ["#", "確認", "地図"] + .map((label) => ({ label, cls: "" })) + .concat( + fields.map((f) => ({ label: f.label, cls: COORD_KEYS.has(f.key) ? "c-coord" : "" })), + ); + thead.innerHTML = + "" + + headCols.map((col) => `${col.label}`).join("") + + ""; tbody.innerHTML = ""; rows.forEach((row, r) => { const props = isFC ? row.properties || {} : row; @@ -444,6 +457,7 @@ function render() { fields.forEach((field, c) => { const td = document.createElement("td"); + if (field.key === "緯度" || field.key === "経度") td.className = "c-coord"; const inp = document.createElement("input"); inp.value = field.toy ? toys[field.toy] : (props[field.key] != null ? props[field.key] : ""); inp.dataset.r = r; @@ -481,6 +495,24 @@ function filter() { count.textContent = shown + " / " + rows.length + " 件"; } +// 項目名(キー)の文字化けは表に出ないため、バナーで知らせる +function showCorruptKeys() { + const hits = []; + rows.forEach((row, i) => { + const props = isFC ? row.properties || {} : row; + for (const key of Object.keys(props)) { + if (!key.includes("\uFFFD")) continue; + const name = props["公園名"] || props["name"] || props["名称"] || `行${i + 1}`; + hits.push(`${name} / ${key}`); + } + }); + if (!hits.length) return; + warningEl.hidden = false; + warningEl.textContent = `文字化けした項目名が ${hits.length} 件あります: ${hits.slice(0, 5).join(" / ")}${hits.length > 5 ? " …" : ""}`; + warningEl.style.background = "#ffcdd2"; + warningEl.style.color = "#8e0000"; +} + function markCorrupt() { tbody.querySelectorAll("input[data-r][data-c]").forEach((inp) => { inp.classList.toggle("corrupt", inp.value.includes("\uFFFD")); @@ -498,7 +530,7 @@ function corruptLabel(inp) { const props = isFC ? row.properties || {} : row; const name = props["公園名"] || props["name"] || props["名称"] || `行${Number(inp.dataset.r) + 1}`; - const label = fields[Number(inp.dataset.c)].label; + const label = fields[Number(inp.dataset.c)].label.replace(/<[^>]+>/g, ""); return `${name} / ${label}: ${inp.value}`; } -- cgit v1.3.1