Changeset 0202104 in Klonkt for src/assets/js
- Timestamp:
- 07/28/2026 11:40:37 PM (6 weeks ago)
- Branches:
- main
- Children:
- 439f095
- Parents:
- 6eab7e9
- File:
-
- 1 edited
-
src/assets/js/guardian.js (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/assets/js/guardian.js
r6eab7e9 r0202104 123 123 return card; 124 124 } 125 /** A running lapse (FEP-633c 3.6.3): the available co-guardians deciding 126 * to release a dormant one. Votes ride the same Accept/Reject wire as the 127 * offers; buttons appear only for set members (the ward watches, it does 128 * not vote). */ 129 function lapseCard(l) { 130 var card = el('div', 'g-card lapse'); 131 card.appendChild(el('div', 'who', (T.lapse_line || '{who} has stopped answering as a guardian of {ward}.') 132 .replace('{who}', handleOf(l.object.object)).replace('{ward}', handleOf(l.object['shaer:ward'])))); 133 card.appendChild(el('div', 'g-avlabel', (T.lapse_tally || '{n} of {need} agreed; closes {date}.') 134 .replace('{n}', l['shaer:accepts']).replace('{need}', l['shaer:threshold']) 135 .replace('{date}', new Date(l['shaer:closesAt']).toLocaleDateString()))); 136 var row = el('div', 'row'); 137 var inSet = (l['shaer:set'] || []).indexOf(S.me) >= 0; 138 if (inSet && !l['shaer:myVote']) { 139 var yes = el('button', 'small', T.lapse_agree || 'Agree'); 140 yes.addEventListener('click', function () { answer(l.id, 'accept', yes); }); 141 var no = el('button', 'quiet small', T.lapse_disagree || 'Disagree'); 142 no.addEventListener('click', function () { answer(l.id, 'reject', no); }); 143 row.appendChild(yes); row.appendChild(no); 144 } else if (inSet) { 145 row.appendChild(el('span', 'g-avlabel', T.voted || 'You voted')); 146 } 147 card.appendChild(row); 148 card.appendChild(el('p', 'g-empty small', T.lapse_note || '')); 149 return card; 150 } 151 125 152 function renderPending() { 126 153 var list = document.getElementById('pending-list'); 127 154 list.textContent = ''; 128 155 var offers = S.offers || []; 129 offers.forEach(function (o) { list.appendChild(offerCard(o)); }); 130 show('pending-section', offers.length > 0); 156 // The offers state carries the adoption offers; the lapse proposals ride 157 // separately so a lapse never renders as an adoption. 158 var lapses = (S.lapses || []).filter(function (l) { return l['shaer:outcome'] === 'open'; }); 159 offers.forEach(function (o) { 160 if (o.object && o.object.type === 'shaer:Lapse') return; // rendered below 161 list.appendChild(offerCard(o)); 162 }); 163 lapses.forEach(function (l) { list.appendChild(lapseCard(l)); }); 164 show('pending-section', offers.length > 0 || lapses.length > 0); 131 165 } 132 166 … … 233 267 } 234 268 269 /** The availability dot (FEP-633c 3.6): buddy-list language on the 270 * responsibility axis. Green available, yellow declared away with an end, 271 * grey observed dormant (one answer restores). */ 272 function availLabel(g) { 273 if (g.availability === 'away') { 274 var date = g.awayUntil ? new Date(g.awayUntil).toLocaleDateString() : '?'; 275 return (T.avail_away || 'Unavailable till {date}').replace('{date}', date); 276 } 277 if (g.availability === 'dormant') return T.avail_dormant || 'Offline'; 278 return T.avail_available || 'Available'; 279 } 280 function availRow(g, wardUri) { 281 var row = el('div', 'row g-guard'); 282 var dot = el('span', 'g-avdot ' + (g.availability === 'away' ? 'is-away' : g.availability === 'dormant' ? 'is-dormant' : 'is-active')); 283 row.appendChild(dot); 284 row.appendChild(el('span', 'who grow', handleOf(g.uri, g.handle))); 285 row.appendChild(el('span', 'g-avlabel', availLabel(g))); 286 // A dormant fellow guardian without a running lapse: the deliberate, 287 // rare next step (3.6.3). Never shown for anyone still answering. 288 if (g.availability === 'dormant' && !g.lapse && g.uri !== S.me) { 289 var btn = el('button', 'quiet small', T.lapse_propose || 'Propose release'); 290 btn.addEventListener('click', function () { 291 btn.disabled = true; 292 fetch('/guardian/api/lapse', { 293 method: 'POST', headers: { 'Content-Type': 'application/json' }, 294 body: JSON.stringify({ ward: wardUri, target: g.uri, site: S.site }), 295 }).then(refresh).catch(function () { btn.disabled = false; }); 296 }); 297 row.appendChild(btn); 298 } 299 return row; 300 } 301 235 302 function wardPanel(w) { 236 303 var uri = w.other_uri; … … 244 311 set.appendChild(setRow); 245 312 panel.appendChild(set); 313 314 // The fellow guardians of this child, with availability (3.6). For a 315 // ward on another server the states live there, and saying so honestly 316 // beats guessing. 317 var gsec = el('div', 'g-panel-sec'); 318 gsec.appendChild(el('h3', null, T.panel_guards || 'Guardians of this child')); 319 if (w.guardians && w.guardians.length) { 320 w.guardians.forEach(function (g) { gsec.appendChild(availRow(g, uri)); }); 321 } else { 322 gsec.appendChild(el('p', 'g-empty small', T.panel_guards_remote || '')); 323 } 324 panel.appendChild(gsec); 246 325 247 326 sectionInto(panel, T.panel_follow || 'Follow requests', … … 314 393 }); 315 394 show('wards-empty', wards.length === 0); 316 } 395 // Step away (3.6.1) only means something with wards to tell. 396 show('away-section', wards.length > 0); 397 } 398 399 // ── 4b. Step away (FEP-633c 3.6.1) ───────────────────────────────────── 400 function declareAway(days, btn) { 401 btn.disabled = true; 402 fetch('/guardian/api/away', { 403 method: 'POST', headers: { 'Content-Type': 'application/json' }, 404 body: JSON.stringify({ days: days, site: S.site }), 405 }).then(function (r) { return r.json(); }) 406 .then(function (j) { 407 btn.disabled = false; 408 var msg = document.getElementById('away-msg'); 409 msg.hidden = false; 410 if (j && j.ok) { 411 msg.className = 'g-msg'; 412 msg.textContent = (T.away_done || 'Your wards know you are unavailable until {date}.') 413 .replace('{date}', new Date(j.until).toLocaleDateString()); 414 } else { 415 msg.className = 'g-msg err'; 416 msg.textContent = (j && j.error) || (T.failed || 'failed'); 417 } 418 }) 419 .catch(function () { btn.disabled = false; }); 420 } 421 var awayWeek = document.getElementById('away-week'); 422 var awayMonth = document.getElementById('away-month'); 423 if (awayWeek) awayWeek.addEventListener('click', function () { declareAway(7, awayWeek); }); 424 if (awayMonth) awayMonth.addEventListener('click', function () { declareAway(30, awayMonth); }); 317 425 318 426 function sendWave(uri, btn) {
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)