https://www.ispazio.net/wp-content/themes/ispazio-theme/assets/js/load-more.js?x58667&ver=1790235968
1/** 2 * iSpazio â Shared "Carica altri" loader for home sections. 3 * 4 * Hooks any element with [data-isp-section] that contains: 5 * - a target wrapper [data-load-more-target] (where new cards are appended) 6 * - a button [data-isp-load-more] 7 * - a list of currently-rendered IDs in [data-current-ids="1,2,3,..."] 8 * 9 * Fetches /wp-json/ispazio/v1/section/{key}/load-more with the exclude list, 10 * receives { html, post_ids, has_more }, appends html and updates state. 11 * 12 * Note: html comes from a same-origin endpoint that renders cards through theme 13 * partials with esc_html/esc_attr â same trust model as the existing article-grid. 14 */ 15(function () { 16 'use strict'; 17 18 var REST_BASE = (window.ISP_LOAD_MORE && window.ISP_LOAD_MORE.rest) 19 || '/wp-json/ispazio/v1'; 20 21 // Carica featured-video.js al volo se contenuto appena inserito contiene un 22 // featured video e il controller non è ancora presente. Idempotente. 23 function ensureFeaturedVideo(scope) { 24 if (window.__ispFvLoaded) return; // già caricato/presente 25 if (!scope || !scope.querySelector || !scope.querySelector('[data-isp-fvideo]')) return; 26 var src = window.ISP_LOAD_MORE && window.ISP_LOAD_MORE.fvideoSrc; 27 if (!src) return; 28 window.__ispFvLoaded = true; // evita iniezioni multiple 29 var s = document.createElement('script'); 30 s.src = src; s.defer = true; 31 document.head.appendChild(s); 32 } 33 34 function init(section) { 35 if (section._ispLm) return; 36 section._ispLm = true; 37 38 var key = section.getAttribute('data-isp-section'); 39 var tax = section.getAttribute('data-isp-section-tax'); 40 var slug = section.getAttribute('data-isp-section-slug'); 41 var batch = parseInt(section.getAttribute('data-isp-section-batch') || '0', 10); 42 // Filtri liberi (categorie, tag, ID) â /custom/load-more. Il valore è una 43 // query string già pronta, generata da ispazio_load_more_attrs(). 44 var custom = section.getAttribute('data-isp-lm-custom'); 45 46 var target = section.querySelector('[data-load-more-target]'); 47 if (!target && section.hasAttribute('data-load-more-target')) target = section; 48 var btn = section.querySelector('[data-isp-load-more]'); 49 if (!target || !btn) return; 50 if (!key && !(tax && slug) && custom === null) return; 51 52 var endpoint = key 53 ? '/section/' + encodeURIComponent(key) + '/load-more' 54 : (tax && slug) 55 ? '/' + encodeURIComponent(tax) + '/' + encodeURIComponent(slug) + '/load-more'
56 : '/custom/load-more'; 57 58 var labelLabel = btn.querySelector('[data-isp-load-more-label]') || btn; 59 var labelDefault = labelLabel.dataset.label || labelLabel.textContent.trim(); 60 var labelLoading = labelLabel.dataset.loadingLabel || 'Caricamentoâ¦'; 61 62 function getCurrentIds() { 63 var raw = section.getAttribute('data-current-ids') || ''; 64 return raw.split(',').map(function (s) { return parseInt(s, 10); }).filter(function (n) { return n > 0; }); 65 } 66 function setCurrentIds(ids) { 67 section.setAttribute('data-current-ids', ids.join(',')); 68 } 69 70 /* 71 * La regione che annuncia l'esito. 72 * 73 * Chi naviga da tastiera o con uno screen reader premeva «carica altro» 74 * e non riceveva niente: arrivavano sei articoli in fondo alla pagina, 75 * fuori dal punto in cui si trovava, e nessuno glielo diceva. Una riga 76 * annunciata costa un nodo vuoto e chiude il buco. 77 * 78 * `polite`: si aspetta una pausa nella lettura invece di interrompere. 79 */ 80 var live = document.createElement('span'); 81 live.className = 'sr-only'; 82 live.setAttribute('role', 'status'); 83 live.setAttribute('aria-live', 'polite'); 84 section.appendChild(live); 85 86 /* 87 * Dove va il focus dopo il caricamento. 88 * 89 * Non sul primo articolo nuovo â sarebbe un salto, e la pagina si 90 * muoverebbe sotto gli occhi di chi ci vede benissimo. Sul contenitore 91 * dei nuovi, reso raggiungibile solo da codice (`tabindex="-1"`), cosi' 92 * il prossimo Tab riparte da li' invece che dall'inizio del documento. 93 */ 94 function focusFirstNew(firstNew) { 95 if (!firstNew) return; 96 if (!firstNew.hasAttribute('tabindex')) firstNew.setAttribute('tabindex', '-1'); 97 try { firstNew.focus({ preventScroll: true }); } catch (e) { firstNew.focus(); } 98 } 99 100 var loading = false; 101 btn.addEventListener('click', function () { 102 if (loading) return; 103 loading = true; 104 btn.disabled = true; 105 labelLabel.dataset.label = labelDefault; 106 labelLabel.textContent = labelLoading; 107 108 var ids = getCurrentIds(); 109 var url = REST_BASE + endpoint 110 + '?exclude=' + encodeURIComponent(ids.join(',')); 111 if (batch > 0) url += '&count=' + batch; 112 if (custom && !key && !(tax && slug)) url += '&' + custom; 113 var partial = section.getAttribute('data-isp-lm-partial'); 114 if (partial) url += '&partial=' + encodeURIComponent(partial); 115 116 fetch(url, { credentials: 'same-origin' }) 117 .then(function (r) { return r.ok ? r.json() : Promise.reject(r.status); }) 118 .then(function (data) { 119 if (data && data.html) { 120 var tmp = document.createElement('div'); 121 // Same-origin trusted output rendered by theme partials. 122 tmp.innerHTML = data.html; 123 var frag = document.createDocumentFragment(); 124 var added = []; 125 while (tmp.firstChild) { 126 if (tmp.firstChild.nodeType === 1) added.push(tmp.firstChild); 127 frag.appendChild(tmp.firstChild); 128 } 129 target.appendChild(frag); 130 131 // Prima il focus, poi l'annuncio: chi legge con lo 132 // screen reader sente «sei articoli aggiunti» e si trova 133 // gia' nel punto giusto per continuare col Tab. 134 focusFirstNew(added[0]); 135 live.textContent = added.length === 1 136 ? '1 articolo aggiunto' 137 : added.length + ' articoli aggiunti'; 138 139 // Se le nuove card contengono un featured video ma il 140 // controller non è ancora caricato (la prima infornata non 141 // aveva video â enqueue condizionale l'aveva saltato), lo 142 // carichiamo al volo: al boot farà scan(document) e prenderà 143 // anche queste card. 144 ensureFeaturedVideo(target); 145 146 // Primitiva generica: notifica che è stato aggiunto contenuto 147 // dinamico. featured-video.js (ed eventuali futuri lazy-feature) 148 // ascoltano e ri-scansionano solo i nuovi nodi (idempotente). 149 document.dispatchEvent(new CustomEvent('ispazio:content-added', { 150 detail: { container: target } 151 })); 152 153 if (Array.isArray(data.post_ids) && data.post_ids.length) { 154 setCurrentIds(ids.concat(data.post_ids.map(function (n) { return parseInt(n, 10); }))); 155 } 156 if (window._ispSyncBookmarks) window._ispSyncBookmarks(); 157 } 158 if (!data || data.has_more === false) { 159 btn.style.display = 'none'; 160 // Il pulsante sparisce: senza una parola, chi non lo 161 // vede sparire non sa che l'elenco e' finito. 162 live.textContent = (live.textContent ? live.textContent + '. ' : '') + 'N
162on ci sono altri articoli.'; 163 } 164 }) 165 .catch(function () { 166 // Il pulsante resta visibile per riprovare, ma il perche' 167 // va detto: prima, un clic che falliva non produceva nulla. 168 live.textContent = 'Non è stato possibile caricare altri articoli. Riprova.'; 169 }) 170 .then(function () { 171 loading = false; 172 btn.disabled = false; 173 labelLabel.textContent = labelDefault; 174 }); 175 }); 176 } 177 178 function bootstrap() { 179 document.querySelectorAll('[data-isp-section][data-current-ids],[data-isp-section-tax][data-current-ids],[data-isp-lm-custom][data-current-ids]').forEach(init); 180 } 181 182 if (document.readyState === 'loading') { 183 document.addEventListener('DOMContentLoaded', bootstrap); 184 } else { 185 bootstrap(); 186 } 187})();
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.