补全页:手工填过的值自动进下拉候选,后面同类地点不用再打一遍

下拉的候选是渲染时定好的,这一页手工新填的活动名/类别进不去候选,
后面遇到同类地点只能照着再敲一遍——这正是「其它(自己写)」最费事的地方。

现在填过的值会被记住并补进同类下拉,标成「新填:X」,插在建议之后、
真正的候选之前,一眼就能挑到;本页实时同步(打字即生效),
翻页和点「用高德分析」重载也留得住,提交成功后清掉(那之后它们已经是真候选了)。

顺带两处:
- 草稿保存改成按 name 合并,翻页不再把上一页填的覆盖掉;分页链接也接了保存。
- 重画候选前先把「这一格已经选中的新填值」留住再还回去,
  否则改一下文本框就会把别的行选好的值悄悄抹成空。

文本框的监听直接挂在框上而不是委托到 document:`new Event('input')` 默认不冒泡,
探针第一次就是这么假绿的——直接挂不依赖冒泡,也少一层隐式约定。
This commit is contained in:
tamakyi
2026-09-20 09:32:07 +08:00
parent bf23fc62d7
commit ffee082fad
2 changed files with 102 additions and 3 deletions
+81 -3
View File
@@ -113,6 +113,7 @@
<script>
(function () {
var KEY = 'rond-fillup-draft';
var NEW = 'rond-fillup-newopts';
// 活动和类别是同一套下拉:选了「其它(自己写)」就露出旁边的文本框
document.querySelectorAll('select.fill-sel').forEach(function (sel) {
@@ -127,6 +128,70 @@
sync();
});
// 下拉的候选是渲染时定好的,手工新填的名字进不了候选,后面遇到同类地点还得重打一遍。
// 所以把填过的值记下来补进同类下拉:本页实时生效,翻页/点「用高德分析」也留得住,
// 提交成功后清掉(那之后它们已经在真正的候选里了)。
var fromOther = {act: [], cat: []}; // 从别处(别的页/上次)带来的
var fromPage = {act: [], cat: []}; // 本页文本框里当前填着的
try {
var saved = JSON.parse(sessionStorage.getItem(NEW) || '{}');
fromOther.act = saved.act || [];
fromOther.cat = saved.cat || [];
} catch (e) { /* 坏数据就当没有 */ }
var paint = function (prefix) {
var vals = fromOther[prefix].concat(fromPage[prefix].filter(function (v) {
return fromOther[prefix].indexOf(v) < 0;
}));
document.querySelectorAll('select[name^="' + prefix + '_"]').forEach(function (sel) {
// 重画不能动用户已经选好的东西:这一格选的要是「新填」里的值,先留住它
var keep = sel.value;
if (keep && vals.indexOf(keep) < 0 && [].some.call(sel.options, function (o) {
return o.value === keep && o.getAttribute('data-local');
})) vals.push(keep);
[].forEach.call(sel.querySelectorAll('option[data-local]'), function (o) { o.remove(); });
// 插在「(不动)」/建议之后、真正的候选之前,免得沉到列表最底下去找
var anchor = null;
for (var i = 0; i < sel.options.length; i++) {
var o = sel.options[i];
if (o.getAttribute('data-local') || !o.value || o.value === sel.dataset.hint) continue;
anchor = o;
break;
}
vals.forEach(function (v) {
if ([].some.call(sel.options, function (o) { return o.value === v; })) return;
var o = document.createElement('option');
o.value = v;
o.textContent = '新填:' + v;
o.setAttribute('data-local', '1');
sel.insertBefore(o, anchor);
});
// 选项重插之后浏览器不会自己选回来,得手工还回去
if (keep && sel.value !== keep) sel.value = keep;
});
};
var collect = function (prefix) {
fromPage[prefix] = [];
document.querySelectorAll('input[name^="' + prefix + '_"][name$="__custom"]').forEach(function (box) {
var v = box.value.trim();
if (v && fromPage[prefix].indexOf(v) < 0) fromPage[prefix].push(v);
});
paint(prefix);
try {
sessionStorage.setItem(NEW, JSON.stringify({
act: fromOther.act.concat(fromPage.act),
cat: fromOther.cat.concat(fromPage.cat)
}));
} catch (e) { /* 隐私模式就算了 */ }
};
// 文本框里打字就同步,不用等失焦或提交。直接挂在框上,不靠事件冒泡——
// 省得以后有人在这行 DOM 上动手脚(或程序化派发)时静默失效。
document.querySelectorAll('input[name$="__custom"]').forEach(function (box) {
box.addEventListener('input', function () { collect(box.name.split('_')[0]); });
});
// 采纳本页建议:把建议项选上(活动和类别都是下拉)
var pick = document.getElementById('pick-hints');
if (pick) {
@@ -141,18 +206,25 @@
});
}
// 「用高德分析」会整页重载,先把这一页填过的存起来、回来再恢复——
// 否则挑了半天,点一下就全没了。
// 离开本页(翻页 / 「用高德分析」)之前把填过的存起来、回来接着填——
// 否则挑了半天,点一下就全没了。按 name 合并,所以翻页也留得住。
var save = function () {
var draft = {};
try { draft = JSON.parse(sessionStorage.getItem(KEY) || '{}'); } catch (e) { draft = {}; }
document.querySelectorAll('select.fill-sel, input[name$="__custom"]').forEach(function (el) {
if (el.value) draft[el.name] = el.value;
else delete draft[el.name]; // 本页明确清空的就是不要了,别让旧值顶上来
});
try { sessionStorage.setItem(KEY, JSON.stringify(draft)); } catch (e) { /* 隐私模式就算了 */ }
};
var amap = document.getElementById('amap-btn');
if (amap) amap.addEventListener('click', save);
document.querySelectorAll('.pager a').forEach(function (a) { a.addEventListener('click', save); });
// 先把「新填」的候选补上再恢复草稿:草稿里选中的可能就是新填的值,
// 选项不在跟前的话 select.value 是设不进去的。
paint('act');
paint('cat');
try {
var draft = JSON.parse(sessionStorage.getItem(KEY) || '{}');
Object.keys(draft).forEach(function (name) {
@@ -162,11 +234,17 @@
if (el.tagName === 'SELECT') el.dispatchEvent(new Event('change'));
});
} catch (e) { /* 坏数据就当没有 */ }
// 恢复出来的文本框(`set value` 不触发 input)也要算进「新填」
collect('act');
collect('cat');
// 提交成功后草稿就没用了,清掉,免得下次进来还带着旧选择
var form = document.getElementById('fillup-form');
if (form) form.addEventListener('submit', function () {
try { sessionStorage.removeItem(KEY); } catch (e) {}
try {
sessionStorage.removeItem(KEY);
sessionStorage.removeItem(NEW);
} catch (e) {}
});
})();
</script>