PageSourceSearch

https://www.utt.fr/static/js/scroll-spy.js

js utt.fr collected 2026-10-01 10:23:56 UTC 8,087 bytes, 194 lines download raw bytes

1var throttle = function(func, wait, options) {
2    var context, args, result;
3    var timeout = null;
4    var previous = 0;
5    if (!options) options = {};
6    var later = function() {
7        previous = options.leading === false ? 0 : Date.now();
8        timeout = null;
9        result = func.apply(context, args);
10        if (!timeout) context = args = null;
11    };
12    return function() {
13        var now = Date.now();
14        if (!previous && options.leading === false) previous = now;
15        var remaining = wait - (now - previous);
16        context = this;
17        args = arguments;
18        if (remaining <= 0 || remaining > wait) {
19            if (timeout) {
20                clearTimeout(timeout);
21                timeout = null;
22            }
23            previous = now;
24            result = func.apply(context, args);
25            if (!timeout) context = args = null;
26        } else if (!timeout && options.trailing !== false) {
27            timeout = setTimeout(later, remaining);
28        }
29        return result;
30    };
31};
32
33function getPosition(element) {
34    var xPosition = 0;
35    var yPosition = 0;
36
37    while(element) {
38        xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
39        yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
40        element = element.offsetParent;
41    }
42
43    return { x: xPosition, y: yPosition };
44}
45
46var ScrollSpy = function() {
47    var instance = {
48        /**
49         * Objet représentant toutes les configurations possibles sur ScrollSpy
50         */
51        _options: {
52            /**
53             * anchors: liste des zones à repérer dans le menu de sauts.
54             * Peut être :
55             * - une chaîne de caractère (sélecteur)
56             * - un tableau de Nodes
57             * - une fonction qui retourne une NodeList
58             */
59            anchors: '[data-scrollspy-landmark]',
60            /**
61             * Fonction appelée pour récupérer le titre de la zone.
62             * @param anchor zone ancrée à repérer
63             * @returns {string} Titre de la zone
64             */
65            anchorGetTitle: function(anchor) {
66                return anchor.querySelector('[data-scrollspy-landmark-title]').innerHTML;
67            },
68            /**
69             * Décalage du scroll à appliquer lors des calculs (utile en cas d'éléments fixes)
70             */
71            yFix: 0,
72            /**
73             * Fonction appelée au moment de scroller dans la page. Cette fonction peut-être surchargée pour animer le
74             * scroll par exemple.
75             * @param y Coordonnée du saut.
76             */
77            jumpTo: function(y) {
78                document.documentElement.scrollTop = y;
79            },
80            /**
81             * Méthode appelée quand on entre dans une zone. Cette méthode sert notamment à activer les classes
82             * adéquates du menu de sauts entre autres.
83             * @param anchor Ancre concernée.
84             */
85            onEnter: function(anchor) {
86                anchor.classList.add('active');
87                this._chaptersElements.forEach(function(handler) {
88                    handler.querySelector('[data-scrollspy-jump="' + anchor.getAttribute('id') + '"]').classList.add('active');
89                });
90            },
91            /**
92             * Méthode appelée quand on sort d'une zone. Cette méthode sert notamment à désactiver les classes
93             * adéquantes du menu de sauts entre autres.
94             * @param anchor Ancre concernée.
95             */
96            onLeave: function(anchor) {
97                anchor.classList.remove('active');
98                this._chaptersElements.forEach(function(handler) {
99                    handler.querySelector('[data-scrollspy-jump="' + anchor.getAttribute('id') + '"]').classList.remove('active');
100                });
101            },
102            /**
103             * Méthode appelée une fois que le ScrollSpy est initialisé. Par défaut, cette méthode crée un menu de sauts
104             * dans une div repérée par l'attribut "data-scrollspy-chapters".
105             * @param anchors Liste des zones ancrées.
106             */
107            created: function(anchors) {
108                var self = this;
109                var ul = document.createElement('ol');
110                [].forEach.call(document.querySelectorAll('[data-scrollspy-chapters]'), function($element) {
111                    anchors.forEach(function(anchor) {
112                        var id = anchor.getAttribute('id');
113                        var a = document.createElement('a');
114                        a.innerHTML = self._options.anchorGetTitle(anchor);
115                        a.setAttribute('href', '#' + id);
116                        a.setAttribute('data-scrollspy-jump', id);
117                        a.addEventListener('click', function(event) {
118                            event.preventDefault();
119                            var y = getPosition(anchor).y - self._options.yFix;
120                            self._options.jumpTo.call(self, y);
121                            return false;
122                        });
123                        var li = document.createElement('li');
124                        li.appendChild(a);
125                        ul.appendChild(li);
126                    });
127                    $element.appendChild(ul);
128                    self.addChaptersElement($element);
129                });
130            }
131        },
132        _chaptersElements: [],
133        _computedAnchors: [],
134        _onscroll: function(event) {
135            var self = this;
136            this._computedAnchors.forEach(function(anchor) {
137                var rect = anchor.getBoundingClientRect();
138                if (Math.floor(rect.top) <= self._options.yFix && Math.floor(rect.bottom) > self._options.yFix) {
139                    if (!anchor._isActive) {
140                        anchor._isActive = true;
141                        self._options.onEnter.call(self, anchor);
142                    }
143                } else {
144                    if (anchor._isActive) {
145                        anchor._isActive = false;
146                        self._options.onLeave.call(self, anchor);
147                    }
148                }
149            });
150        },
151        _extend: function(options) {
152            for (var key in options) {
153                if (options.hasOwnProperty(key)) {
154                    this._options[key] = options[key];
155                }
156            }
157        },
158        _binds: function() {
159            var self = this;
160            var callback = throttle(function (event) {
161                self._onscroll.call(self, event);
162            }, 100, { trailing: true });
163            window.addEventListener('scroll', callback);
164            window.addEventListener('resize', callback);
165            window.addEventListener('load', callback);
166        },
167        _create: function() {
168            if (typeof this._options.anchors === typeof '') {
169                this._computedAnchors = document.documentElement.querySelectorAll(this._options.anchors);
170            } else if (typeof this._options.anchors === typeof [] || this._options.anchors instanceof NodeList) {
171                this._computedAnchors = this._options.anchors;
172            } else if (typeof this._options.anchors === typeof Function) {
173                this._computedAnchors = this._options.anchors(document.documentElement);
174            }
175            this._computedAnchors = [].map.call(this._computedAnchors, function(anchor) {
176                anchor._isActive = false;
177                return anchor;
178            });
179        },
180        addChaptersElement: function(handler) {
181            this._chaptersElements.push(handler);
182        },
183        init: function(options) {
184            this._extend(options);
185            this._create();
186            this._binds();
187            if (typeof this._options.created === typeof Function) {
188                this._options.created.call(this, this._computedAnchors);
189            }
190        }
191    };
192    instance.init.apply(instance, arguments);
193    return instance;
194};

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.