+
+
+
+
Connecting…
POLLS OPEN
@@ -1369,6 +1410,7 @@
budgetScenarios: [],
priceUpdatedAt: '',
priceHistoryRunCount: 0,
+ sortMode: localStorage.getItem('cabo_sort_mode') || 'vote-desc',
priceSourceSelections: (() => {
try {
return JSON.parse(localStorage.getItem('cabo_price_source_selections') || '{}');
@@ -1648,6 +1690,55 @@
render();
}
+ function setSortMode(sortMode) {
+ const allowedModes = new Set(['vote-desc', 'vote-asc', 'price-asc', 'price-desc']);
+ state.sortMode = allowedModes.has(sortMode) ? sortMode : 'vote-desc';
+ localStorage.setItem('cabo_sort_mode', state.sortMode);
+ render();
+ }
+
+ function getOptionOrderIndexMap() {
+ return new Map(state.options.map((opt, index) => [opt.id, index]));
+ }
+
+ function getSelectedOptionPrice(opt) {
+ const selectedSeries = getOptionSourceSeries(opt);
+ const selectedPoint = selectedSeries.at(-1) || opt.latestPricePoint || null;
+ return typeof selectedPoint?.price === 'number' ? selectedPoint.price : null;
+ }
+
+ function sortOptionsByMode(opts, orderIndexMap) {
+ const mode = state.sortMode || 'vote-desc';
+ const ascending = mode.endsWith('asc');
+ const isVoteSort = mode.startsWith('vote');
+ return [...opts].sort((a, b) => {
+ const aIndex = orderIndexMap.get(a.id) ?? 0;
+ const bIndex = orderIndexMap.get(b.id) ?? 0;
+
+ if (isVoteSort) {
+ const aVotes = getVoteEntries(a).length;
+ const bVotes = getVoteEntries(b).length;
+ if (aVotes !== bVotes) {
+ return ascending ? aVotes - bVotes : bVotes - aVotes;
+ }
+ } else {
+ const aPrice = getSelectedOptionPrice(a);
+ const bPrice = getSelectedOptionPrice(b);
+ const aHasPrice = typeof aPrice === 'number';
+ const bHasPrice = typeof bPrice === 'number';
+
+ if (aHasPrice && bHasPrice && aPrice !== bPrice) {
+ return ascending ? aPrice - bPrice : bPrice - aPrice;
+ }
+ if (aHasPrice !== bHasPrice) {
+ return aHasPrice ? -1 : 1;
+ }
+ }
+
+ return aIndex - bIndex;
+ });
+ }
+
function escapeHtml(value) {
return String(value ?? '')
.replace(/&/g, '&')
@@ -1995,6 +2086,10 @@
// ── Render options ────────────────────────────────────────
function render() {
const list = document.getElementById('optionsList');
+ const sortModeSelect = document.getElementById('sortModeSelect');
+ if (sortModeSelect && sortModeSelect.value !== state.sortMode) {
+ sortModeSelect.value = state.sortMode;
+ }
// ── Results tab ──────────────────────────────────────────
if (activeTab === 'results') {
@@ -2062,7 +2157,7 @@
return;
}
- const sorted = [...opts];
+ const sorted = sortOptionsByMode(opts, getOptionOrderIndexMap());
const maxVotes = sorted[0] ? getVoteEntries(sorted[0]).length : 1;
const budgetBoard = activeTab === 'budget' ? renderBudgetBoard() : '';