PageSourceSearch

https://webadminportal.ucv.edu.pe/uploads/files/scripts-js/ucv-home-v09_20251031132840.js

js ucv.edu.pe collected 2026-09-24 18:32:25 UTC 7,640 bytes, 221 lines download raw bytes

1(function () {
2  // --- util: esperar a que existan selectores (hasta timeout) ---
3  function waitForSelectors(selectors, interval = 120, timeout = 8000) {
4    return new Promise((resolve) => {
5      const stopAt = Date.now() + timeout;
6      (function check() {
7        const results = selectors.map(s => Array.from(document.querySelectorAll(s)));
8        const allFound = results.every(nodes => nodes.length > 0);
9        if (allFound) {
10          resolve(results);
11        } else if (Date.now() > stopAt) {
12          resolve(results);
13        } else {
14          setTimeout(check, interval);
15        }
16      })();
17    });
18  }
19
20  // --- util: cargar API de YouTube ---
21  function loadYouTubeIframeAPI() {
22    return new Promise((resolve, reject) => {
23      if (window.YT && window.YT.Player) return resolve(window.YT);
24
25      if (!document.querySelector('script[src="https://www.youtube.com/iframe_api"]')) {
26        const tag = document.createElement('script');
27        tag.src = "https://www.youtube.com/iframe_api";
28        tag.async = true;
29        tag.onerror = () => reject(new Error('Error cargando YouTube Iframe API'));
30        document.head.appendChild(tag);
31      }
32
33      const previous = window.onYouTubeIframeAPIReady;
34      window.onYouTubeIframeAPIReady = function () {
35        if (typeof previous === 'function') {
36          try { previous(); } catch (e) { console.warn('previous onYouTubeIframeAPIReady failed', e); }
37        }
38        resolve(window.YT);
39      };
40
41      setTimeout(() => {
42        if (window.YT && window.YT.Player) resolve(window.YT);
43      }, 1000);
44    });
45  }
46
47  // --- Variables globales ---
48  let currentIndex = 0;
49  let ytPlayer = null;
50  let container = null;
51
52  function destroyYTPlayer() {
53    if (ytPlayer && typeof ytPlayer.destroy === 'function') {
54      try { ytPlayer.destroy(); } catch (e) { console.warn('Error destruyendo YT player', e); }
55      ytPlayer = null;
56    }
57  }
58
59  // --- reproducir video por índice ---
60  function playVideo(index) {
61    const playlistItems = Array.from(document.querySelectorAll('.playlist'));
62    if (index < 0 || index >= playlistItems.length) return;
63    currentIndex = index;
64
65    const item = playlistItems[index];
66    const videoId = item.getAttribute('data-video-id');
67    const type = item.getAttribute('data-type') || 'local';
68
69    if (!container) container = document.getElementById('video-container');
70    if (!container) return;
71    container.innerHTML = "";
72
73    destroyYTPlayer();
74
75    if (type === "youtube") {
76      const div = document.createElement("div");
77      div.id = "yt-player";
78      div.style.cssText = "width:100%;height:100%;border-radius:1.5em;overflow:hidden;";
79      container.appendChild(div);
80
81      if (window.YT && window.YT.Player) {
82        ytPlayer = new YT.Player("yt-player", {
83          height: "100%",
84          width: "100%",
85          videoId: videoId,
86          playerVars: { autoplay: 1, controls: 1, rel: 0 },
87          events: {
88            'onReady': (e) => { try { e.target.playVideo(); } catch (err) {} },
89            'onStateChange': (event) => {
90              if (event.data === YT.PlayerState.ENDED) playVideo(currentIndex + 1);
91            }
92          }
93        });
94      }
95    } else {
96      const video = document.createElement("video");
97      video.src = videoId;
98      video.controls = true;
99      video.autoplay = true;
100      video.playsInline = true;
101      video.style.cssText = "width:100%;height:80vh;border-radius:1.5em;background:#000;";
102      video.addEventListener("ended", () => playVideo(currentIndex + 1));
103      container.appendChild(video);
104
105      const playPromise = video.play();
106      if (playPromise !== undefined) {
107        playPromise.catch(() => {
108          video.muted = true;
109          video.play().catch(() => {
110            console.warn('Autoplay bloqueado en video local — el usuario deberá pulsar play');
111          });
112        });
113      }
114    }
115  }
116
117  // --- Inicializar playlist ---
118  function initializePlaylist() {
119    container = document.getElementById('video-container');
120    const playlistItems = Array.from(document.querySelectorAll('.playlist'));
121    const intro = document.getElementById('intro-video');
122
123    if (!container || playlistItems.length === 0) {
124      console.warn('initializePlaylist: elementos necesarios no encontrados');
125      return;
126    }
127
128    if (!window.__playlist_click_delegated) {
129      document.addEventListener('click', (e) => {
130        const item = e.target.closest('.playlist');
131        if (!item) return;
132        const items = Array.from(document.querySelectorAll('.playlist'));
133        const idx = items.indexOf(item);
134        if (idx >= 0) playVideo(idx);
135      });
136      window.__playlist_click_delegated = true;
137    }
138
139    if (intro && !intro.__playlistBound) {
140      intro.addEventListener('ended', () => {
141        playVideo(0);
142      });
143      intro.__playlistBound = true;
144    }
145
146    if (!window.__video_click_delegated) {
147      document.addEventListener('click', (e) => {
148        const v = e.target.closest('.video');
149        if (!v) return;
150        try { if (v.paused) v.play(); } catch (err) {}
151      });
152      window.__video_click_delegated = true;
153    }
154
155    console.log('Playlist inicializada con', playlistItems.length, 'items');
156  }
157
158  // --- Punto de entrada ---
159  async function start() {
160    try {
161      if (document.readyState === 'loading') {
162        await new Promise(res => document.addEventListener('DOMContentLoaded', res));
163      }
164      const apiPromise = loadYouTubeIframeAPI();
165      const [containers, playlists] = await waitForSelectors(['#video-container', '.playlist'], 120, 7000);
166
167      if ((containers.length === 0) || (playlists.length === 0)) {
168        const obs = new MutationObserver((mutations, observer) => {
169          const c = document.getElementById('video-container');
170          const p = document.querySelectorAll('.playlist');
171          if (c && p && p.length > 0) {
172            observer.disconnect();
173            initializePlaylist();
174          }
175        });
176        obs.observe(document.body, { childList: true, subtree: true });
177      } else {
178        await apiPromise.catch(err => console.warn('YouTube API fallo:', err));
179        initializePlaylist();
180      }
181    } catch (err) {
182      console.error('Error en start():', err);
183    }
184  }
185
186  start();
187
188
189document.querySelectorAll(".tab_inf_in").forEach(el => {
190  el.addEventListener("click", function() {
191    const destino = document.querySelector(".btn_despl_hero");
192    if (destino) {
193      // scroll inicial al destino
194      destino.scrollIntoView({ behavior: "smooth", block: "start" });
195
196      // aplicar desplazamiento suave hacia arriba luego
197      setTimeout(() => {
198        window.scrollTo({
199          top: window.scrollY - 100, // sube 100px, ajusta a tu gusto
200          behavior: "smooth"
201        });
202      }, 0);
203    }
204
205    // re-inicializar el contenido del tab
206    setTimeout(() => { initializePlaylist(); }, 600);
207  });
208});
209
210  document.querySelectorAll('.tab_inf_in.active').forEach(el => {
211    el.classList.remove('active');
212  });
213
214
215})();
216
217(function(c,l,a,r,i,t,y){
218    c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
219    t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
220    y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
221  })(window, document, "clarity", "script", "r478otvvis");

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.