gaia-swissknife/tampermonkey-script/GAIA-Swissknife.user.js

612 lines
No EOL
27 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ==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.005
// @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
// @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
function ensureSwissknifeHeader() {
console.log("GAIA Swissknife: Aggiungo intestazione GAIA Swissknife...");
if ($('#sezione').length > 0 && $('#gaia-swissknife-header').length === 0) {
const headerHTML = `
<hr>
<li id="gaia-swissknife-header" class="dropdown-header grassetto piu-grande">
GAIA Swissknife v${currentVersion}
</li>
`;
$('#sezione').append(headerHTML);
}
}
// 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 = $(`
<li role="presentation">
<a href="${info.href}">
${tipo}
<span class="badge pull-right">${info.count}</span>
</a>
</li>
`);
$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 = $('<div></div>');
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 = $('<div class="gaia-line"></div>').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 = $('<span></span>').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...");
ensureSwissknifeHeader();
// Aggiungi i pulsanti per settare gli esiti
const buttonsHTML = `
<li role="presentation">
<button id="button_set_ampp" style="margin: 5px; padding: 8px; width: 97%; background-color: #007BFF; color: #FFF; border: none; border-radius: 4px; cursor: pointer;">
Ammessi, Positivo, Positivo
</button>
</li>
<li role="presentation">
<button id="button_set_ampo" style="margin: 5px; padding: 8px; width: 97%; background-color: #28a745; color: #FFF; border: none; border-radius: 4px; cursor: pointer;">
Ammessi, Positivo, Non previsto
</button>
</li>
<li role="presentation">
<button id="button_set_amop" style="margin: 5px; padding: 8px; width: 97%; background-color:rgb(167, 40, 99); color: #FFF; border: none; border-radius: 4px; cursor: pointer;">
Ammessi, Non previsto, Positivo
</button>
</li>
`;
$('#sezione').append(buttonsHTML);
// 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 = $(`
<button id="open_all_profiles" style="margin: 5px; padding: 8px; width: 97%; background-color:rgba(234, 0, 255, 0.65); color: #FFF; border: none; border-radius: 4px; cursor: pointer;">
Apri tutti i Curriculum
</button>
`);
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) {
ensureSwissknifeHeader();
$('#sezione').append(
$('<li role="presentation"></li>').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 <span class="text-danger">Respinto</span>
$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{4,})/);
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 = $(`
<div id="gaia-auth-tool" style="position: fixed; top: 20px; right: 20px; width: 320px; background: white; border: 2px solid #007BFF; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.2); z-index: 9999; overflow: hidden;">
<div id="gaia-auth-header" style="background-color: #007BFF; color: white; padding: 8px 10px; font-weight: bold; cursor: move; display: flex; justify-content: space-between; align-items: center;">
<span>🛠 GAIA Swissknife Richieste iscrizione</span>
<button id="gaia-auth-toggle" title="Riduci/Espandi" style="background: transparent; border: none; color: white; font-weight: bold; font-size: 16px; cursor: pointer; padding: 0; margin-left: 10px;"></button>
</div>
<div id="gaia-auth-body" style="padding: 15px;">
<div id="gaia-auth-summary" style="margin-bottom: 10px; font-size: 13px;">
<strong>📋 Richieste trovate:</strong><br>
${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
? `<a href="${courseUrl}" target="_blank">${c}</a> ${count} ${plural}`
: `${c} ${count} ${plural}`;
return `${label}`;
}).join("<br>")}
</div>
<label for="gaia-auth-select">Seleziona un corso:</label>
<select id="gaia-auth-select" style="width: 100%; padding: 5px; margin-bottom: 10px;">
<option value="">-- Seleziona --</option>
${corsiUnici.map(c => `<option value="${c}">${c}</option>`).join("")}
</select>
<button id="gaia-auth-btn" style="width: 100%; padding: 8px; background-color: #007BFF; color: white; border: none; border-radius: 4px; cursor: pointer;">Recupera Profili</button>
<div id="gaia-auth-openall-container" style="display: none; margin-top: 10px;">
<button id="gaia-auth-openall" style="width: 100%; padding: 6px; background-color: #28a745; color: white; border: none; border-radius: 4px; cursor: pointer;">Apri tutti i Curriculum</button>
</div>
<div id="gaia-auth-results" style="margin-top: 10px; max-height: 200px; overflow-y: auto; border-top: 1px solid #ddd; padding-top: 10px;"></div>
</div>
</div>
`);
$('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(`<div style="color: red;">Nessun risultato trovato.</div>`);
return;
}
trovati.forEach(r => {
r.$panel.css("background-color", "#d4edda");
const link = `https://gaia.cri.it/profilo/${r.id}/curriculum/?us`;
$results.append(`<div><a href="${link}" target="_blank">${r.nome}</a></div>`);
});
$('#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();
}
$(document).ready(() => {
applyStyleFixes();
addExamOutcomeButtons();
addOpenAllProfilesButton();
addAuthorizationProfileTool();
enhanceCurriculumTable();
highlightRejectedCourses();
console.log("GAIA Swissknife: Funzioni caricate con successo!");
});
})(jQuery.noConflict(true));
// ==CHANGELOG==
// 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==