PageSourceSearch

https://uclouvain.be/modules/uclouvain/uclouvain_core/assets/js/uclouvain-tarteaucitron.js?tikpb5

js uclouvain.be collected 2026-10-01 07:52:07 UTC 15,498 bytes, 364 lines download raw bytes

1(function (Drupal) {
2    'use strict';
3
4    Drupal.behaviors.uclouvain_tarteaucitron = {
5        attach: function (context, settings) {
6
7            let uclouvain_declared_services = [];
8            if (typeof tarteaucitron === 'undefined') return;
9
10            function getDomainFromURL(url) {
11                try {
12                    return new URL(url).hostname;
13                } catch {
14                    return '';
15                }
16            }
17
18            function isWhitelisted(domain) {
19                return whitelist.some((rule) => {
20                    if (rule.startsWith('*.')) {
21                        const base = rule.substring(2);
22                        return domain === base || domain.endsWith('.' + base);
23                    }
24                    return domain === rule;
25                });
26            }
27
28            function getServiceMatch(url) {
29                const domain = getDomainFromURL(url);
30
31                for (const service of services) {
32                    if (service.domains && service.domains.some(d => domain === d || domain.endsWith('.' + d))) {
33                        // execute regex of the service on url
34                        const match = url.match(service.regex);
35                        if (match) {
36
37                            service.objectId = null;
38
39                            if (match[1] || match[2]) {
40                                service.objectId = match[1] || match[2];
41                            }
42
43                            return service;
44                        }
45                    }
46                }
47                return null;
48            }
49
50            const iframes = once('uclouvain-tac-processed', 'iframe', context);
51
52            const whitelist = [
53                '*.uclouvain.be',
54                '*.ucl.ac.be',
55                'cdn.uclouvain.be',
56                '*.genially.com',
57                'stats.sisg.ucl.ac.be'
58            ];
59
60            const services = [
61                {
62                    name: 'youtube',
63                    label: "Youtube",
64                    className: 'youtube_player',
65                    domains: ['youtube.com', 'youtu.be', 'youtube-nocookie.com'],
66                    regex: /(?:https?:\/\/)?(?:www\.)?(?:youtube(?:-nocookie)?\.com\/(?:watch\?v=|embed\/|v\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/,
67                    custom_plugin: false,
68                    add_video_id_param: true
69                },
70                {
71                    name: 'vimeo',
72                    label: "Vimeo",
73                    className: 'vimeo_player',
74                    domains: ['vimeo.com'],
75                    regex: /vimeo\.com\/(?:video\/)?(\d+)/,
76                    custom_plugin: false,
77                    add_video_id_param: true
78
79                },
80                {
81                    name: 'dailymotion',
82                    label: "Dailymotion",
83                    className: 'dailymotion_player',
84                    domains: ['dailymotion.com', 'dai.ly'],
85                    regex: /dailymotion\.com\/video\/([a-zA-Z0-9]+)|dai\.ly\/([a-zA-Z0-9]+)/,
86                    custom_plugin: false,
87                    add_video_id_param: true
88                },
89                {
90                    name: 'uclouvain_flip_service',
91                    label: "Flip",
92                    className: 'flip_player',
93                    domains: ['fliphtml5.com', 'online.fliphtml5.com'],
94                    regex: /fliphtml5\.com\/([^\/]+)\/([^\/]+)/,
95                    custom_plugin: true,
96                    type: 'api',
97                    add_video_id_param: false
98                },
99                {
100                    name: 'uclouvain_padlet_service',
101                    label: "Padlet",
102                    className: 'padlet_player',
103                    domains: ['padlet.org', 'padlet.pics','padlet.net','padlet.com'],
104                    regex: /padlet\.(org|pics|net|com)\/embed\/([a-zA-Z0-9]+)/,
105                    custom_plugin: true,
106                    type: 'api',
107                    add_video_id_param: false
108                },
109                {
110                    name: 'uclouvain_podcastics_service',
111                    label: "Podcastics",
112                    className: 'podcastics_player',
113                    domains: ['podcastics.com'],
114                    regex: /podcastics\.com\/playlist\/(\d+)/,
115                    custom_plugin: true,
116                    type: 'other',
117                    add_video_id_param: false
118                },
119                {
120                    name: 'uclouvain_airtable_service',
121                    label: "Airtable.com",
122                    className: 'airtable_player',
123                    domains: ['airtable.com'],
124                    regex: /airtable\.com\/embed\/([a-zA-Z0-9]+)/,
125                    custom_plugin: true,
126                    type: 'api',
127                    add_video_id_param: false
128                },
129                {
130                    name: 'uclouvain_powerbi_service',
131                    label: "Powerbi.com",
132                    className: 'powerbi_player',
133                    domains: ['powerbi.com'],
134                    regex: /powerbi\.com\/view\?r=([a-zA-Z0-9]+)/,
135                    custom_plugin: true,
136                    type: "api",
137                    add_video_id_param: false
138                },
139                {
140                    name: 'uclouvain_auvio_service',
141                    label: "Auvio (RTBF)",
142                    className: 'auvio_player',
143                    domains: ['rtbf.be'],
144                    regex: /www\.rtbf\.be\/auvio\/[^?]*\?id=(\d+)/,
145                    custom_plugin: true,
146                    type: 'video',
147                    add_video_id_param: false
148                },
149                {
150                    name: 'uclouvain_spotify_service',
151                    label: "Spotify",
152                    className: 'spotify_player',
153                    domains: ['spotify.com'],
154                    regex: /open\.spotify\.com\/embed\/[a-z]+\/([a-zA-Z0-9]+)/,
155                    custom_plugin: true,
156                    type: 'video',
157                    add_video_id_param: false
158                },
159                {
160                    name: 'uclouvain_flickr_service',
161                    label: "Flickr",
162                    className: 'flicker_player',
163                    domains: ['flickr.com'],
164                    regex: /www\.flickr\.com\/photos\/[^\/]+\/sets\/(\d+)/,
165                    custom_plugin: true,
166                    type: 'other',
167                    add_video_id_param: false
168                },
169                {
170                    name: 'uclouvain_xmind_service',
171                    label: "xmind",
172                    className: 'xmind_player',
173                    domains: ['xmind.app'],
174                    regex: /xmind\.app\/embed\/([a-zA-Z0-9]+)/,
175                    custom_plugin: true,
176                    type: 'api',
177                    add_video_id_param: false
178                },
179                {
180                    name: 'uclouvain_srf_service',
181                    label: "SRF.ch",
182                    className: 'srf_player',
183                    domains: ['tp.srgssr.ch', 'rts.ch'],
184                    regex: /urn=urn:rts:audio:(\d+)/,
185                    custom_plugin: true,
186                    type: 'video',
187                    add_video_id_param: false
188                }
189            ];
190
191            // Modify twig template is not enough for inclusion. Need to parse all page iframes.
192            iframes.forEach((iframe) => {
193                const src = iframe.src || '';
194                const domain = getDomainFromURL(src);
195
196                // don't touch the iframe is its domain (from url) is into whitelist.
197                // Matomo debug preview adds an iframe with src = about:blank.
198                if (isWhitelisted(domain) || src === 'about:blank') return;
199
200                const width = iframe.style.width || iframe.getAttribute('data-width') || iframe.getAttribute('width')  ||  '100%';
201                const height = iframe.style.height || iframe.getAttribute('data-height') || iframe.getAttribute('height')  ||  '100%';
202
203                let service = getServiceMatch(src);
204
205                // don't touch the iframe if service doesn't exist
206                if (service === null) {
207                     service =  {
208                         className: 'uclouvain_external_player',
209                         objectId: null,
210                         name : 'uclouvain_external_services',
211                         label : 'Contenu externe',
212                         add_video_id_param: false
213                    }
214                }
215
216                const placeholder = document.createElement('div');
217                placeholder.setAttribute('class', service.className + ' tarteaucitron-placeholder');
218                placeholder.setAttribute('data-width', width);
219                placeholder.setAttribute('data-src', src);
220                placeholder.setAttribute('data-height', height);
221
222                placeholder.style.height = height;
223                placeholder.style.width = width;
224                placeholder.id = service.className;
225
226                placeholder.innerHTML = `
227                          <div class="tac_activate tac_activate_${service.className}">
228                            <div class="tac_float">
229                              ${service.label}  est bloqué. 
230                              <button type="button" aria-label="Autoriser ${service.label}" id="${service.name}Allowed" class="tarteaucitronAllow" aria-pressed="true">           
231                                <span class="tarteaucitronCheck" aria-hidden="true"></span> Autoriser       
232                               </button>                    
233                            </div>
234                          </div>
235                        `;
236
237                if (service.add_video_id_param) {
238                    placeholder.setAttribute('data-videoID', service.objectId);
239                }
240
241                iframe.parentNode.replaceChild(placeholder, iframe);
242            });
243
244
245            /**
246             * Declare a Tarte au cintron service.
247             * @param name
248             * @param label
249             * @param className
250             * @param type
251             */
252            function declareTarteaucitronService({ name, label,className, type='other' }) {
253                tarteaucitron.services[name] = {
254                    key: name,
255                    type: type,
256                    name: label,
257                    description: `Ce plugin bloque les contenus ${label}`,
258                    needConsent: true,
259                    cookies: [],
260                    js: function () {
261                        const elements = document.querySelectorAll(`.${className}`);
262                        elements.forEach(el => {
263                            const src = el.getAttribute('data-src');
264                            const width = el.getAttribute('data-width') || el.style.width || '100%';
265                            const height = el.getAttribute('data-height') || el.style.height || '100%';
266
267                            const iframe = document.createElement('iframe');
268                            iframe.src = src;
269                            iframe.className = className;
270                            iframe.width = width;
271                            iframe.height = height;
272                            iframe.allowFullscreen = true;
273                            iframe.setAttribute('frameborder', 0);
274
275                            el.parentNode.replaceChild(iframe, el);
276                        });
277                    },
278                    fallback: function () {
279                        const id = className;
280                        const iframes = document.querySelectorAll(`iframe.${className}`);
281
282                        iframes.forEach((iframe) => {
283                            const src = iframe.src;
284                            if (!src) return;
285
286                            const width = iframe.getAttribute('data-width') || iframe.style.width || '100%';
287                            const height = iframe.getAttribute('data-height') || iframe.style.height || '100%';
288
289                            const placeholder = document.createElement('div');
290                            placeholder.className = `${className} tarteaucitron-placeholder`;
291                            placeholder.setAttribute('data-src', src);
292                            placeholder.setAttribute('data-width', width);
293                            placeholder.setAttribute('data-height', height);
294                            placeholder.style = `z-index:98;position:relative;height:${height};width:${width};`;
295                            placeholder.setAttribute('aria-label', `Contenu externe désactivé.`);
296
297                            placeholder.id = id;
298                            placeholder.innerHTML = `
299                              <div class="tac_activate tac_activate_${id}">
300                                <div class="tac_float">
301                                  ${label} est bloqué.
302                                  <button type="button" class="tarteaucitronAllow" id="${name}" onclick="tarteaucitron.userInterface.respond('${name}', true);">
303                                    <span class="tarteaucitronCheck" aria-hidden="true"></span> Autoriser ${label}
304                                  </button>
305                                </div>
306                              </div>
307                            `;
308
309                            iframe.parentNode.replaceChild(placeholder, iframe);
310                        });
311                    }
312                };
313            }
314
315            // UCLouvain Matomo - Specific plugin
316            tarteaucitron.services.uclouvain_matomo = {
317                key: 'uclouvain_matomo',
318                type: 'analytic',
319                name: 'UCLouvain Tracking',
320                needConsent: true,
321                cookies: [],
322                js: function () {
323                    // @todo is necessary for matomo triggering (Flying Fish)
324                },
325                fallback: function () {
326                    // @todo is necessary for matomo triggering (Flying Fish)
327                }
328            };
329
330            if (!tarteaucitron.job.includes('uclouvain_matomo')) {
331                tarteaucitron.job.push('uclouvain_matomo');
332            }
333
334            tarteaucitron.job = tarteaucitron.job || [];
335            services.forEach(function(service, index) {
336
337                if (service.custom_plugin) {
338                    declareTarteaucitronService({
339                        name: service.name,
340                        label: service.label,
341                        className: service.className,
342                        type: service.type ? service.type : 'other'
343                    });
344                }
345
346                if (!tarteaucitron.job.includes(service.name)) {
347                    tarteaucitron.job.push(service.name);
348                }
349            });
350
351            /* generic service */
352            declareTarteaucitronService({
353                name: 'uclouvain_external_services',
354                label: 'Contenus externes',
355                className: 'uclouvain_external_player'
356            });
357
358            if (!tarteaucitron.job.includes('uclouvain_external_services')) {
359                tarteaucitron.job.push('uclouvain_external_services');
360            }
361
362        }
363    };
364})(Drupal);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.