# EU Cookie Law JS

Libreria JavaScript standalone per gestire un banner cookie con consenso preventivo, granulare e revocabile. E pensata per siti statici o dinamici che vogliono integrare rapidamente un meccanismo di consenso lato client senza dipendenze esterne.

## Cosa fa

- mostra un banner con pulsanti `Accetta tutti`, `Rifiuta tutti` e `Personalizza`
- mantiene i cookie opzionali disattivati fino a una scelta esplicita
- consente consenso per categoria: `necessary`, `preferences`, `analytics`, `external`, `marketing`
- salva la scelta dell'utente in `localStorage` e in un cookie tecnico di consenso
- espone un pannello preferenze riapribile in qualsiasi momento
- sblocca script e iframe opzionali solo dopo il consenso della categoria richiesta
- blocca automaticamente immagini, video, audio, iframe, embed, object e altre risorse HTML esterne senza modificare il markup del sito
- espone una API globale JavaScript per aprire il pannello, leggere o resettare il consenso

## Limiti e responsabilita

La libreria aiuta a implementare i comportamenti tecnici comunemente richiesti dalla normativa europea su cookie, ePrivacy e consenso GDPR, ma non sostituisce una verifica legale. Resta responsabilita del titolare:

- classificare correttamente cookie e tecnologie simili
- bloccare davvero ogni script non necessario fino al consenso
- redigere cookie policy e privacy policy corrette
- verificare eventuali regole nazionali aggiuntive o aggiornamenti normativi

## File

- `eu-cookie-law.js`: libreria standalone da includere nel sito
- `example.html`: pagina demo completa con stato live, log eventi e contenuti bloccati
- `demo-analytics.js`: script esterno di esempio sbloccato dalla categoria analytics
- `demo-embed.html`: iframe locale di esempio sbloccato dalla categoria marketing

## Demo locale

Per provare subito la libreria apri [example.html](example.html:1) in un browser locale. La pagina mostra:

- banner e centro preferenze
- attivazione condizionale di script inline ed esterni
- iframe bloccato fino al consenso marketing
- stato del consenso ed eventi aggiornati in tempo reale

## Uso senza modificare il sito

Da questa versione la libreria puo bloccare automaticamente le risorse caricate da domini esterni al sito, anche se il markup originale contiene gia tag come:

- `<img>`
- `<iframe>`
- `<video>`
- `<audio>`
- `<source>`
- `<embed>`
- `<object>`
- `<input type="image">`
- `<track>`

Il blocco automatico usa la categoria `external` e funziona senza aggiungere attributi manuali agli elementi della pagina.

## Integrazione consigliata

Per il blocco preventivo automatico includi la libreria il prima possibile nel `head`, preferibilmente come primo script applicativo e senza `defer`.

```html
<script>
  window.EUCookieLawConfig = {
    locale: "it",
    policyUrl: "/cookie-policy"
  };
</script>
<script src="/assets/eu-cookie-law.js"></script>
```

Se carichi la libreria troppo tardi, le risorse gia richieste dal browser prima della sua esecuzione non possono essere bloccate retroattivamente.

## Integrazione minima

Inserisci un blocco di configurazione globale prima della libreria:

```html
<script>
  window.EUCookieLawConfig = {
    policyUrl: "/cookie-policy",
    locale: "it"
  };
</script>
<script src="/assets/eu-cookie-law.js"></script>
```

Se `window.EUCookieLawConfig` non esiste, la libreria usa valori predefiniti.

## Esempio completo

```html
<script>
  window.EUCookieLawConfig = {
    locale: "it",
    revision: 2,
    policyUrl: "/cookie-policy",
    cookieDurationDays: 180,
    manageButtonPosition: "bottom-right",
    externalResourceBlocking: {
      enabled: true,
      category: "external",
      allowedOrigins: ["https://cdn.example.com"],
      allowedHostnames: ["static.example.it"]
    },
    palette: {
      background: "#111827",
      accent: "#0f766e"
    },
    texts: {
      bannerTitle: "Usiamo cookie e tecnologie simili",
      bannerDescription:
        "I cookie necessari sono sempre attivi. Puoi accettare o rifiutare quelli opzionali oppure scegliere per categoria."
    },
    categories: {
      analytics: {
        label: "Statistiche",
        description: "Misurano traffico e uso del sito."
      },
      external: {
        label: "Contenuti esterni",
        description: "Abilitano risorse remote come immagini, video e iframe esterni."
      },
      marketing: {
        label: "Marketing",
        description: "Abilitano embed, remarketing e pubblicita personalizzata."
      }
    },
    callbacks: {
      onConsent: function (payload) {
        console.log("Consenso aggiornato:", payload);
      }
    }
  };
</script>
<script src="/assets/eu-cookie-law.js"></script>
```

## Blocco automatico delle risorse esterne

Per default la libreria considera interne:

- risorse in `same-origin`
- risorse `same-site` sullo stesso dominio principale
- URL `data:`, `blob:` e `about:`
- origini o host inseriti in allowlist via configurazione

Quando una risorsa HTML punta a un dominio esterno e non esiste ancora consenso per la categoria `external`, la libreria:

- salva l'URL originale in attributi `data-eucl-original-*`
- rimuove temporaneamente l'attributo di caricamento come `src`, `srcset`, `poster` o `data`
- nasconde l'elemento o mostra un placeholder, a seconda del tipo di tag
- ripristina automaticamente la risorsa dopo il consenso esplicito

### Configurazione dell'allowlist

```js
window.EUCookieLawConfig = {
  externalResourceBlocking: {
    enabled: true,
    category: "external",
    allowedOrigins: [
      "https://cdn.example.com",
      "https://images.example.com"
    ],
    allowedHostnames: [
      "static.example.it",
      "media.example.it"
    ]
  }
};
```

Usa `allowedOrigins` o `allowedHostnames` se il sito dipende da CDN, media server o sottodomini che vuoi considerare interni.

## Come bloccare script opzionali

Gli script non necessari non devono essere caricati normalmente. Devono essere marcati come bloccati usando `type="text/plain"` e la categoria richiesta.

### Script esterno analytics

```html
<script
  type="text/plain"
  data-cookie-category="analytics"
  src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX"
></script>
```

### Script inline marketing

```html
<script type="text/plain" data-cookie-category="marketing">
  console.log("Questo codice parte solo dopo il consenso marketing");
</script>
```

Quando l'utente abilita la categoria, la libreria sostituisce lo script bloccato con uno script reale.

## Come bloccare iframe opzionali

Per embed come YouTube, Vimeo, mappe o widget social, non impostare `src` direttamente. Usa `data-cookie-src`.

```html
<iframe
  width="560"
  height="315"
  data-cookie-category="marketing"
  data-cookie-src="https://www.youtube.com/embed/VIDEO_ID"
  data-cookie-placeholder="Per vedere questo video devi abilitare i cookie marketing."
  title="Video"
  allowfullscreen
></iframe>
```

Prima del consenso viene mostrato un placeholder. Dopo il consenso la libreria copia `data-cookie-src` in `src`.

## Variabili globali supportate

La configurazione avviene tramite `window.EUCookieLawConfig`.

```js
window.EUCookieLawConfig = {
  locale: "it",
  revision: 1,
  storageKey: "eu_cookie_law_consent",
  cookieName: "eu_cookie_law_consent",
  cookieDurationDays: 180,
  sameSite: "Lax",
  secure: true,
  policyUrl: "/cookie-policy",
  autoShow: true,
  showManageButton: true,
  manageButtonPosition: "bottom-left",
  hideAfterConsent: false,
  reloadPageOnConsentWithdraw: true,
  externalResourceBlocking: {
    enabled: true,
    category: "external",
    showPlaceholders: true,
    placeholderTags: ["img", "iframe", "video", "audio", "embed", "object"],
    allowedOrigins: [],
    allowedHostnames: [],
    allowedProtocols: ["data:", "blob:", "about:"],
    allowSameOrigin: true,
    allowSameSite: true,
    ignoreSelectors: [],
    categoryByTagName: {
      img: "external",
      iframe: "external",
      video: "external",
      audio: "external",
      source: "external",
      embed: "external",
      object: "external",
      input: "external",
      track: "external"
    }
  },
  palette: {
    background: "#101418",
    surface: "#ffffff",
    text: "#0f1720",
    inverseText: "#f7fafc",
    accent: "#0f766e",
    accentText: "#ffffff",
    border: "#d0d7de",
    muted: "#5b6672"
  },
  texts: {
    bannerTitle: "Questo sito utilizza cookie"
  },
  categories: {
    necessary: {
      enabled: true,
      required: true,
      label: "Necessari",
      description: "Cookie tecnici essenziali.",
      order: 0
    },
    preferences: {
      enabled: false,
      required: false,
      label: "Preferenze",
      description: "Lingua e impostazioni.",
      order: 10
    },
    analytics: {
      enabled: false,
      required: false,
      label: "Statistiche",
      description: "Misurazione traffico.",
      order: 20
    },
    external: {
      enabled: false,
      required: false,
      label: "Contenuti esterni",
      description: "Risorse caricate da domini esterni.",
      order: 25
    },
    marketing: {
      enabled: false,
      required: false,
      label: "Marketing",
      description: "Pubblicita e embed esterni.",
      order: 30
    }
  },
  callbacks: {
    onReady: function (ctx) {},
    onConsent: function (payload) {}
  }
};
```

## Valori predefiniti

Se una chiave manca, la libreria usa questi default:

- `locale`: rilevata da `<html lang="">`, con fallback `en`
- `revision`: `1`
- `storageKey`: `eu_cookie_law_consent`
- `cookieName`: `eu_cookie_law_consent`
- `cookieDurationDays`: `180`
- `sameSite`: `Lax`
- `secure`: `true` su HTTPS, `false` su HTTP
- `autoShow`: `true`
- `showManageButton`: `true`
- `manageButtonPosition`: `bottom-left`
- `hideAfterConsent`: `false`
- `reloadPageOnConsentWithdraw`: `true`
- `externalResourceBlocking.enabled`: `true`
- categoria `external` inizialmente disattivata
- categorie opzionali inizialmente disattivate

## API JavaScript disponibile

La libreria espone `window.EUCookieLaw`.

```js
window.EUCookieLaw.openPreferences();
window.EUCookieLaw.closePreferences();
window.EUCookieLaw.acceptAll();
window.EUCookieLaw.rejectAll();
window.EUCookieLaw.resetConsent();
window.EUCookieLaw.hasConsent("analytics");
window.EUCookieLaw.getConsent();
window.EUCookieLaw.scan();
window.EUCookieLaw.runIfConsented("analytics", function (consent) {
  console.log(consent);
});
```

## Eventi browser

La libreria emette questi eventi `CustomEvent` su `window`:

- `eu-cookie-law:ready`
- `eu-cookie-law:consent-changed`
- `eu-cookie-law:consent-reset`

Esempio:

```js
window.addEventListener("eu-cookie-law:consent-changed", function (event) {
  console.log(event.detail.categories);
});
```

## Versionamento del consenso

Se cambi testo, categorie o base giuridica del banner, incrementa `revision`. Alla revisione successiva il consenso precedente viene ignorato e il banner viene mostrato di nuovo.

## Note operative importanti

- Includi la libreria il prima possibile nella pagina, idealmente nel `head` senza `defer` se vuoi il blocco automatico preventivo.
- Non inserire script di analytics o marketing in modo normale se vuoi che vengano bloccati.
- Se il sito dipende da CDN o sottodomini essenziali, inseriscili in `externalResourceBlocking.allowedOrigins` o `allowedHostnames`.
- La libreria non puo fermare script gia eseguiti prima del suo caricamento.
- La libreria non intercetta CSS `background-image`, chiamate `fetch`, `XMLHttpRequest` o WebSocket: il blocco automatico riguarda le principali risorse HTML caricate tramite attributi del DOM.
- Se l'utente revoca una categoria prima accettata, per default la pagina viene ricaricata per riallineare i contenuti opzionali allo stato di consenso.
- Se usi tag manager o script server side, devi coordinarli con lo stato del consenso.

## Riferimenti normativi e di prassi

Per il disegno tecnico di questa libreria sono stati considerati questi principi operativi:

- consenso preventivo per cookie non necessari
- possibilita di rifiutare con la stessa facilita dell'accettazione
- consenso specifico e granulare
- possibilita di revoca e modifica successiva

Fonti utili:

- Direttiva ePrivacy, art. 5(3): https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:02002L0058-20091219
- EDPB Guidelines 05/2020 on consent: https://www.edpb.europa.eu/our-work-tools/our-documents/guidelines/guidelines-052020-consent-under-regulation-2016679_en
- European Commission web guide on cookies: https://commission.europa.eu/cookies_en
- CNIL cookie guidance: https://www.cnil.fr/en/cookies-and-other-tracking-devices-cnil-publishes-new-guidelines-and-recommendation
