PageSourceSearch

https://petitfaucheux.fr/modules/supersoniks/ssks_gtranslate/js/ssks_gtranslate_notranslate.js?v=1

js petitfaucheux.fr collected 2026-09-24 19:16:46 UTC 4,365 bytes, 109 lines download raw bytes

1(function ($) {
2  Drupal.behaviors.ssks_gtranslate_notranslate = {
3    attach: function (context, settings) {
4      excludeEmailLinksTranslation();
5      protectExcludedWords(context, settings);
6    },
7  };
8
9  function excludeEmailLinksTranslation() {
10    // add class notranslate to all email
11    $(once("notranlate-class-mail", "a[href*=mailto]")).each(function () {
12      $(this).addClass("notranslate");
13    });
14  }
15
16  function protectExcludedWords(context, settings) {
17    // Get all excluded words, clean them (remove empty string, escape regex chars, order them)
18    let excluded_words = settings.ssks_gtranslate.excluded_words;
19    excluded_words = cleanWords(excluded_words);
20    if (!excluded_words.length) return;
21
22    // Get the target element from the context.
23    // Can be the document or a DOM element
24    // Typically to process ajax content, like the widget horaires
25    const $targetElement = (context === document) ? $("body") : $(context);
26    // Build the regex to match at least one word
27    const wordsRegex = new RegExp(`(?:^|[^a-zA-Z\\d'’′])(${excluded_words.join('|')})(?:[^a-zA-Z\\d]|$)`, 'i');
28    $(once("notranlate-class-added", $targetElement)).each((k, el) => {
29      const queue = [el];
30      let curr;
31      while ((curr = queue.pop())) {
32        // Utiliser TreeWalker pour ne traiter que les nœuds de texte
33        const walker = document.createTreeWalker(
34          curr,
35          NodeFilter.SHOW_TEXT,
36          {
37            acceptNode: function (node) {
38                const parent = node.parentElement;
39                if (!parent) return NodeFilter.FILTER_ACCEPT;
40
41                // Skip si le parent est déjà notranslate
42                if (parent.classList.contains('notranslate')) {
43                    return NodeFilter.FILTER_REJECT;
44                }
45
46                // Skip les contenus bruts non-DOM : noscript, script, style, template
47                // (leur "texte" peut contenir du HTML brut, ex: fallback d'images lazy-load)
48                const tag = parent.tagName;
49                if (tag === 'NOSCRIPT' || tag === 'SCRIPT' || tag === 'STYLE' || tag === 'TEMPLATE') {
50                    return NodeFilter.FILTER_REJECT;
51                }
52
53                return NodeFilter.FILTER_ACCEPT;
54            }
55          },
56          false
57        );
58
59        // On collecte d'abord tous les nœuds à traiter SANS muter le DOM :
60        // remplacer un nœud en cours de traversée détache le nœud courant du
61        // TreeWalker, et nextNode() s'arrête alors après le premier remplacement.
62        const nodesToProcess = [];
63        let textNode;
64        while ((textNode = walker.nextNode())) {
65          if (textNode.textContent.match(new RegExp(wordsRegex.source, "gi"))) {
66            nodesToProcess.push(textNode);
67          }
68        }
69
70        // La traversée terminée, on peut muter le DOM sans casser le walker.
71        nodesToProcess.forEach((node) => {
72          const textRegex = new RegExp(wordsRegex.source, "gi");
73          // Créer un fragment de document pour le nouveau contenu
74          const fragment = document.createDocumentFragment();
75          const tempDiv = document.createElement('div');
76          tempDiv.innerHTML = node.textContent.replace(
77            textRegex,
78            (match) => `<span class="notranslate">${match}</span>`
79          );
80
81          // Transférer les nœuds du div temporaire vers le fragment
82          while (tempDiv.firstChild) {
83            fragment.appendChild(tempDiv.firstChild);
84          }
85
86          // Remplacer le nœud de texte par le fragment
87          node.parentNode.replaceChild(fragment, node);
88        });
89      }
90    });
91  }
92
93  /**
94   * Cleans up and processes an array of words by removing empty strings,
95   * sorting them by length in descending order, and escaping special
96   * characters.
97   *
98   * @param {string[]} words - The array of words to be cleaned and processed.
99   * @return {string[]} The cleaned and processed array of words.
100   */
101  function cleanWords(words) {
102    // Order words by length, bigger to smaller, to be sure to parse all words
103    // Exemple : parse "Le Rocher de Palmer" before "Le Rocher"
104    return words.filter((w) => w.trim().length)
105      .sort((a, b) => b.length - a.length)
106      .map((str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
107  }
108
109})(jQuery, Drupal, drupalSettings);

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.