@ecomconsult/consentkit 0.5.13 → 0.5.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +203 -9
- package/npm/index.d.ts +35 -1
- package/npm/internal-stub.mjs +1 -1
- package/package.json +1 -1
- package/src/ck-core.js +24 -1
- package/src/ck-debug.js +74 -6
- package/src/ck-locales.js +36 -1
- package/src/ck-saas.js +154 -6
- package/src/ck-ui.js +554 -6
package/src/ck-locales.js
CHANGED
|
@@ -8,7 +8,11 @@
|
|
|
8
8
|
+ uk tr no nb is sr ca sq mk
|
|
9
9
|
|
|
10
10
|
Key set mirrors the builtin en dictionary of ck-ui.js exactly:
|
|
11
|
-
19 flat strings + cat.{necessary,functional,analytics,marketing}.{title,desc}
|
|
11
|
+
19 flat strings + cat.{necessary,functional,analytics,marketing}.{title,desc},
|
|
12
|
+
plus `extraTitle` (SPEC V1.16 §1.2 — the heading of the «Дополнительно» card
|
|
13
|
+
in the settings panel). Its BODY, `extraText`, is deliberately not here: the
|
|
14
|
+
block renders only from what the site itself supplies, so a translated body
|
|
15
|
+
would put an empty operator card on every site that never configured one.
|
|
12
16
|
|
|
13
17
|
NOTE: these translations are drafts produced for the prototype. They MUST be reviewed
|
|
14
18
|
by native speakers before production use — legal wording (refusal, "always on") is the
|
|
@@ -40,6 +44,7 @@
|
|
|
40
44
|
colPurpose: 'Цел',
|
|
41
45
|
colExpiry: 'Изтича',
|
|
42
46
|
floating: 'Настройки на бисквитките',
|
|
47
|
+
extraTitle: 'Допълнителна информация',
|
|
43
48
|
cat: {
|
|
44
49
|
necessary: { title: 'Необходими', desc: 'Нужни са, за да работи сайтът — вход, сигурност, запомняне на съгласието ви. Не могат да се изключат.' },
|
|
45
50
|
functional: { title: 'Функционални', desc: 'Запомнят предпочитанията ви, например език или чат, за да не ги задавате отново.' },
|
|
@@ -68,6 +73,7 @@
|
|
|
68
73
|
colPurpose: 'Účel',
|
|
69
74
|
colExpiry: 'Platnost',
|
|
70
75
|
floating: 'Nastavení cookies',
|
|
76
|
+
extraTitle: 'Doplňující informace',
|
|
71
77
|
cat: {
|
|
72
78
|
necessary: { title: 'Nezbytné', desc: 'Bez nich web nefunguje — přihlášení, bezpečnost, uložení vašeho souhlasu. Nelze je vypnout.' },
|
|
73
79
|
functional: { title: 'Funkční', desc: 'Pamatují si vaše předvolby, třeba jazyk nebo chat, abyste je nenastavovali znovu.' },
|
|
@@ -96,6 +102,7 @@
|
|
|
96
102
|
colPurpose: 'Formål',
|
|
97
103
|
colExpiry: 'Udløber',
|
|
98
104
|
floating: 'Cookieindstillinger',
|
|
105
|
+
extraTitle: 'Yderligere oplysninger',
|
|
99
106
|
cat: {
|
|
100
107
|
necessary: { title: 'Nødvendige', desc: 'Nødvendige for at siden virker — login, sikkerhed, hukommelse om dit samtykke. De kan ikke slås fra.' },
|
|
101
108
|
functional: { title: 'Funktionelle', desc: 'Husker dine indstillinger, fx sprog eller chat, så du ikke skal vælge dem igen.' },
|
|
@@ -124,6 +131,7 @@
|
|
|
124
131
|
colPurpose: 'Zweck',
|
|
125
132
|
colExpiry: 'Laufzeit',
|
|
126
133
|
floating: 'Cookie-Einstellungen',
|
|
134
|
+
extraTitle: 'Weitere Informationen',
|
|
127
135
|
cat: {
|
|
128
136
|
necessary: { title: 'Notwendig', desc: 'Nötig, damit die Website funktioniert — Anmeldung, Sicherheit, Speichern Ihrer Einwilligung. Sie lassen sich nicht abschalten.' },
|
|
129
137
|
functional: { title: 'Funktional', desc: 'Merken sich Ihre Einstellungen, etwa Sprache oder Chat, damit Sie sie nicht erneut wählen müssen.' },
|
|
@@ -152,6 +160,7 @@
|
|
|
152
160
|
colPurpose: 'Σκοπός',
|
|
153
161
|
colExpiry: 'Λήξη',
|
|
154
162
|
floating: 'Ρυθμίσεις cookies',
|
|
163
|
+
extraTitle: 'Πρόσθετες πληροφορίες',
|
|
155
164
|
cat: {
|
|
156
165
|
necessary: { title: 'Απαραίτητα', desc: 'Χρειάζονται για να λειτουργεί ο ιστότοπος — σύνδεση, ασφάλεια, διατήρηση της επιλογής σας. Δεν απενεργοποιούνται.' },
|
|
157
166
|
functional: { title: 'Λειτουργικά', desc: 'Θυμούνται τις προτιμήσεις σας, όπως γλώσσα ή συνομιλία, ώστε να μην τις ορίζετε ξανά.' },
|
|
@@ -180,6 +189,7 @@
|
|
|
180
189
|
colPurpose: 'Finalidad',
|
|
181
190
|
colExpiry: 'Caduca',
|
|
182
191
|
floating: 'Configuración de cookies',
|
|
192
|
+
extraTitle: 'Información adicional',
|
|
183
193
|
cat: {
|
|
184
194
|
necessary: { title: 'Necesarias', desc: 'Imprescindibles para que el sitio funcione: inicio de sesión, seguridad y memoria de su consentimiento. No se pueden desactivar.' },
|
|
185
195
|
functional: { title: 'Funcionales', desc: 'Recuerdan sus preferencias, como el idioma o el chat, para que no tenga que configurarlas de nuevo.' },
|
|
@@ -208,6 +218,7 @@
|
|
|
208
218
|
colPurpose: 'Eesmärk',
|
|
209
219
|
colExpiry: 'Kehtivus',
|
|
210
220
|
floating: 'Küpsiste seaded',
|
|
221
|
+
extraTitle: 'Lisateave',
|
|
211
222
|
cat: {
|
|
212
223
|
necessary: { title: 'Vajalikud', desc: 'Vajalikud saidi tööks — sisselogimine, turvalisus, teie nõusoleku meelespidamine. Neid ei saa välja lülitada.' },
|
|
213
224
|
functional: { title: 'Funktsionaalsed', desc: 'Jätavad meelde teie eelistused, näiteks keele või vestluse, et te ei peaks neid uuesti valima.' },
|
|
@@ -236,6 +247,7 @@
|
|
|
236
247
|
colPurpose: 'Tarkoitus',
|
|
237
248
|
colExpiry: 'Voimassaolo',
|
|
238
249
|
floating: 'Evästeasetukset',
|
|
250
|
+
extraTitle: 'Lisätiedot',
|
|
239
251
|
cat: {
|
|
240
252
|
necessary: { title: 'Välttämättömät', desc: 'Tarvitaan sivuston toimintaan: kirjautuminen, turvallisuus ja suostumuksenne muistaminen. Näitä ei voi poistaa käytöstä.' },
|
|
241
253
|
functional: { title: 'Toiminnalliset', desc: 'Muistavat asetuksenne, kuten kielen tai chatin, jottei niitä tarvitse valita uudelleen.' },
|
|
@@ -264,6 +276,7 @@
|
|
|
264
276
|
colPurpose: 'Finalité',
|
|
265
277
|
colExpiry: 'Expiration',
|
|
266
278
|
floating: 'Paramètres des cookies',
|
|
279
|
+
extraTitle: 'Informations complémentaires',
|
|
267
280
|
cat: {
|
|
268
281
|
necessary: { title: 'Nécessaires', desc: 'Indispensables au fonctionnement du site : connexion, sécurité, mémorisation de votre choix. Ils ne peuvent pas être désactivés.' },
|
|
269
282
|
functional: { title: 'Fonctionnels', desc: 'Retiennent vos préférences, par exemple la langue ou le chat, pour ne pas avoir à les régler de nouveau.' },
|
|
@@ -292,6 +305,7 @@
|
|
|
292
305
|
colPurpose: 'Cuspóir',
|
|
293
306
|
colExpiry: 'Éagann',
|
|
294
307
|
floating: 'Socruithe fianán',
|
|
308
|
+
extraTitle: 'Eolas breise',
|
|
295
309
|
cat: {
|
|
296
310
|
necessary: { title: 'Riachtanach', desc: 'Ag teastáil chun an suíomh a oibriú — logáil isteach, slándáil, do thoiliú a choinneáil. Ní féidir iad a mhúchadh.' },
|
|
297
311
|
functional: { title: 'Feidhmiúil', desc: 'Coinníonn siad do roghanna, mar shampla an teanga nó an comhrá, ionas nach gá duit iad a shocrú arís.' },
|
|
@@ -320,6 +334,7 @@
|
|
|
320
334
|
colPurpose: 'Svrha',
|
|
321
335
|
colExpiry: 'Istječe',
|
|
322
336
|
floating: 'Postavke kolačića',
|
|
337
|
+
extraTitle: 'Dodatne informacije',
|
|
323
338
|
cat: {
|
|
324
339
|
necessary: { title: 'Nužni', desc: 'Potrebni su za rad stranice — prijava, sigurnost, pamćenje vaše privole. Ne mogu se isključiti.' },
|
|
325
340
|
functional: { title: 'Funkcionalni', desc: 'Pamte vaše postavke, primjerice jezik ili chat, da ih ne morate ponovno birati.' },
|
|
@@ -348,6 +363,7 @@
|
|
|
348
363
|
colPurpose: 'Cél',
|
|
349
364
|
colExpiry: 'Lejárat',
|
|
350
365
|
floating: 'Sütibeállítások',
|
|
366
|
+
extraTitle: 'További információk',
|
|
351
367
|
cat: {
|
|
352
368
|
necessary: { title: 'Szükséges', desc: 'Az oldal működéséhez kellenek: belépés, biztonság, a hozzájárulása megjegyzése. Nem kapcsolhatók ki.' },
|
|
353
369
|
functional: { title: 'Funkcionális', desc: 'Megjegyzik a beállításait, például a nyelvet vagy a chatet, hogy ne kelljen újra megadnia őket.' },
|
|
@@ -376,6 +392,7 @@
|
|
|
376
392
|
colPurpose: 'Finalità',
|
|
377
393
|
colExpiry: 'Scadenza',
|
|
378
394
|
floating: 'Impostazioni dei cookie',
|
|
395
|
+
extraTitle: 'Informazioni aggiuntive',
|
|
379
396
|
cat: {
|
|
380
397
|
necessary: { title: 'Necessari', desc: 'Servono al funzionamento del sito: accesso, sicurezza, memoria del suo consenso. Non possono essere disattivati.' },
|
|
381
398
|
functional: { title: 'Funzionali', desc: 'Ricordano le sue preferenze, come la lingua o la chat, così non deve impostarle di nuovo.' },
|
|
@@ -404,6 +421,7 @@
|
|
|
404
421
|
colPurpose: 'Paskirtis',
|
|
405
422
|
colExpiry: 'Galiojimas',
|
|
406
423
|
floating: 'Slapukų nustatymai',
|
|
424
|
+
extraTitle: 'Papildoma informacija',
|
|
407
425
|
cat: {
|
|
408
426
|
necessary: { title: 'Būtini', desc: 'Reikalingi, kad svetainė veiktų: prisijungimas, saugumas, jūsų sutikimo įsiminimas. Jų išjungti negalima.' },
|
|
409
427
|
functional: { title: 'Funkciniai', desc: 'Įsimena jūsų nustatymus, pavyzdžiui, kalbą ar pokalbius, kad jų nereikėtų nurodyti iš naujo.' },
|
|
@@ -432,6 +450,7 @@
|
|
|
432
450
|
colPurpose: 'Nolūks',
|
|
433
451
|
colExpiry: 'Derīgums',
|
|
434
452
|
floating: 'Sīkdatņu iestatījumi',
|
|
453
|
+
extraTitle: 'Papildu informācija',
|
|
435
454
|
cat: {
|
|
436
455
|
necessary: { title: 'Nepieciešamās', desc: 'Vajadzīgas vietnes darbībai — pieteikšanās, drošība, jūsu piekrišanas saglabāšana. Tās nevar izslēgt.' },
|
|
437
456
|
functional: { title: 'Funkcionālās', desc: 'Atceras jūsu iestatījumus, piemēram, valodu vai tērzēšanu, lai tie nebūtu jānorāda atkārtoti.' },
|
|
@@ -460,6 +479,7 @@
|
|
|
460
479
|
colPurpose: 'Skop',
|
|
461
480
|
colExpiry: 'Skadenza',
|
|
462
481
|
floating: 'Issettjar tal-cookies',
|
|
482
|
+
extraTitle: 'Informazzjoni addizzjonali',
|
|
463
483
|
cat: {
|
|
464
484
|
necessary: { title: 'Meħtieġa', desc: 'Meħtieġa biex is-sit jaħdem — login, sigurtà, tifkira tal-kunsens tiegħek. Ma jistgħux jintfew.' },
|
|
465
485
|
functional: { title: 'Funzjonali', desc: 'Jiftakru l-preferenzi tiegħek, bħal-lingwa jew iċ-chat, biex ma jkollokx terġa’ tissettjahom.' },
|
|
@@ -488,6 +508,7 @@
|
|
|
488
508
|
colPurpose: 'Doel',
|
|
489
509
|
colExpiry: 'Vervalt',
|
|
490
510
|
floating: 'Cookie-instellingen',
|
|
511
|
+
extraTitle: 'Aanvullende informatie',
|
|
491
512
|
cat: {
|
|
492
513
|
necessary: { title: 'Noodzakelijk', desc: 'Nodig om de site te laten werken: inloggen, beveiliging en het onthouden van uw keuze. Ze kunnen niet uit.' },
|
|
493
514
|
functional: { title: 'Functioneel', desc: 'Onthouden uw voorkeuren, zoals taal of chat, zodat u ze niet opnieuw hoeft in te stellen.' },
|
|
@@ -516,6 +537,7 @@
|
|
|
516
537
|
colPurpose: 'Cel',
|
|
517
538
|
colExpiry: 'Wygasa',
|
|
518
539
|
floating: 'Ustawienia plików cookie',
|
|
540
|
+
extraTitle: 'Informacje dodatkowe',
|
|
519
541
|
cat: {
|
|
520
542
|
necessary: { title: 'Niezbędne', desc: 'Potrzebne, by strona działała: logowanie, bezpieczeństwo, zapamiętanie zgody. Nie można ich wyłączyć.' },
|
|
521
543
|
functional: { title: 'Funkcjonalne', desc: 'Zapamiętują ustawienia, na przykład język lub czat, żeby nie trzeba było wybierać ich ponownie.' },
|
|
@@ -544,6 +566,7 @@
|
|
|
544
566
|
colPurpose: 'Finalidade',
|
|
545
567
|
colExpiry: 'Validade',
|
|
546
568
|
floating: 'Definições de cookies',
|
|
569
|
+
extraTitle: 'Informações adicionais',
|
|
547
570
|
cat: {
|
|
548
571
|
necessary: { title: 'Necessários', desc: 'Precisos para o site funcionar: início de sessão, segurança e memória do seu consentimento. Não podem ser desativados.' },
|
|
549
572
|
functional: { title: 'Funcionais', desc: 'Guardam as suas preferências, como o idioma ou o chat, para não ter de as definir outra vez.' },
|
|
@@ -572,6 +595,7 @@
|
|
|
572
595
|
colPurpose: 'Pentru ce',
|
|
573
596
|
colExpiry: 'Expiră',
|
|
574
597
|
floating: 'Setări cookie-uri',
|
|
598
|
+
extraTitle: 'Informații suplimentare',
|
|
575
599
|
// SPEC V1.10 §2 — заглушка встраивания. Only ro carries these here: en and
|
|
576
600
|
// ru are builtin in ck-ui.js, and every other locale falls back to en.
|
|
577
601
|
phText: 'Aici este conținut de la {host}. Se va încărca după acordul pentru «{cat}».',
|
|
@@ -616,6 +640,7 @@
|
|
|
616
640
|
colPurpose: 'Účel',
|
|
617
641
|
colExpiry: 'Platnosť',
|
|
618
642
|
floating: 'Nastavenia cookies',
|
|
643
|
+
extraTitle: 'Doplňujúce informácie',
|
|
619
644
|
cat: {
|
|
620
645
|
necessary: { title: 'Nevyhnutné', desc: 'Bez nich stránka nefunguje — prihlásenie, bezpečnosť, zapamätanie vášho súhlasu. Nedajú sa vypnúť.' },
|
|
621
646
|
functional: { title: 'Funkčné', desc: 'Pamätajú si vaše nastavenia, napríklad jazyk alebo chat, aby ste ich nezadávali znova.' },
|
|
@@ -644,6 +669,7 @@
|
|
|
644
669
|
colPurpose: 'Namen',
|
|
645
670
|
colExpiry: 'Poteče',
|
|
646
671
|
floating: 'Nastavitve piškotkov',
|
|
672
|
+
extraTitle: 'Dodatne informacije',
|
|
647
673
|
cat: {
|
|
648
674
|
necessary: { title: 'Nujni', desc: 'Potrebni za delovanje spletnega mesta — prijava, varnost, pomnjenje vašega soglasja. Ni jih mogoče izklopiti.' },
|
|
649
675
|
functional: { title: 'Funkcionalni', desc: 'Zapomnijo si vaše nastavitve, na primer jezik ali klepet, da jih ni treba določati znova.' },
|
|
@@ -672,6 +698,7 @@
|
|
|
672
698
|
colPurpose: 'Syfte',
|
|
673
699
|
colExpiry: 'Upphör',
|
|
674
700
|
floating: 'Cookieinställningar',
|
|
701
|
+
extraTitle: 'Ytterligare information',
|
|
675
702
|
cat: {
|
|
676
703
|
necessary: { title: 'Nödvändiga', desc: 'Krävs för att webbplatsen ska fungera — inloggning, säkerhet, minne av ditt samtycke. De kan inte stängas av.' },
|
|
677
704
|
functional: { title: 'Funktionella', desc: 'Kommer ihåg dina inställningar, till exempel språk eller chatt, så att du slipper välja igen.' },
|
|
@@ -700,6 +727,7 @@
|
|
|
700
727
|
colPurpose: 'Мета',
|
|
701
728
|
colExpiry: 'Термін',
|
|
702
729
|
floating: 'Налаштування cookie',
|
|
730
|
+
extraTitle: 'Додаткова інформація',
|
|
703
731
|
cat: {
|
|
704
732
|
necessary: { title: 'Необхідні', desc: 'Без них сайт не працює: вхід, безпека, пам’ять про ваш вибір. Вимкнути неможливо.' },
|
|
705
733
|
functional: { title: 'Функціональні', desc: 'Запам’ятовують ваші налаштування — наприклад мову або чат, — щоб ви не задавали їх знову.' },
|
|
@@ -728,6 +756,7 @@
|
|
|
728
756
|
colPurpose: 'Amaç',
|
|
729
757
|
colExpiry: 'Süre',
|
|
730
758
|
floating: 'Çerez ayarları',
|
|
759
|
+
extraTitle: 'Ek bilgiler',
|
|
731
760
|
cat: {
|
|
732
761
|
necessary: { title: 'Zorunlu', desc: 'Sitenin çalışması için gerekli: oturum açma, güvenlik, onayınızın hatırlanması. Kapatılamazlar.' },
|
|
733
762
|
functional: { title: 'İşlevsel', desc: 'Dil veya sohbet gibi tercihlerinizi hatırlar, böylece yeniden ayarlamanız gerekmez.' },
|
|
@@ -756,6 +785,7 @@
|
|
|
756
785
|
colPurpose: 'Formål',
|
|
757
786
|
colExpiry: 'Utløper',
|
|
758
787
|
floating: 'Innstillinger for informasjonskapsler',
|
|
788
|
+
extraTitle: 'Tilleggsinformasjon',
|
|
759
789
|
cat: {
|
|
760
790
|
necessary: { title: 'Nødvendige', desc: 'Kreves for at nettstedet skal virke — innlogging, sikkerhet, minne om samtykket ditt. De kan ikke slås av.' },
|
|
761
791
|
functional: { title: 'Funksjonelle', desc: 'Husker innstillingene dine, som språk eller chat, så du slipper å velge på nytt.' },
|
|
@@ -788,6 +818,7 @@
|
|
|
788
818
|
colPurpose: 'Tilgangur',
|
|
789
819
|
colExpiry: 'Gildistími',
|
|
790
820
|
floating: 'Stillingar vefkaka',
|
|
821
|
+
extraTitle: 'Viðbótarupplýsingar',
|
|
791
822
|
cat: {
|
|
792
823
|
necessary: { title: 'Nauðsynlegar', desc: 'Nauðsynlegar til að vefurinn virki — innskráning, öryggi, að muna samþykki þitt. Ekki er hægt að slökkva á þeim.' },
|
|
793
824
|
functional: { title: 'Virknivefkökur', desc: 'Muna stillingar þínar, til dæmis tungumál eða spjall, svo þú þurfir ekki að velja aftur.' },
|
|
@@ -817,6 +848,7 @@
|
|
|
817
848
|
colPurpose: 'Сврха',
|
|
818
849
|
colExpiry: 'Истиче',
|
|
819
850
|
floating: 'Подешавања колачића',
|
|
851
|
+
extraTitle: 'Додатне информације',
|
|
820
852
|
cat: {
|
|
821
853
|
necessary: { title: 'Неопходни', desc: 'Потребни су да би сајт радио — пријава, безбедност, памћење ваше сагласности. Не могу се искључити.' },
|
|
822
854
|
functional: { title: 'Функционални', desc: 'Памте ваша подешавања, на пример језик или ћаскање, да их не бисте бирали поново.' },
|
|
@@ -845,6 +877,7 @@
|
|
|
845
877
|
colPurpose: 'Finalitat',
|
|
846
878
|
colExpiry: 'Caduca',
|
|
847
879
|
floating: 'Configuració de galetes',
|
|
880
|
+
extraTitle: 'Informació addicional',
|
|
848
881
|
cat: {
|
|
849
882
|
necessary: { title: 'Necessàries', desc: 'Calen perquè el lloc funcioni: inici de sessió, seguretat i memòria del vostre consentiment. No es poden desactivar.' },
|
|
850
883
|
functional: { title: 'Funcionals', desc: 'Recorden les vostres preferències, com l’idioma o el xat, perquè no les hàgiu de tornar a configurar.' },
|
|
@@ -873,6 +906,7 @@
|
|
|
873
906
|
colPurpose: 'Qëllimi',
|
|
874
907
|
colExpiry: 'Skadon',
|
|
875
908
|
floating: 'Cilësimet e cookie-ve',
|
|
909
|
+
extraTitle: 'Informacione shtesë',
|
|
876
910
|
cat: {
|
|
877
911
|
necessary: { title: 'Të nevojshme', desc: 'Nevojiten që faqja të funksionojë — hyrja, siguria, ruajtja e pëlqimit tuaj. Nuk mund të fiken.' },
|
|
878
912
|
functional: { title: 'Funksionale', desc: 'Mbajnë mend preferencat tuaja, si gjuha ose biseda, që të mos i vendosni sërish.' },
|
|
@@ -901,6 +935,7 @@
|
|
|
901
935
|
colPurpose: 'Цел',
|
|
902
936
|
colExpiry: 'Истекува',
|
|
903
937
|
floating: 'Поставки за колачиња',
|
|
938
|
+
extraTitle: 'Дополнителни информации',
|
|
904
939
|
cat: {
|
|
905
940
|
necessary: { title: 'Неопходни', desc: 'Потребни се за страницата да работи — најава, безбедност, помнење на вашата согласност. Не можат да се исклучат.' },
|
|
906
941
|
functional: { title: 'Функционални', desc: 'Ги паметат вашите поставки, на пример јазикот или разговорот, за да не ги задавате повторно.' },
|
package/src/ck-saas.js
CHANGED
|
@@ -64,11 +64,35 @@
|
|
|
64
64
|
// document.currentScript is correct while this file is executing.
|
|
65
65
|
var cur = doc.currentScript;
|
|
66
66
|
if (cur && cur.getAttribute && cur.getAttribute('data-ck-id')) { return cur; }
|
|
67
|
+
// Fallback for the exotic case where currentScript is unavailable (an
|
|
68
|
+
// async injection, an old browser). With two snippets on the page both
|
|
69
|
+
// loaders would pick the same last tag — which the §1.2 stand-down below
|
|
70
|
+
// turns into "the second one goes quiet" rather than a double init. Not
|
|
71
|
+
// ideal, but it degrades in the safe direction, and every real snippet is
|
|
72
|
+
// a plain synchronous <script> where currentScript is set.
|
|
67
73
|
var all = doc.querySelectorAll('script[data-ck-id]');
|
|
68
74
|
return all && all.length ? all[all.length - 1] : null;
|
|
69
75
|
} catch (e) { return null; }
|
|
70
76
|
}
|
|
71
77
|
|
|
78
|
+
// Every distinct data-ck-id on the page, in document order. Read from the DOM
|
|
79
|
+
// rather than accumulated across loaders, because on a real page the second
|
|
80
|
+
// snippet's tag may not be parsed yet when the first loader runs — the last
|
|
81
|
+
// loader to execute sees them all, and it is the one that matters.
|
|
82
|
+
function tagIds() {
|
|
83
|
+
var out = [];
|
|
84
|
+
try {
|
|
85
|
+
var all = doc.querySelectorAll('script[data-ck-id]');
|
|
86
|
+
if (!all) { return out; }
|
|
87
|
+
for (var i = 0; i < all.length; i++) {
|
|
88
|
+
var id = '';
|
|
89
|
+
try { id = String(all[i].getAttribute('data-ck-id') || '').trim(); } catch (e2) { id = ''; }
|
|
90
|
+
if (id && out.indexOf(id) === -1) { out.push(id); }
|
|
91
|
+
}
|
|
92
|
+
} catch (e) { /* noop */ }
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
|
|
72
96
|
var tag = findOwnTag();
|
|
73
97
|
if (!tag) { return; } // no data-ck-id -> standalone page, stay inert
|
|
74
98
|
|
|
@@ -87,6 +111,54 @@
|
|
|
87
111
|
return;
|
|
88
112
|
}
|
|
89
113
|
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
// Shared state across every loader on the page (SPEC §1.1)
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
/* A page can carry more than one snippet: a site migrated between two ids and
|
|
118
|
+
the old block was never removed, an agency pasted its own on top of the
|
|
119
|
+
client's. Each copy of this file is a separate IIFE with its own closure, so
|
|
120
|
+
the only thing they can agree on is a global.
|
|
121
|
+
|
|
122
|
+
`pending` here counts CONFIG FETCHES still in flight — deliberately not the
|
|
123
|
+
same thing as the beacon queue further down, which is also called `pending`
|
|
124
|
+
but lives in this file's closure and is what _saas.pending() reports.
|
|
125
|
+
|
|
126
|
+
`warnedDup` and `activeId` are not in the spec's field list, but the once-
|
|
127
|
+
only duplicate warning and the "driven by snippet X" message have nowhere
|
|
128
|
+
else to live: whichever loader speaks last would otherwise repeat the
|
|
129
|
+
warning, and the loser needs the winner's id. */
|
|
130
|
+
var shared = global.__ckSaas;
|
|
131
|
+
if (!shared || typeof shared !== 'object') {
|
|
132
|
+
shared = global.__ckSaas = { pending: 0, done: false, ids: [], failures: [] };
|
|
133
|
+
}
|
|
134
|
+
if (!shared.ids || typeof shared.ids.length !== 'number') { shared.ids = []; }
|
|
135
|
+
if (!shared.failures || typeof shared.failures.length !== 'number') { shared.failures = []; }
|
|
136
|
+
|
|
137
|
+
/* SPEC §1.2 — the same id twice is Tilda duplicating the head block, not two
|
|
138
|
+
snippets. It is not a misconfiguration, so it must not warn; but it must
|
|
139
|
+
also not fetch or initialise a second time, or the page would pay for two
|
|
140
|
+
config requests and CK.init() would run twice. Stand down silently, and
|
|
141
|
+
BEFORE pending++ so the vanished loader cannot hold the strict fallback
|
|
142
|
+
hostage in §1.4. */
|
|
143
|
+
if (shared.ids.indexOf(siteId) !== -1) { return; }
|
|
144
|
+
shared.ids.push(siteId);
|
|
145
|
+
shared.pending++;
|
|
146
|
+
|
|
147
|
+
var allIds = tagIds();
|
|
148
|
+
// A tag whose loader has not executed yet is still a snippet on this page.
|
|
149
|
+
for (var ai = 0; ai < shared.ids.length; ai++) {
|
|
150
|
+
if (allIds.indexOf(shared.ids[ai]) === -1) { allIds.push(shared.ids[ai]); }
|
|
151
|
+
}
|
|
152
|
+
if (allIds.length > 1 && !shared.warnedDup) {
|
|
153
|
+
shared.warnedDup = true;
|
|
154
|
+
var others = [];
|
|
155
|
+
for (var oi = 0; oi < allIds.length; oi++) {
|
|
156
|
+
if (allIds[oi] !== siteId) { others.push(allIds[oi]); }
|
|
157
|
+
}
|
|
158
|
+
warn('another ConsentKit snippet on this page uses site id ' + others.join(', ') +
|
|
159
|
+
'; keep one snippet per site');
|
|
160
|
+
}
|
|
161
|
+
|
|
90
162
|
var cacheKey = CACHE_PREFIX + siteId;
|
|
91
163
|
var activeConfig = null; // config currently driving this page load
|
|
92
164
|
|
|
@@ -142,13 +214,64 @@
|
|
|
142
214
|
} catch (e) { return 0; }
|
|
143
215
|
}
|
|
144
216
|
|
|
217
|
+
/* This loader's own config attempt resolves exactly once. Both the cold path
|
|
218
|
+
and the cached path run through here, and the cached path is the reason the
|
|
219
|
+
guard exists at all: it settles SUCCESSFULLY the moment the cache is read,
|
|
220
|
+
and then starts a background revalidation whose failure must not decrement
|
|
221
|
+
`pending` a second time or push a failure the page never suffered. */
|
|
222
|
+
var settled = false;
|
|
223
|
+
function settleOk() {
|
|
224
|
+
if (settled) { return; }
|
|
225
|
+
settled = true;
|
|
226
|
+
shared.done = true;
|
|
227
|
+
shared.activeId = shared.activeId || siteId;
|
|
228
|
+
shared.pending--;
|
|
229
|
+
}
|
|
230
|
+
|
|
145
231
|
function initWith(config, why) {
|
|
232
|
+
settleOk();
|
|
146
233
|
activeConfig = config;
|
|
147
234
|
applyHostDb(config);
|
|
148
235
|
try { CK.init(config); } catch (e) { error('init() failed: ' + (e && e.message)); }
|
|
149
236
|
if (why) { /* reserved for diagnostics */ }
|
|
150
237
|
}
|
|
151
238
|
|
|
239
|
+
/* SPEC §1.4 — one loader's config failed. What follows depends entirely on
|
|
240
|
+
what the OTHER loaders are doing, which is why none of this can be decided
|
|
241
|
+
locally.
|
|
242
|
+
|
|
243
|
+
The case that motivates the whole section: a site has a live snippet and a
|
|
244
|
+
dead one (an id that was deleted from the account). Before 0.5.14 the dead
|
|
245
|
+
one's 404 raised the strict fallback and re-initialised the core with
|
|
246
|
+
everything denied — a working banner replaced by a broken one because of a
|
|
247
|
+
block nobody had noticed in years. Now the dead snippet only fails; the
|
|
248
|
+
live snippet still drives the page. */
|
|
249
|
+
function settleFail(reason) {
|
|
250
|
+
if (settled) { return; }
|
|
251
|
+
settled = true;
|
|
252
|
+
shared.pending--;
|
|
253
|
+
shared.failures.push(siteId + ': ' + reason);
|
|
254
|
+
|
|
255
|
+
if (shared.done) {
|
|
256
|
+
// Someone else already initialised the page. Touching CK.init() now would
|
|
257
|
+
// swap ConsentKit.config identity out from under a banner the visitor may
|
|
258
|
+
// already be looking at.
|
|
259
|
+
warn('config for ' + siteId + ' unavailable (' + reason + '); the page is driven by snippet ' +
|
|
260
|
+
(shared.activeId || 'unknown'));
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (shared.pending > 0) {
|
|
264
|
+
// SPEC §1.5: the strict fallback is a last resort, and it is not the last
|
|
265
|
+
// resort while another snippet may still succeed. CFG_TIMEOUT_MS bounds
|
|
266
|
+
// that wait — every in-flight fetch aborts by then, so this cannot hang.
|
|
267
|
+
warn('config for ' + siteId + ' unavailable (' + reason + '); waiting for the other snippet');
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
// Every snippet on the page failed. This is the 0.5.13 behaviour, and for a
|
|
271
|
+
// single tag the joined list is exactly one entry.
|
|
272
|
+
initStrict(shared.failures.join('; '));
|
|
273
|
+
}
|
|
274
|
+
|
|
152
275
|
// Strict FALLBACK: banner shows, every opt-in category stays off, no journal.
|
|
153
276
|
// policyVersion 'strict-fallback' deliberately mismatches any stored consent,
|
|
154
277
|
// so a previous decision is not silently reused when the server is unreachable.
|
|
@@ -161,13 +284,28 @@
|
|
|
161
284
|
// Known trackers are still blocked, as always.
|
|
162
285
|
function initStrict(reason) {
|
|
163
286
|
warn('config unavailable (' + reason + ') — strict fallback: banner shown, all opt-in categories denied, journal disabled.');
|
|
287
|
+
shared.strictFallback = true;
|
|
288
|
+
// A _saas already published by another loader must learn this too: the
|
|
289
|
+
// object below is a plain assignment and the last loader to run wins, so a
|
|
290
|
+
// late publisher would otherwise report strictFallback: false.
|
|
291
|
+
try { if (CK._saas) { CK._saas.strictFallback = true; } } catch (e) { /* noop */ }
|
|
164
292
|
initWith({ policyVersion: 'strict-fallback' });
|
|
165
293
|
}
|
|
166
294
|
|
|
167
295
|
// cacheMode: 'default' lets the HTTP cache answer (cold load); 'no-cache'
|
|
168
296
|
// forces a conditional request to the origin (background revalidation).
|
|
169
297
|
function fetchConfig(etag, cacheMode, onOk, onFail) {
|
|
170
|
-
if (typeof global.fetch !== 'function') {
|
|
298
|
+
if (typeof global.fetch !== 'function') {
|
|
299
|
+
/* Deferred to a microtask rather than called inline. Every other failure
|
|
300
|
+
path here is already asynchronous, so a synchronous one would be the
|
|
301
|
+
single case where this loader could reach the strict fallback before a
|
|
302
|
+
later snippet on the page had a chance to register itself in
|
|
303
|
+
__ckSaas.pending. A microtask, not a timer: it still resolves before
|
|
304
|
+
any network could. */
|
|
305
|
+
try { global.Promise.resolve().then(function () { onFail('fetch unsupported'); }); }
|
|
306
|
+
catch (e) { onFail('fetch unsupported'); }
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
171
309
|
var ctrl = null, timer = null;
|
|
172
310
|
try { ctrl = new global.AbortController(); } catch (e) { ctrl = null; }
|
|
173
311
|
var opts = { method: 'GET', credentials: 'omit', mode: 'cors' };
|
|
@@ -236,12 +374,13 @@
|
|
|
236
374
|
// Cold path: no cached config exists, so the HTTP cache cannot serve a
|
|
237
375
|
// stale one. Default caching is the right economy here.
|
|
238
376
|
fetchConfig(null, null, function (r) {
|
|
239
|
-
|
|
377
|
+
// An empty 304 without a cache to satisfy it is a failure like any other,
|
|
378
|
+
// and now goes through the same arbitration: another snippet may still be
|
|
379
|
+
// holding a usable config.
|
|
380
|
+
if (r.notModified || !r.config) { settleFail('empty response without cache'); return; }
|
|
240
381
|
writeCache(r.etag, r.config);
|
|
241
382
|
initWith(r.config, 'network');
|
|
242
|
-
},
|
|
243
|
-
initStrict(reason);
|
|
244
|
-
});
|
|
383
|
+
}, settleFail);
|
|
245
384
|
}
|
|
246
385
|
|
|
247
386
|
// ---------------------------------------------------------------------------
|
|
@@ -421,10 +560,19 @@
|
|
|
421
560
|
global.addEventListener && global.addEventListener('pagehide', flush, false);
|
|
422
561
|
} catch (e) { /* noop */ }
|
|
423
562
|
|
|
424
|
-
|
|
563
|
+
/* Minimal surface for the demo status panel; not a public API.
|
|
564
|
+
|
|
565
|
+
With two loaders this is assigned twice and the last one wins, so nothing
|
|
566
|
+
that must survive may be read out of this closure: `siteIds` comes from the
|
|
567
|
+
DOM and `strictFallback` from the shared object, both of which every loader
|
|
568
|
+
agrees on. `pending()` still reports the BEACON queue — a different counter
|
|
569
|
+
from __ckSaas.pending, and the one the demo page and the panel already
|
|
570
|
+
read. */
|
|
425
571
|
CK._saas = {
|
|
426
572
|
siteId: siteId,
|
|
427
573
|
api: apiBase,
|
|
574
|
+
siteIds: allIds.slice(),
|
|
575
|
+
strictFallback: shared.strictFallback === true,
|
|
428
576
|
pending: function () { return pending.length; },
|
|
429
577
|
config: function () { return activeConfig; }
|
|
430
578
|
};
|