`);
+ 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
@@ -231,26 +236,18 @@ GM_addStyle(GM_getResourceText("DataTablesCSS"));
if ($('#sezione').length > 0) {
console.log("GAIA Swissknife: Elementi trovati, aggiungo i pulsanti nel menu laterale...");
- ensureSwissknifeHeader();
// Aggiungi i pulsanti per settare gli esiti
- const buttonsHTML = `
-
-
-
-
-
-
-
-
-
- `;
- $('#sezione').append(buttonsHTML);
+ [
+ { 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(() => {
@@ -344,9 +341,7 @@ GM_addStyle(GM_getResourceText("DataTablesCSS"));
// Inserimento del pulsante nel menu laterale o in floating
if ($('#sezione').length > 0) {
- ensureSwissknifeHeader();
-
- $('#sezione').append(
+ appendToSwissknifeSection(
$('').append(openButton)
);
} else {
@@ -585,6 +580,240 @@ GM_addStyle(GM_getResourceText("DataTablesCSS"));
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();
@@ -592,21 +821,35 @@ GM_addStyle(GM_getResourceText("DataTablesCSS"));
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
-// 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.4 - Fix:
-// - Modificata regex per il matching dei codici corso, compatibile con i codici che contengono caratteri alfanumerici
// ==/CHANGELOG==
\ No newline at end of file