1/** 2 * Hides/favourite/notify controls on sources_list.php (heavily disk-cached page, 3 * so personalization is hydrated client-side against ngnm_reader_api.php, 4 * same pattern as ngnm-reader-home.js). 5 */ 6(function () { 7 'use strict'; 8 9 var cfg = window.NgnmReaderSourcesList || {}; 10 var apiBase = cfg.apiBase || ''; 11 var portalUrl = cfg.portalUrl || ''; 12 var dashboardUrl = cfg.dashboardUrl || ''; 13 if (!apiBase) { 14 return; 15 } 16 17 var disabled = {}; 18 var favoriteAuthors = {}; 19 var notifyAuthors = {}; 20 var loggedIn = false; 21 var pushEnabled = false; 22 var requestProof = ''; 23 24 function setPressed(btn, on, iconOnColor) { 25 btn.setAttribute('aria-pressed', on ? 'true' : 'false'); 26 var icon = btn.querySelector('i'); 27 if (icon) { 28 icon.style.color = on ? iconOnColor : 'rgb(151,151,151)'; 29 } 30 } 31 32 function refreshRow(row) { 33 var aid = row.getAttribute('data-author-id'); 34 if (!aid) return; 35 var hideBtn = row.querySelector('.ngnm-src-hide'); 36 var favBtn = row.querySelector('.ngnm-src-fav'); 37 var notifyBtn = row.querySelector('.ngnm-src-notify'); 38 if (hideBtn) setPressed(hideBtn, !!disabled[aid], '#f87171'); 39 if (favBtn) setPressed(favBtn, !!favoriteAuthors[aid], '#facc15'); 40 if (notifyBtn) setPressed(notifyBtn, !!notifyAuthors[aid], '#ff8a80'); 41 } 42 43 function post(action, authorId) { 44 return fetch(apiBase + '?action=' + action, { 45 method: 'POST', 46 credentials: 'same-origin', 47 headers: { 'Content-Type': 'application/json', 'X-NGNM-Reader-Proof': requestProof }, 48 body: JSON.stringify({ author_id: parseInt(authorId, 10) }) 49 }).then(function (r) { return r.json(); }); 50 } 51 52 function onClick(e) { 53 var btn = e.target.closest ? e.target.closest('.ngnm-src-btn') : null; 54 if (!btn) return; 55 e.preventDefault(); 56 var row = btn.closest('[data-ngnm-reader-source-row]'); 57 if (!row) return; 58 var aid = row.getAttribute('data-author-id'); 59 if (!aid) return; 60 61 if (!loggedIn) { 62 if (portalUrl) { 63 window.location.href = portalUrl + '?mode=register'; 64 } 65 return; 66 } 67 68 var action = btn.getAttribute('data-action'); 69 if (action === 'hide') { 70 post('hide_author', aid).then(function (data) { 71 if (!data || !data.ok) return; 72 disabled = {}; 73 (data.disabled_author_ids || []).forEach(function (id) { disabled[String(id)] = true; }); 74 refreshRow(row); 75 }); 76 } else if (action === 'favorite') { 77 post('favorite_author_toggle', aid).then(function (data) { 78 if (!data || !data.ok) return; 79 favoriteAuthors = {}; 80 (data.favorite_author_ids || []).forEach(function (id) { favoriteAuthors[String(id)] = true; }); 81 refreshRow(row); 82 }); 83 } else if (action === 'notify') { 84 post('notify_author_toggle', aid).then(function (data) { 85 if (!data || !data.ok) return; 86 notifyAuthors = {}; 87 (data.notify_author_ids || []).forEach(function (id) { notifyAuthors[String(id)] = true; }); 88 refreshRow(row); 89 if (data.notify && !pushEnabled && row.getAttribute('data-notify-browser') === '1' && dashboardUrl) { 90 window.location.href = dashboardUrl + '#ngnm-reader-push'; 91 } 92 }); 93 } 94 } 95 96 function boot() { 97 document.addEventListener('click', onClick); 98 fetch(apiBase + '?action=me', { credentials: 'same-origin' }) 99 .then(function (r) { return r.json(); }) 100 .then(function (data) { 101 if (!data) return; 102 loggedIn = !!data.logged_in; 103 pushEnabled = !!data.push_enabled; 104 requestProof = data.request_proof || '';
105 (data.disabled_author_ids || []).forEach(function (id) { disabled[String(id)] = true; }); 106 (data.favorite_author_ids || []).forEach(function (id) { favoriteAuthors[String(id)] = true; }); 107 (data.notify_author_ids || []).forEach(function (id) { notifyAuthors[String(id)] = true; }); 108 var rows = document.querySelectorAll('[data-ngnm-reader-source-row]'); 109 for (var i = 0; i < rows.length; i++) { 110 refreshRow(rows[i]); 111 } 112 }) 113 .catch(function () {}); 114 } 115 116 if (document.readyState === 'loading') { 117 document.addEventListener('DOMContentLoaded', boot); 118 } else { 119 boot(); 120 } 121})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.