微件:SaltVoteContainer:修订间差异
Salt lovely(留言 | 贡献) (一些问题修复 // 维基盐编辑器) |
Salt lovely(留言 | 贡献) 小 (编辑“微件:SaltVoteContainer” // 维基盐编辑器) |
||
| (未显示同一用户的1个中间版本) | |||
| 第1行: | 第1行: | ||
<noinclude>用于展示投票箱</noinclude><includeonly><script> | <noinclude>用于展示投票箱</noinclude><includeonly><script> | ||
/** | /** | ||
* | * | ||
| 第16行: | 第15行: | ||
document.body.querySelectorAll("div.salt-vote-container.not-init") | document.body.querySelectorAll("div.salt-vote-container.not-init") | ||
); | ); | ||
const at = (arr, index) => { | const at = (arr, index) => { | ||
| 第29行: | 第27行: | ||
}; | }; | ||
/** 渲染条状图内容 @type {(collect: {name: string, set: string[]}[], color: string[]) => string} */ | /** 渲染条状图内容 @type {(collect: {name: string, set: string[], li: HTMLElement, count: HTMLElement}[], color: string[], hasBar: boolean) => { barHTML: string }} */ | ||
const | const renderPercent = (collect, color, hasBar) => { | ||
const countAll = collect.reduce((prev, curr) => { | const countAll = collect.reduce((prev, curr) => { | ||
return prev + curr.set.length; | return prev + curr.set.length; | ||
}, 0); | }, 0); | ||
const divList = collect.map( | // 计算百分比 | ||
const percent = collect.map(({ set, li, count }) => { | |||
const res = Number(((set.length * 100) / countAll).toFixed(2)); | |||
li.style.setProperty("--vote-percent", `${res}%`); // 顺便把百分比记录上去 | |||
count.textContent = `${set.length} (${res}%)`; | |||
return res; | |||
}); | |||
const divList = hasBar | |||
? collect.map( | |||
return divList.join(""); | ({ name, set }, i) => | ||
`<div class="salt-vote-bar-item" title="${name.replace( | |||
/"/g, | |||
"'" | |||
)}" style="--vote-color:${at(color, i)};width:${ | |||
set.length ? percent[i] : 0 | |||
}%">${Number(percent[i])}%</div>` | |||
) | |||
: []; | |||
return { barHTML: divList.join("") }; | |||
}; | }; | ||
/** 主流程 */ | /** 主流程 */ | ||
/** @type {(el: HTMLDivElement) => void} */ | /** @type {(el: HTMLDivElement) => void} */ | ||
const | const process = (el) => { | ||
el.classList.remove("not-init"); | |||
const barEl = el.querySelector(".salt-vote-bar"); | const barEl = el.querySelector(".salt-vote-bar"); | ||
const colorEl = el.querySelector(".salt-vote-color"); | const colorEl = el.querySelector(".salt-vote-color"); | ||
const list = el.querySelector(" | const list = el.querySelector(".salt-vote-options"); | ||
const lists = list && list.querySelectorAll("li"); | const lists = list && list.querySelectorAll("li"); | ||
/** 收集的投票信息 @type {{name: string, set: string[]}[]} */ | const descUl = el.querySelector(".salt-vote-describe"); | ||
const descLi = descUl && descUl.querySelectorAll("li"); | |||
/** 收集的投票信息 @type {{name: string, set: string[], li: HTMLElement, count: HTMLElement, desc?: HTMLElement}[]} */ | |||
const collect = []; | const collect = []; | ||
/** 收集的投票信息 @type {{name: string, desc: HTMLElement}[]} */ | |||
const descCollect = []; | |||
/** 有问题的投票信息 @type {Record<string, Set<string>>} */ | /** 有问题的投票信息 @type {Record<string, Set<string>>} */ | ||
const wrongCollect = {}; | const wrongCollect = {}; | ||
| 第73行: | 第84行: | ||
else color.push(...defaultColor); | else color.push(...defaultColor); | ||
} | } | ||
// 获取投票选项描述 | |||
const descList = Array.from(descLi || []); | |||
descList.forEach((desc) => { | |||
const option = desc.querySelector(".salt-vote-desc-option"); | |||
const value = desc.querySelector(".salt-vote-desc"); | |||
if (!option || !value) return; | |||
const title = option.textContent || ""; | |||
const thisCollect = { name: title, desc: value }; | |||
descCollect.push(thisCollect); | |||
desc.style.setProperty("--height", "0"); | |||
}); | |||
// 获取投票信息 | // 获取投票信息 | ||
const liList = Array.from(lists); | const liList = Array.from(lists); | ||
liList.forEach((li, liIndex) => { | liList.forEach((li, liIndex) => { | ||
const option = li.querySelector(".salt-vote-option"); | const option = li.querySelector(".salt-vote-option"); | ||
const voter = li.querySelector(".salt-vote-voter"); | const voter = li.querySelector(".salt-vote-voter"); | ||
if (!option || !voter) return; | if (!option || !voter) return; | ||
const title = option.textContent || ""; | const title = option.textContent || ""; | ||
const voters = Array.from(voter.querySelectorAll("a")); | const voters = Array.from(voter.querySelectorAll("a")); | ||
const count = document.createElement("div"); | |||
const thisCollect = { name: title, set: [] }; | const thisCollect = { name: title, set: [], li: li, count }; | ||
voters.forEach((v) => { | voters.forEach((v) => { | ||
const res = v.title | const res = v.title | ||
.replace(/^(?:User|U|用户):/i, "") | .replace(/^(?:User|U|用户):/i, "") | ||
.replace(/\s/, "_"); | .replace(/\s/g, "_"); | ||
if (thisCollect.set.includes(res)) { | if (thisCollect.set.includes(res)) { | ||
v.remove(); | v.remove(); | ||
| 第94行: | 第114行: | ||
} | } | ||
thisCollect.set.push(res); | thisCollect.set.push(res); | ||
v.textContent = res; | // 允许自定义用户名样式 | ||
if ( | |||
!v.textContent || | |||
v.textContent.toUpperCase().trim().replace(/\s/g, "_") !== | |||
res.toUpperCase() | |||
) | |||
v.textContent = res; | |||
}); | }); | ||
collect.push(thisCollect); | collect.push(thisCollect); | ||
// 配色 | // 外观 | ||
li.style.setProperty("--vote-color", at(color, liIndex)); | li.appendChild(count); | ||
count.className = "salt-vote-option-count"; | |||
li.style.setProperty("--vote-color", at(color, liIndex)); // 配色 | |||
li.style.setProperty("--vote-count", `${thisCollect.set.length}`); | |||
// 点击展开选项描述 | |||
const desc = descCollect.find(({ name }) => name === title); | |||
if (desc) { | |||
const descEl = desc.desc; | |||
thisCollect.desc = descEl; | |||
li.classList.add("has-desc"); | |||
descEl.classList.add("salt-vote-option-hooked"); | |||
descEl.style.setProperty("--height", `${descEl.scrollHeight}px`); | |||
descEl.style.setProperty("--vote-color", at(color, liIndex)); | |||
li.addEventListener("click", () => { | |||
if (descEl.classList.contains("show")) { | |||
descEl.classList.remove("show"); | |||
} else { | |||
descEl.classList.add("show"); | |||
descEl.style.setProperty("--height", `${descEl.scrollHeight}px`); | |||
} | |||
}); | |||
li.appendChild(descEl); | |||
} | |||
}); | }); | ||
// 绘制图形 | // 绘制图形 | ||
const { barHTML } = renderPercent(collect, color, !!barEl); | |||
if (barEl) barEl.innerHTML = barHTML; | |||
}; | }; | ||
const main = () => getAllNotInitContainer().forEach((el) => process(el)); | |||
setTimeout(() => { | setTimeout(() => { | ||
main(); | |||
}, 0); | }, 0); | ||
setTimeout(() => { | |||
main(); | |||
}, 66); | |||
setInterval(() => { | setInterval(() => { | ||
main(); | |||
}, | }, 500); | ||
})(window); | })(window); | ||
</script></includeonly> | </script></includeonly> | ||
2024年3月23日 (六) 19:38的最新版本
用于展示投票箱