// ==UserScript== // @name GAIA - Swissknife // @namespace https://gitlab.luigidacunto.com/consultant/gaia-swissknife // @updateURL https://luigidacunto.com/scripts/gaia-swissknife/tampermonkey-script/GAIA-Swissknife.user.js // @downloadURL https://luigidacunto.com/scripts/gaia-swissknife/tampermonkey-script/GAIA-Swissknife.user.js // @changelogURL https://luigidacunto.com/scripts/gaia-swissknife/tampermonkey-script/CHANGELOG.md // @author Luigi D'Acunto // @version 1.1.009 // @description Aggiunge funzionalità alle pagine di GAIA // @match https://gaia.cri.it/* // @require https://code.jquery.com/jquery-3.6.0.min.js // @require https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js // @resource DataTablesCSS https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css // @grant GM_addStyle // @grant GM_getResourceText // @grant GM_getValue // @grant GM_setValue // @run-at document-idle // ==/UserScript== GM_addStyle(GM_getResourceText("DataTablesCSS")); (function($) { 'use strict'; console.log("GAIA Swissknife: Inizializzazione in corso!"); // Recupera la versione dallo script se disponibile, altrimenti usa un valore di fallback const currentVersion = (typeof GM_info !== 'undefined' && GM_info.script && GM_info.script.version) ? GM_info.script.version : 'x.x'; console.log(`GAIA Swissknife: Versione ${currentVersion}`); // Inizializza le funzionalità // Funzione per aggiungere il blocco di intestazione in cima alla sidebar function ensureSwissknifeHeader() { if ($('#sezione').length === 0 || $('#gaia-swissknife-header').length > 0) return; console.log("GAIA Swissknife: Aggiungo intestazione GAIA Swissknife in cima..."); const $header = $(``); const $divider = $('
'); // Prepend: header prima, poi divider — risultato: [header][divider][voci esistenti] // I pulsanti vengono inseriti tra header e divider $('#sezione').prepend($divider).prepend($header); } // Helper: inserisce un
  • con il pulsante tra l'header Swissknife e il divider function appendToSwissknifeSection($li) { ensureSwissknifeHeader(); $('#gaia-swissknife-divider').before($li); } // Funzione per correggere i filtri della sidebar delle autorizzazioni function fixAutorizzazioniSidebarFilters() { const $ul = $("#sezione-2"); if (!$ul.length) return; const voci = {}; // Scansiona tutti i link $ul.find("li[role='presentation'] a").each(function () { const $a = $(this); const text = $a.clone().children().remove().end().text().trim(); const badge = parseInt($a.find(".badge").text().trim(), 10); const href = $a.attr("href"); if (!text || isNaN(badge)) return; if (!voci[text]) { voci[text] = { count: 0, href: href }; } voci[text].count += badge; }); $ul.find("li[role='presentation']").remove(); Object.entries(voci).forEach(([tipo, info]) => { const $li = $(`
  • ${tipo} ${info.count}
  • `); $ul.append($li); }); } // Funzione per ricostruire le celle con i dettagli delle qualifiche nel curriculum in modo pulito function rebuildCurriculumDetailCells() { $("td.piu-piccolo").each(function (cellIndex) { const $td = $(this); const rawNodes = Array.from(this.childNodes); const nodes = rawNodes.filter(n => { if (n.nodeType === 3) return n.nodeValue.trim() !== ""; return true; }); console.log(`\n📦 [Cella ${cellIndex + 1}] Analizzo ${nodes.length} nodi validi...`); const newContent = $('
    '); for (let i = 0; i < nodes.length; i++) { const node = nodes[i]; if (node.nodeType === 1 && node.tagName === "I") { const $icon = $(node).clone(); const $row = $('
    ').css({ "display": "flex", "align-items": "baseline", "gap": "5px", "line-height": "1.4", "margin-bottom": "2px" }); $icon.css({ "margin-right": "4px", "vertical-align": "middle" }); $row.append($icon); let content = null; let nextIndex = i + 1; while (nextIndex < nodes.length) { const nextNode = nodes[nextIndex]; if (nextNode.nodeType === 3) { const text = nextNode.nodeValue.trim(); if (text) { content = $('').text(text); if (text.length > 40) { content.css({ "display": "inline-block", "max-width": "200px", "white-space": "nowrap", "overflow": "hidden", "text-overflow": "ellipsis", "vertical-align": "middle" }).attr("title", text); } break; } } else if (nextNode.nodeType === 1) { const $el = $(nextNode); if (nextNode.tagName === "A") { let text = $el.text().trim(); if (!text) { const href = $el.attr("href") || ""; const fallback = href.split("/").pop(); text = fallback || "(documento)"; $el.text(text); } $el.css({ "display": "inline-block", "max-width": "200px", "white-space": "nowrap", "overflow": "hidden", "text-overflow": "ellipsis", "vertical-align": "middle", "color": "#a94442" }).attr("title", text); content = $el; break; } else if (nextNode.tagName === "SPAN") { const text = $el.text().trim(); if (text) { content = $el.clone(); content.css({ "display": "inline-block", "max-width": "200px", "white-space": "nowrap", "overflow": "hidden", "text-overflow": "ellipsis", "vertical-align": "middle" }).attr("title", text); break; } } } nextIndex++; } i = nextIndex - 1; if (content) { $row.append(content); newContent.append($row); console.log(`✅ Riga generata: ${$icon.attr("class")} + contenuto`); } else { console.warn(`⚠️ Riga ignorata: icona "${$icon.attr("class")}" senza contenuto`); } } } $td.empty().append(newContent); }); } // Funzione per applicare le correzioni di stile alle celle del curriculum function applyStyleFixes() { const url = window.location.href; // Correzione per le celle del curriculum if (url.match(/\/profilo\/\d+\/curriculum\//)) { console.log("GAIA Swissknife: Ricostruzione celle curriculum in modo ordinato..."); rebuildCurriculumDetailCells(); } // Correzione per menu laterale autorizzazioni if (url.includes("/autorizzazioni")) { console.log("GAIA Swissknife: Correzione menu laterale autorizzazioni..."); fixAutorizzazioniSidebarFilters(); } } // Funzione per aggiungere i pulsanti per settare gli esiti degli esami function addExamOutcomeButtons() { console.log("GAIA Swissknife: esecuzione di addExamOutcomeButtons() ..."); // Verifica che ci siano i select che gestiscono gli esiti if ($("select[id^='id_part_'][id$='-ammissione']").length > 0) { // Cerca il menu laterale (ul#sezione) dove inserire il blocco if ($('#sezione').length > 0) { console.log("GAIA Swissknife: Elementi trovati, aggiungo i pulsanti nel menu laterale..."); // Aggiungi i pulsanti per settare gli esiti [ { id: 'button_set_ampp', label: 'Ammessi, Positivo, Positivo', color: '#007BFF' }, { id: 'button_set_ampo', label: 'Ammessi, Positivo, Non previsto', color: '#28a745' }, { id: 'button_set_amop', label: 'Ammessi, Non previsto, Positivo', color: 'rgb(167, 40, 99)' } ].forEach(({ id, label, color }) => { appendToSwissknifeSection( $('
  • ').append( $(``) ) ); }); // Evento per il pulsante "Tutti Ammessi/Esito Positivo x2" $('#button_set_ampp').click(() => { $("select[id^='id_part_'][id$='-ammissione']").val("AM").trigger('change'); $("select[id^='id_part_'][id$='-esito_parte_1']").val("P").trigger('change'); $("select[id^='id_part_'][id$='-esito_parte_2']").val("P").trigger('change'); console.log("GAIA Swissknife: Valori impostati - Ammessi, Positivo, Positivo"); }); // Evento per il pulsante "Ammessi, Positivo, Non previsto" $('#button_set_ampo').click(() => { $("select[id^='id_part_'][id$='-ammissione']").val("AM").trigger('change'); $("select[id^='id_part_'][id$='-esito_parte_1']").val("P").trigger('change'); $("select[id^='id_part_'][id$='-esito_parte_2']").val("O").trigger('change'); console.log("GAIA Swissknife: Valori impostati - Ammessi, Positivo, Non previsto"); }); // Evento per il pulsante "Ammessi, Non previsto, Positivo" $('#button_set_amop').click(() => { $("select[id^='id_part_'][id$='-ammissione']").val("AM").trigger('change'); $("select[id^='id_part_'][id$='-esito_parte_1']").val("O").trigger('change'); $("select[id^='id_part_'][id$='-esito_parte_2']").val("P").trigger('change'); console.log("GAIA Swissknife: Valori impostati - Ammessi, Non previsto, Positivo"); }); } else { console.log("GAIA Swissknife: Elemento ul#sezione non trovato."); } } else { console.log("GAIA Swissknife: Nessun elemento trovato, i pulsanti non verranno mostrati."); } } // Funzione per aggiungere il pulsante "Apri tutti i Curriculum" sezione iscritti di un corso function addOpenAllProfilesButton() { if (!window.location.href.includes('/iscritti/')) return; const openButton = $(` `); openButton.on('click', () => { const iframe = document.querySelector('iframe.embed-responsive-item'); if (!iframe) { alert("Impossibile trovare l'iframe con la lista."); console.log("GAIA Swissknife: iframe non trovato."); return; } // Verifica che il contenuto sia accessibile (same-origin) let iframeDoc; try { iframeDoc = iframe.contentDocument || iframe.contentWindow.document; } catch (err) { alert("Accesso all'iframe bloccato per motivi di sicurezza (cross-origin)."); console.error("GAIA Swissknife: accesso iframe negato.", err); return; } const $iframeLinks = $(iframeDoc).find("a[href^='/profilo/'][href*='?fpc']"); if ($iframeLinks.length === 0) { alert("Nessun profilo trovato all'interno dell'iframe."); console.log("GAIA Swissknife: Nessun link profilo nell'iframe."); return; } const profileLinks = $iframeLinks.map(function() { const href = $(this).attr('href'); const match = href.match(/\/profilo\/(\d+)\//); if (match && match[1]) { const id = match[1]; return `https://gaia.cri.it/profilo/${id}/curriculum/?us`; } return null; }).get().filter(Boolean); // Mostra le URL in console sempre console.log("GAIA Swissknife: Profili trovati:"); profileLinks.forEach(link => console.log(link)); if (!confirm(`Vuoi aprire ${profileLinks.length} profili in nuove schede?`)) return; profileLinks.forEach(link => { window.open(link, '_blank'); }); console.log(`GAIA Swissknife: Aperte ${profileLinks.length} schede da iframe.`); }); // Inserimento del pulsante nel menu laterale o in floating if ($('#sezione').length > 0) { appendToSwissknifeSection( $('
  • ').append(openButton) ); } else { openButton.css({ position: 'fixed', top: '10px', right: '10px', zIndex: 9999 }).appendTo('body'); } } // Funzione per evidenziare le righe con "Respinto" function highlightRejectedCourses() { if (!window.location.href.match(/\/profilo\/\d+\/curriculum\//)) return; console.log("GAIA Swissknife: Avvio evidenziazione 'Respinto'…"); const $table = $(".table.table-striped"); if (!$table.length || !$.fn.DataTable.isDataTable($table)) return; const api = $table.DataTable(); function applyRejectionStyle() { // Prima puliamo tutte le righe (reset) api.rows().every(function () { const $row = $(this.node()); $row.css({ "box-shadow": "", "background-color": "" }); }); // Poi coloriamo solo le righe che contengono Respinto $table.find("span.text-danger").each(function () { const text = $(this).text().trim().toLowerCase(); if (text === "respinto") { const $row = $(this).closest("tr"); console.log("🟥 Evidenzio riga:", $row.index(), $row.find("p.grassetto").text().trim()); $row.css({ "box-shadow": "inset 8px 0 0 0 #dc3545", "background-color": "#fbe9ea" }); } }); } applyRejectionStyle(); $table.on("draw.dt", applyRejectionStyle); } // Funzione per aggiungere il tool per i profili delle richieste iscrizioni function addAuthorizationProfileTool() { if (!window.location.href.includes("/autorizzazioni/")) return; console.log("GAIA Swissknife: Attivo tool per gestione richieste iscrizione..."); const richieste = []; $(".panel.panel-default").each(function () { const $panel = $(this); const $corsoLink = $panel.find("a[href^='/aspirante/corso-base/']"); if ($corsoLink.length === 0) return; // blocco non relativo a richiesta corso const corsoText = $corsoLink.text().trim(); const match = corsoText.match(/([A-Z]{2,}\/\d{4}\/[A-Z0-9\-]+(?: [A-Z0-9\-]+)?\/\d+)/); if (!match) return; const codiceCorso = match[1]; const $profileLink = $panel.find("a[href^='/profilo/']").first(); const nome = $profileLink.text().trim(); const href = $profileLink.attr("href"); const idMatch = href.match(/\/profilo\/(\d+)\//); if (idMatch && idMatch[1]) { richieste.push({ codice: codiceCorso, nome, id: idMatch[1], linkCorso: $corsoLink.attr("href"), $panel }); } }); const corsiUnici = [...new Set(richieste.map(r => r.codice))]; if (corsiUnici.length === 0) return; // === CREAZIONE MODALE === const $modal = $(`
    🛠 GAIA Swissknife – Richieste iscrizione
    📋 Richieste trovate:
    ${corsiUnici.map(c => { const matching = richieste.filter(r => r.codice === c); const count = matching.length; const plural = count === 1 ? "richiesta" : "richieste"; const courseUrl = matching[0]?.linkCorso ? `https://gaia.cri.it${matching[0].linkCorso}` : null; const label = courseUrl ? `${c} – ${count} ${plural}` : `${c} – ${count} ${plural}`; return `• ${label}`; }).join("
    ")}
    `); $('body').append($modal); // Riduci / Espandi let isCollapsed = false; $('#gaia-auth-toggle').on('click', function (e) { isCollapsed = !isCollapsed; $('#gaia-auth-body').slideToggle(200); $(this).text(isCollapsed ? '+' : '−'); e.stopPropagation(); }); // Modal mobile let isDragging = false, dragOffsetX = 0, dragOffsetY = 0; $('#gaia-auth-header').on('mousedown', function (e) { const rect = document.getElementById('gaia-auth-tool').getBoundingClientRect(); isDragging = true; dragOffsetX = e.clientX - rect.left; dragOffsetY = e.clientY - rect.top; e.preventDefault(); }); $(document).on('mousemove', function (e) { if (!isDragging) return; const $modal = $('#gaia-auth-tool'); let left = e.clientX - dragOffsetX; let top = e.clientY - dragOffsetY; left = Math.max(0, Math.min(left, window.innerWidth - $modal.outerWidth())); top = Math.max(0, Math.min(top, window.innerHeight - $modal.outerHeight())); $modal.css({ left: left + 'px', top: top + 'px', right: 'auto' }); }).on('mouseup', () => isDragging = false); // Recupera profili $('#gaia-auth-btn').on('click', function () { const codiceSelezionato = $('#gaia-auth-select').val(); const $results = $('#gaia-auth-results').empty(); $('#gaia-auth-openall-container').hide(); if (!codiceSelezionato) { alert("Seleziona un codice corso."); return; } // Reset evidenziazione $(".panel.panel-default").css("background-color", ""); const trovati = richieste.filter(r => r.codice === codiceSelezionato); if (trovati.length === 0) { $results.append(`
    Nessun risultato trovato.
    `); return; } trovati.forEach(r => { r.$panel.css("background-color", "#d4edda"); const link = `https://gaia.cri.it/profilo/${r.id}/curriculum/?us`; $results.append(`
    ${r.nome}
    `); }); $('#gaia-auth-openall-container').show(); $('#gaia-auth-openall').off('click').on('click', function () { trovati.forEach(r => window.open(`https://gaia.cri.it/profilo/${r.id}/curriculum/?us`, '_blank')); }); }); } // Funzione per migliorare la tabella del curriculum function enhanceCurriculumTable() { if (!window.location.href.match(/\/profilo\/\d+\/curriculum\//)) return; const palette = { "Qualifica CRI": "#e6f0ff", // blu chiaro "Altra Qualifica": "#e6fff0", // verde chiaro "Esperienze Professionali": "#fff3e6", // arancione chiaro "Competenza Personale": "#e6faff", // ciano chiaro "Patente Civile": "#f0f0f0", // grigio chiaro "Patente CRI": "#f3e6ff" // lilla chiaro }; const $table = $(".table.table-striped"); const $tbody = $table.find("tbody"); if (!$table.length || !$tbody.length) return; console.log("GAIA Swissknife: DataTable + Colorazione permanente per tipologia..."); $table.DataTable({ paging: false, order: [[0, 'asc'], [1, 'asc']], columnDefs: [ { orderable: false, targets: 2 } ], language: { search: "Filtra qualifiche:", zeroRecords: "Nessuna qualifica trovata", info: "Mostrate _TOTAL_ qualifiche", infoEmpty: "Nessuna qualifica disponibile", infoFiltered: "(filtrate da _MAX_ totali)" } }); function applyColoring() { const tableApi = $table.DataTable(); tableApi.rows().every(function () { const $row = $(this.node()); const $tipoCell = $row.find("td").eq(0); const tipo = $tipoCell.text().trim(); if (palette[tipo]) { $tipoCell.css("background-color", palette[tipo]); } }); } // Applica le correzioni le colorazioni dei tipi di qualifica in lista applyColoring(); } // Funzione per la selezione rapida del comitato preferito (persistente cross-sessione) function addSediPreferitaTool() { if ($('table tbody input[name="sedi"]').length === 0) return; console.log("GAIA Swissknife: Aggiungo tool selezione sede preferita..."); // Costruisce la mappa di tutte le sedi dalla tabella function buildSediMap() { const map = []; document.querySelectorAll('table tbody tr').forEach(row => { const cb = row.querySelector('input[name="sedi"]'); const nameTd = row.querySelector('td.grassetto'); if (!cb || !nameTd) return; map.push({ value: cb.value, label: nameTd.innerText.trim(), numCells: row.querySelectorAll('td').length }); }); return map; } const sediMap = buildSediMap(); const savedValue = GM_getValue('preferred_sede_value', ''); // Select con indentazione visiva per la gerarchia const $select = $('').css({ width: '100%', padding: '4px', margin: '4px 5px 4px 5px', fontSize: '12px', boxSizing: 'border-box', width: 'calc(100% - 10px)' }); $select.append(''); sediMap.forEach(({ value, label, numCells }) => { const prefix = numCells === 4 ? '' : numCells === 5 ? '\u00a0\u00a0\u00a0' : '\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'; const $opt = $(``); if (value === savedValue) $opt.prop('selected', true); $select.append($opt); }); $select.on('change', function () { GM_setValue('preferred_sede_value', $(this).val()); }); // Pulsante: seleziona solo il preferito (+ figli se è Regionale o Locale) const $btnSolo = $(''); $btnSolo.on('click', function () { const val = $select.val(); if (!val) { alert('Seleziona prima un comitato preferito.'); return; } $('input[name="sedi"]').prop('checked', false); const idx = sediMap.findIndex(s => s.value === val); if (idx === -1) return; const selected = sediMap[idx]; $(`#c_${selected.value}`).prop('checked', true); // Se è Regionale (4) o Locale (5), seleziona anche tutti i figli if (selected.numCells <= 5) { for (let i = idx + 1; i < sediMap.length; i++) { if (sediMap[i].numCells <= selected.numCells) break; $(`#c_${sediMap[i].value}`).prop('checked', true); } } console.log(`GAIA Swissknife: Selezionato solo "${selected.label}" e figli.`); }); // Pulsante: seleziona tutto const $btnAll = $(''); $btnAll.on('click', function () { $('input[name="sedi"]').prop('checked', true); console.log('GAIA Swissknife: Tutte le sedi selezionate.'); }); appendToSwissknifeSection( $('
  • ').append($select, $btnSolo, $btnAll) ); } // Funzione per copiare il catalogo corsi in clipboard come JSON function addCopyCatalogButton() { if (!window.location.href.includes('/courses/catalog')) return; if (!$('.corso-nome').length) return; console.log("GAIA Swissknife: Aggiungo pulsante copia catalogo corsi..."); function extractCatalogo() { const main = document.querySelector('.col-md-9'); if (!main) return []; const results = []; let currentTipo = ''; for (const el of [...main.children]) { if (el.classList.contains('area-nome')) { currentTipo = el.textContent.trim(); continue; } if (el.classList.contains('area-levels') && currentTipo) { let currentObiettivo = ''; for (const child of [...el.children]) { if (child.classList.contains('area-nome')) { currentObiettivo = child.textContent.trim(); } else if (child.classList.contains('area-levels') && currentObiettivo) { let currentLivello = ''; for (const inner of [...child.children]) { if (inner.tagName === 'H4') { currentLivello = inner.textContent.trim(); } else if (inner.tagName === 'SECTION') { const corsoNome = inner.querySelector('.corso-nome'); if (!corsoNome) continue; const codice = corsoNome.querySelector('strong')?.textContent.trim() || ''; const nome = corsoNome.textContent.trim().replace(/\s*\([^)]*\)\s*$/, '').trim(); const scheda_pdf = inner.querySelector('.corso-scheda-completa a')?.href || null; results.push({ nome, codice, livello: currentLivello, tipo: currentTipo, obiettivo: currentObiettivo, scheda_pdf }); } } } } } } return results; } const $btn = $(''); $btn.on('click', function () { const catalogo = extractCatalogo(); if (!catalogo.length) { alert('Nessun corso trovato.'); return; } navigator.clipboard.writeText(JSON.stringify(catalogo, null, 2)).then(() => { console.log(`GAIA Swissknife: Catalogo copiato — ${catalogo.length} corsi.`); const orig = $(this).text(); $(this).text(`✓ Copiato! (${catalogo.length} corsi)`).css('background-color', '#28a745'); setTimeout(() => $(this).text(orig).css('background-color', '#c0504d'), 3000); }).catch(err => { console.error('GAIA Swissknife: Errore clipboard:', err); alert('Errore durante la copia in clipboard.'); }); }); if ($('#sezione').length > 0) { appendToSwissknifeSection($('
  • ').append($btn)); } } // Funzione per estrarre la gerarchia sedi e copiarla in clipboard come JSON function addCopyStructureButton() { if (!window.location.href.includes('/us/elenchi/volontari/')) return; // Il pulsante ha senso solo quando la tabella sedi è visibile (non nella vista risultati con iframe) if ($('table tbody tr').length === 0) return; console.log("GAIA Swissknife: Aggiungo pulsante copia struttura sedi..."); function extractStructure() { const rows = document.querySelectorAll('table tbody tr'); const regionali = []; let currentRegionale = null; let currentLocale = null; rows.forEach(row => { const cells = row.querySelectorAll('td'); const numCells = cells.length; // Il nome è sempre nella cella con classe "grassetto" let nome = ''; cells.forEach(td => { if (td.className.trim() === 'grassetto') { nome = td.innerText.trim(); } }); if (!nome) return; if (numCells === 4) { // Comitato Regionale currentRegionale = { nome, comitati_locali: [] }; regionali.push(currentRegionale); currentLocale = null; } else if (numCells === 5) { // Comitato Locale currentLocale = { nome, sottosedi: [] }; if (currentRegionale) { currentRegionale.comitati_locali.push(currentLocale); } } else if (numCells >= 6) { // Unità / Sottosede if (currentLocale) { currentLocale.sottosedi.push(nome); } } }); // Se c'è un solo regionale, restituisce l'oggetto direttamente (non array) return regionali.length === 1 ? regionali[0] : regionali; } const $btn = $(` `); $btn.on('click', function () { const structure = extractStructure(); const json = JSON.stringify(structure, null, 2); navigator.clipboard.writeText(json).then(() => { const locali = Array.isArray(structure) ? structure.reduce((acc, r) => acc + r.comitati_locali.length, 0) : structure.comitati_locali.length; const sottosedi = Array.isArray(structure) ? structure.reduce((acc, r) => acc + r.comitati_locali.reduce((a, l) => a + l.sottosedi.length, 0), 0) : structure.comitati_locali.reduce((a, l) => a + l.sottosedi.length, 0); console.log("GAIA Swissknife: JSON struttura sedi copiato in clipboard."); console.log(` Locali: ${locali}, Sottosedi: ${sottosedi}`); const orig = $(this).text(); $(this).text(`✓ Copiato! (${locali} locali, ${sottosedi} sottosedi)`).css('background-color', '#28a745'); setTimeout(() => $(this).text(orig).css('background-color', '#5a3d8a'), 3000); }).catch(err => { console.error("GAIA Swissknife: Errore copia clipboard:", err); alert("Errore durante la copia in clipboard."); }); }); // Inserisce in cima alla sidebar, nella sezione Swissknife if ($('#sezione').length > 0) { appendToSwissknifeSection( $('
  • ').append($btn) ); } } $(document).ready(() => { applyStyleFixes(); addExamOutcomeButtons(); addOpenAllProfilesButton(); addAuthorizationProfileTool(); enhanceCurriculumTable(); highlightRejectedCourses(); addSediPreferitaTool(); addCopyCatalogButton(); addCopyStructureButton(); console.log("GAIA Swissknife: Funzioni caricate con successo!"); }); })(jQuery.noConflict(true)); // ==CHANGELOG== // v1.1.009 - Nuove funzioni: // - Aggiunto pulsante "Copia catalogo corsi (JSON)" nella sidebar di /courses/catalog/ // - Estrae nome, codice, livello, tipo, obiettivo per ogni corso e copia il JSON in clipboard // - Aggiunto tool "Sede preferita" nelle pagine con selezione sedi: select persistente (GM_setValue/getValue), // pulsante "Solo preferito" (deseleziona tutto, seleziona il comitato scelto + figli), pulsante "Seleziona tutto" // - Pulsanti Swissknife ora posizionati in cima alla sidebar con header e separatore // v1.1.008 - Nuova funzione: // - Aggiunto pulsante "Copia struttura sedi (JSON)" nel menu laterale della pagina /us/elenchi/volontari/ // - Estrae la gerarchia Comitato Regionale > Comitato Locale > Sottosedi dalla tabella sedi // - Copia il JSON in clipboard con feedback visivo; se presente un solo Regionale restituisce l'oggetto diretto, altrimenti un array // - Visibile solo quando la tabella sedi è presente (non nella vista risultati con iframe) // v1.0.4 - Fix: // - Modificata regex per il matching dei codici corso, compatibile con i codici che contengono caratteri alfanumerici // v1.0.2 - Fix: // - Modificata regex per il matching dei codici corso, compatibile con i codici che contengono spazi // - Aggiunto link per aprire la pagina del corso nella modale dove compaiono i corsi rilevati // v1.0.0 - Versione stabile, con: // - DataTable integrata nella tabella curriculum // - Evidenziazione "Respinto" // - Correzioni grafiche file/link // - Gestione richieste iscrizioni con modale mobile // - Funzioni esiti massivi su termina corso // ==/CHANGELOG==