PageSourceSearch

https://ds24.ru/bitrix/templates/ranx-landing/assets/js/custom.js?17857930559182

js ds24.ru collected 2026-09-24 11:52:23 UTC 9,182 bytes, 414 lines download raw bytes

1// this file won't be updated, so you can write your own code here
2
3document.addEventListener('DOMContentLoaded', function () {
4
5    document.querySelectorAll('.ranx-yadisk-audio').forEach(function (wrapper) {
6
7        if (wrapper.dataset.audioInitialized === 'Y') {
8            return;
9        }
10
11        const source = wrapper.querySelector('.ranx-yadisk-audio__source');
12
13        if (!source) {
14            return;
15        }
16
17        const publicUrl = source.getAttribute('href');
18        const title = source.textContent.trim();
19
20        if (!publicUrl) {
21            return;
22        }
23
24
25        /*
26         * Audio
27         */
28        const audio = document.createElement('audio');
29
30        audio.preload = 'metadata';
31        audio.src =
32            '/local/ajax/yadisk-audio.php?url='
33            + encodeURIComponent(publicUrl);
34
35
36        /*
37         * Player
38         */
39        const player = document.createElement('div');
40        player.className = 'ranx-audio-player';
41
42
43        /*
44         * Play / Pause
45         */
46        const playButton = document.createElement('button');
47
48        playButton.type = 'button';
49        playButton.className = 'ranx-audio-player__play';
50        playButton.setAttribute('aria-label', 'Воспроизвести');
51        playButton.textContent = '▶';
52
53
54        /*
55         * Content
56         */
57        const content = document.createElement('div');
58        content.className = 'ranx-audio-player__content';
59
60
61        /*
62         * Title
63         */
64        const titleElement = document.createElement('div');
65
66        titleElement.className = 'ranx-audio-player__title';
67        titleElement.textContent = title;
68
69
70        /*
71         * Waveform
72         */
73        const waveform = document.createElement('div');
74
75        waveform.className = 'ranx-audio-player__waveform';
76        waveform.setAttribute('role', 'slider');
77        waveform.setAttribute('aria-label', 'Перемотка аудио');
78        waveform.setAttribute('aria-valuemin', '0');
79        waveform.setAttribute('aria-valuemax', '100');
80        waveform.setAttribute('aria-valuenow', '0');
81
82
83        /*
84         * Создаём seed из названия и ссылки.
85         * Волна выглядит случайной,
86         * но остаётся одинаковой после перезагрузки.
87         */
88        function createSeed(string) {
89
90            let seed = 0;
91
92            for (let i = 0; i < string.length; i++) {
93
94                seed =
95                    ((seed << 5) - seed)
96                    + string.charCodeAt(i);
97
98                seed |= 0;
99            }
100
101            return Math.abs(seed) || 1;
102        }
103
104
105        /*
106         * Псевдослучайный генератор
107         */
108        function seededRandom(seed) {
109
110            let value = seed % 2147483647;
111
112            if (value <= 0) {
113                value += 2147483646;
114            }
115
116            return function () {
117
118                value =
119                    value * 16807
120                    % 2147483647;
121
122                return (value - 1) / 2147483646;
123            };
124        }
125
126
127        const random = seededRandom(
128            createSeed(title + publicUrl)
129        );
130
131
132        /*
133         * Количество столбиков
134         */
135        const barsCount = 150;
136
137
138        /*
139         * Генерация waveform
140         */
141        for (let i = 0; i < barsCount; i++) {
142
143            const bar = document.createElement('span');
144
145            bar.className = 'ranx-audio-player__bar';
146
147            /*
148             * Высота от 22% до 100%
149             */
150            const height =
151                22 + Math.floor(random() * 79);
152
153            bar.style.height = height + '%';
154
155            waveform.appendChild(bar);
156        }
157
158
159        /*
160         * Time
161         */
162        const time = document.createElement('div');
163
164        time.className = 'ranx-audio-player__time';
165        time.textContent = '0:00 / 0:00';
166
167
168        /*
169         * Build player
170         */
171        content.appendChild(titleElement);
172        content.appendChild(waveform);
173        content.appendChild(time);
174
175        player.appendChild(playButton);
176        player.appendChild(content);
177        player.appendChild(audio);
178
179        wrapper.innerHTML = '';
180        wrapper.appendChild(player);
181
182        wrapper.dataset.audioInitialized = 'Y';
183
184
185        /*
186         * Format seconds → 0:00
187         */
188        function formatTime(seconds) {
189
190            if (!Number.isFinite(seconds)) {
191                return '0:00';
192            }
193
194            const minutes =
195                Math.floor(seconds / 60);
196
197            const secs =
198                Math.floor(seconds % 60);
199
200            return (
201                minutes
202                + ':'
203                + String(secs).padStart(2, '0')
204            );
205        }
206
207
208        /*
209         * Update time
210         */
211        function updateTime() {
212
213            time.textContent =
214                formatTime(audio.currentTime)
215                + ' / '
216                + formatTime(audio.duration);
217        }
218
219
220        /*
221         * Update waveform progress
222         */
223        function updateWaveform() {
224
225            if (
226                !Number.isFinite(audio.duration)
227                || audio.duration <= 0
228            ) {
229                return;
230            }
231
232            const progress =
233                audio.currentTime
234                / audio.duration;
235
236            const bars =
237                waveform.querySelectorAll(
238                    '.ranx-audio-player__bar'
239                );
240
241            bars.forEach(function (bar, index) {
242
243                const barPosition =
244                    (index + 1)
245                    / bars.length;
246
247                bar.classList.toggle(
248                    'is-played',
249                    barPosition <= progress
250                );
251
252            });
253
254            waveform.setAttribute(
255                'aria-valuenow',
256                Math.round(progress * 100)
257            );
258        }
259
260
261        /*
262         * Play / Pause
263         */
264        playButton.addEventListener('click', function () {
265
266            if (audio.paused) {
267
268                /*
269                 * Останавливаем другие плееры
270                 * на текущей странице.
271                 */
272                document
273                    .querySelectorAll(
274                        '.ranx-audio-player audio'
275                    )
276                    .forEach(function (otherAudio) {
277
278                        if (
279                            otherAudio !== audio
280                            && !otherAudio.paused
281                        ) {
282                            otherAudio.pause();
283                        }
284
285                    });
286
287
288                audio.play().catch(function () {
289
290                    /*
291                     * Не ломаем страницу
292                     * при ошибке воспроизведения.
293                     */
294
295                });
296
297            } else {
298
299                audio.pause();
300
301            }
302
303        });
304
305
306        /*
307         * Click waveform → seek
308         */
309        waveform.addEventListener('click', function (event) {
310
311            if (
312                !Number.isFinite(audio.duration)
313                || audio.duration <= 0
314            ) {
315                return;
316            }
317
318            const rect =
319                waveform.getBoundingClientRect();
320
321            const position = Math.max(
322                0,
323                Math.min(
324                    1,
325                    (event.clientX - rect.left)
326                    / rect.width
327                )
328            );
329
330            audio.currentTime =
331                audio.duration * position;
332
333            updateTime();
334            updateWaveform();
335
336        });
337
338
339        /*
340         * Audio events
341         */
342        audio.addEventListener('play', function () {
343
344            playButton.textContent = '❚❚';
345
346            playButton.setAttribute(
347                'aria-label',
348                'Пауза'
349            );
350
351            player.classList.add('is-playing');
352
353        });
354
355
356        audio.addEventListener('pause', function () {
357
358            playButton.textContent = '▶';
359
360            playButton.setAttribute(
361                'aria-label',
362                'Воспроизвести'
363            );
364
365            player.classList.remove('is-playing');
366
367        });
368
369
370        audio.addEventListener('ended', function () {
371
372            audio.currentTime = 0;
373
374            updateTime();
375            updateWaveform();
376
377        });
378
379
380        audio.addEventListener(
381            'loadedmetadata',
382            function () {
383
384                updateTime();
385                updateWaveform();
386
387            }
388        );
389
390
391        audio.addEventListener(
392            'durationchange',
393            function () {
394
395                updateTime();
396                updateWaveform();
397
398            }
399        );
400
401
402        audio.addEventListener(
403            'timeupdate',
404            function () {
405
406                updateTime();
407                updateWaveform();
408
409            }
410        );
411
412    });
413
414});

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.